diff --git a/src/common/filesystem/include/fs_decompress.h b/src/common/filesystem/include/fs_decompress.h new file mode 100644 index 0000000000..ef4b947458 --- /dev/null +++ b/src/common/filesystem/include/fs_decompress.h @@ -0,0 +1,62 @@ +#pragma once +#include "fs_files.h" + +namespace FileSys { + +// Zip compression methods, extended by some internal types to be passed to OpenDecompressor +enum ECompressionMethod +{ + METHOD_STORED = 0, + METHOD_SHRINK = 1, + METHOD_IMPLODE = 6, + METHOD_DEFLATE = 8, + METHOD_BZIP2 = 12, + METHOD_LZMA = 14, + METHOD_XZ = 95, + METHOD_PPMD = 98, + METHOD_LZSS = 1337, // not used in Zips - this is for Console Doom compression + METHOD_ZLIB = 1338, // Zlib stream with header, used by compressed nodes. + METHOD_RFFCRYPT = 1339, // not actual compression but can be put in here to make handling easier. + METHOD_IMPLODE_MIN = 1000, // having discrete types for these avoids keeping around the GPFlags word in Zips. + METHOD_IMPLODE_0 = 1000, + METHOD_IMPLODE_2 = 1002, + METHOD_IMPLODE_4 = 1004, + METHOD_IMPLODE_6 = 1006, + METHOD_IMPLODE_MAX = 1006, + METHOD_INVALID = 0x7fff, + METHOD_TRANSFEROWNER = 0x8000, +}; + +enum EDecompressFlags +{ + DCF_TRANSFEROWNER = 1, + DCF_SEEKABLE = 2, + DCF_EXCEPTIONS = 4 +}; + +bool OpenDecompressor(FileReader& self, FileReader &parent, FileReader::Size length, int method, int flags = 0); // creates a decompressor stream. 'seekable' uses a buffered version so that the Seek and Tell methods can be used. + +// This holds a compresed Zip entry with all needed info to decompress it. +struct FCompressedBuffer +{ + size_t mSize; + size_t mCompressedSize; + int mMethod; + unsigned mCRC32; + char* mBuffer; + const char* filename; + + bool Decompress(char* destbuffer); + void Clean() + { + mSize = mCompressedSize = 0; + if (mBuffer != nullptr) + { + delete[] mBuffer; + mBuffer = nullptr; + } + } +}; + + +} diff --git a/src/common/filesystem/include/fs_files.h b/src/common/filesystem/include/fs_files.h index b7d3148373..24a252cc75 100644 --- a/src/common/filesystem/include/fs_files.h +++ b/src/common/filesystem/include/fs_files.h @@ -72,37 +72,6 @@ public: } }; -// Zip compression methods, extended by some internal types to be passed to OpenDecompressor -enum ECompressionMethod -{ - METHOD_STORED = 0, - METHOD_SHRINK = 1, - METHOD_IMPLODE = 6, - METHOD_DEFLATE = 8, - METHOD_BZIP2 = 12, - METHOD_LZMA = 14, - METHOD_XZ = 95, - METHOD_PPMD = 98, - METHOD_LZSS = 1337, // not used in Zips - this is for Console Doom compression - METHOD_ZLIB = 1338, // Zlib stream with header, used by compressed nodes. - METHOD_RFFCRYPT = 1339, // not actual compression but can be put in here to make handling easier. - METHOD_IMPLODE_MIN = 1000, // having discrete types for these avoids keeping around the GPFlags word in Zips. - METHOD_IMPLODE_0 = 1000, - METHOD_IMPLODE_2 = 1002, - METHOD_IMPLODE_4 = 1004, - METHOD_IMPLODE_6 = 1006, - METHOD_IMPLODE_MAX = 1006, - METHOD_INVALID = 0x7fff, - METHOD_TRANSFEROWNER = 0x8000, -}; - -enum EDecompressFlags -{ - DCF_TRANSFEROWNER = 1, - DCF_SEEKABLE = 2, - DCF_EXCEPTIONS = 4 -}; - class FileReader; // an opaque memory buffer to the file's content. Can either own the memory or just point to an external buffer. @@ -183,28 +152,6 @@ public: }; -// This holds a compresed Zip entry with all needed info to decompress it. -struct FCompressedBuffer -{ - size_t mSize; - size_t mCompressedSize; - int mMethod; - unsigned mCRC32; - char* mBuffer; - const char* filename; - - bool Decompress(char* destbuffer); - void Clean() - { - mSize = mCompressedSize = 0; - if (mBuffer != nullptr) - { - delete[] mBuffer; - mBuffer = nullptr; - } - } -}; - class FileReaderInterface { @@ -290,7 +237,6 @@ public: bool OpenMemoryArray(std::vector& data); // take the given array bool OpenMemoryArray(FileData& data); // take the given array bool OpenMemoryArray(std::function&)> getter); // read contents to a buffer and return a reader to it - bool OpenDecompressor(FileReader &parent, Size length, int method, int flags = 0); // creates a decompressor stream. 'seekable' uses a buffered version so that the Seek and Tell methods can be used. Size Tell() const { diff --git a/src/common/filesystem/include/resourcefile.h b/src/common/filesystem/include/resourcefile.h index 951c8afccc..12ab0ec71e 100644 --- a/src/common/filesystem/include/resourcefile.h +++ b/src/common/filesystem/include/resourcefile.h @@ -7,6 +7,7 @@ #include #include #include "fs_files.h" +#include "fs_decompress.h" namespace FileSys { diff --git a/src/common/filesystem/source/files_decompress.cpp b/src/common/filesystem/source/files_decompress.cpp index 8bf681357d..0942b271da 100644 --- a/src/common/filesystem/source/files_decompress.cpp +++ b/src/common/filesystem/source/files_decompress.cpp @@ -47,6 +47,7 @@ #include "fs_files.h" #include "files_internal.h" #include "ancientzip.h" +#include "fs_decompress.h" namespace FileSys { using namespace byteswap; @@ -849,7 +850,7 @@ public: }; -bool FileReader::OpenDecompressor(FileReader &parent, Size length, int method, int flags) +bool OpenDecompressor(FileReader& self, FileReader &parent, FileReader::Size length, int method, int flags) { FileReaderInterface* fr = nullptr; DecompressorBase* dec = nullptr; @@ -923,7 +924,7 @@ bool FileReader::OpenDecompressor(FileReader &parent, Size length, int method, i } // The decoders for these legacy formats can only handle the full data in one go so we have to perform the entire decompression here. - case METHOD_IMPLODE: + case METHOD_IMPLODE_0: case METHOD_IMPLODE_2: case METHOD_IMPLODE_4: case METHOD_IMPLODE_6: @@ -933,7 +934,7 @@ bool FileReader::OpenDecompressor(FileReader &parent, Size length, int method, i auto& buffer = idec->GetArray(); auto bufr = (uint8_t*)buffer.allocate(length); FZipExploder exploder; - if (exploder.Explode(bufr, length, *p, p->GetLength(), method) == -1) + if (exploder.Explode(bufr, length, *p, p->GetLength(), method - METHOD_IMPLODE_MIN) == -1) { if (exceptions) { @@ -964,9 +965,9 @@ bool FileReader::OpenDecompressor(FileReader &parent, Size length, int method, i auto bufr = (uint8_t*)buffer.allocate(length); p->Read(bufr, length); - Size cryptlen = std::min(length, 256); + FileReader::Size cryptlen = std::min(length, 256); - for (Size i = 0; i < cryptlen; ++i) + for (FileReader::Size i = 0; i < cryptlen; ++i) { bufr[i] ^= i >> 1; } @@ -984,16 +985,12 @@ bool FileReader::OpenDecompressor(FileReader &parent, Size length, int method, i } dec->Length = length; } - if (!(flags & DCF_SEEKABLE)) - { - Close(); - mReader = fr; - } - else + if ((flags & DCF_SEEKABLE)) { // create a wrapper that can buffer the content so that seeking is possible - mReader = new BufferingReader(fr); + fr = new BufferingReader(fr); } + self = FileReader(fr); return true; } catch (...) @@ -1001,7 +998,7 @@ bool FileReader::OpenDecompressor(FileReader &parent, Size length, int method, i if (fr) delete fr; throw; } - } +} bool FCompressedBuffer::Decompress(char* destbuffer) @@ -1016,7 +1013,7 @@ bool FCompressedBuffer::Decompress(char* destbuffer) FileReader mr; mr.OpenMemory(mBuffer, mCompressedSize); FileReader frz; - if (frz.OpenDecompressor(mr, mSize, mMethod)) + if (OpenDecompressor(frz, mr, mSize, mMethod)) { return frz.Read(destbuffer, mSize) != mSize; } diff --git a/src/common/filesystem/source/resourcefile.cpp b/src/common/filesystem/source/resourcefile.cpp index c8643d556b..0e500287f9 100644 --- a/src/common/filesystem/source/resourcefile.cpp +++ b/src/common/filesystem/source/resourcefile.cpp @@ -41,6 +41,7 @@ #include "files_internal.h" #include "unicode.h" #include "fs_findfile.h" +#include "fs_decompress.h" namespace FileSys { @@ -565,7 +566,7 @@ FileReader FResourceFile::GetEntryReader(uint32_t entry, bool newreader) { FileReader fri; fri.OpenFilePart(Reader, Entries[entry].Position, Entries[entry].CompressedSize); - fr.OpenDecompressor(fri, Entries[entry].Length, Entries[entry].Method, FileSys::DCF_TRANSFEROWNER | FileSys::DCF_SEEKABLE | FileSys::DCF_EXCEPTIONS); + OpenDecompressor(fr, fri, Entries[entry].Length, Entries[entry].Method, FileSys::DCF_TRANSFEROWNER | FileSys::DCF_SEEKABLE | FileSys::DCF_EXCEPTIONS); } } return fr; diff --git a/src/maploader/maploader.cpp b/src/maploader/maploader.cpp index d6ae5d4ff1..904d1dcbca 100644 --- a/src/maploader/maploader.cpp +++ b/src/maploader/maploader.cpp @@ -84,6 +84,7 @@ #include "texturemanager.h" #include "hw_vertexbuilder.h" #include "version.h" +#include "fs_decompress.h" enum { @@ -738,7 +739,7 @@ bool MapLoader::LoadExtendedNodes (FileReader &dalump, uint32_t id) if (compressed) { FileReader zip; - if (zip.OpenDecompressor(dalump, -1, FileSys::METHOD_ZLIB, FileSys::DCF_EXCEPTIONS)) + if (OpenDecompressor(zip, dalump, -1, FileSys::METHOD_ZLIB, FileSys::DCF_EXCEPTIONS)) { LoadZNodes(zip, type); return true; @@ -3344,7 +3345,7 @@ void MapLoader::LoadLightmap(MapData *map) return; FileReader fr; - if (!fr.OpenDecompressor(map->Reader(ML_LIGHTMAP), -1, FileSys::METHOD_ZLIB)) + if (!OpenDecompressor(fr, map->Reader(ML_LIGHTMAP), -1, FileSys::METHOD_ZLIB)) return;