Use actual GZIP compression

This commit is contained in:
Ted John 2021-04-08 00:32:07 +01:00
parent 341f716c9d
commit 0971db99c3
3 changed files with 98 additions and 9 deletions

View File

@ -99,16 +99,13 @@ namespace OpenRCT2
// Uncompress
if (_header.Compression == COMPRESSION_GZIP)
{
size_t outUncompressedSize{};
auto uncompressedData = util_zlib_inflate(
reinterpret_cast<const uint8_t*>(_buffer.GetData()), _buffer.GetLength(), &outUncompressedSize);
if (_header.UncompressedSize != outUncompressedSize)
auto uncompressedData = Ungzip(_buffer.GetData(), _buffer.GetLength());
if (_header.UncompressedSize != uncompressedData.size())
{
// Warning?
}
_buffer.Clear();
_buffer.Write(uncompressedData, outUncompressedSize);
std::free(uncompressedData);
_buffer.Write(uncompressedData.data(), uncompressedData.size());
}
}
else
@ -141,7 +138,7 @@ namespace OpenRCT2
std::optional<std::vector<uint8_t>> compressedBytes;
if (_header.Compression == COMPRESSION_GZIP)
{
compressedBytes = util_zlib_deflate(reinterpret_cast<const uint8_t*>(uncompressedData), uncompressedSize);
compressedBytes = Gzip(uncompressedData, uncompressedSize);
if (compressedBytes)
{
_header.CompressedSize = compressedBytes->size();

View File

@ -696,6 +696,96 @@ bool util_gzip_compress(FILE* source, FILE* dest)
return true;
}
std::vector<uint8_t> Gzip(const void* data, size_t dataLen)
{
assert(data != nullptr);
std::vector<uint8_t> output;
z_stream strm{};
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
auto ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 | 16, 8, Z_DEFAULT_STRATEGY);
if (ret != Z_OK)
{
throw std::runtime_error("deflateInit2 failed with error " + std::to_string(ret));
}
int flush;
const auto* src = static_cast<const Bytef*>(data);
size_t srcRemaining = dataLen;
do
{
auto nextBlockSize = std::min(srcRemaining, CHUNK);
srcRemaining -= nextBlockSize;
flush = srcRemaining == 0 ? Z_FINISH : Z_NO_FLUSH;
strm.avail_in = static_cast<uInt>(nextBlockSize);
strm.next_in = const_cast<Bytef*>(src);
do
{
output.resize(output.size() + nextBlockSize);
strm.avail_out = nextBlockSize;
strm.next_out = &output[output.size() - nextBlockSize];
ret = deflate(&strm, flush);
if (ret == Z_STREAM_ERROR)
{
throw std::runtime_error("deflate failed with error " + std::to_string(ret));
}
output.resize(output.size() - strm.avail_out);
} while (strm.avail_out == 0);
src += nextBlockSize;
} while (flush != Z_FINISH);
deflateEnd(&strm);
return output;
}
std::vector<uint8_t> Ungzip(const void* data, size_t dataLen)
{
assert(data != nullptr);
std::vector<uint8_t> output;
z_stream strm{};
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
auto ret = inflateInit2(&strm, 15 | 16);
if (ret != Z_OK)
{
throw std::runtime_error("inflateInit2 failed with error " + std::to_string(ret));
}
int flush;
const auto* src = static_cast<const Bytef*>(data);
size_t srcRemaining = dataLen;
do
{
auto nextBlockSize = std::min(srcRemaining, CHUNK);
srcRemaining -= nextBlockSize;
flush = srcRemaining == 0 ? Z_FINISH : Z_NO_FLUSH;
strm.avail_in = static_cast<uInt>(nextBlockSize);
strm.next_in = const_cast<Bytef*>(src);
do
{
output.resize(output.size() + nextBlockSize);
strm.avail_out = nextBlockSize;
strm.next_out = &output[output.size() - nextBlockSize];
ret = inflate(&strm, flush);
if (ret == Z_STREAM_ERROR)
{
throw std::runtime_error("deflate failed with error " + std::to_string(ret));
}
output.resize(output.size() - strm.avail_out);
} while (strm.avail_out == 0);
src += nextBlockSize;
} while (flush != Z_FINISH);
deflateEnd(&strm);
return output;
}
// Type-independent code left as macro to reduce duplicate code.
#define add_clamp_body(value, value_to_add, min_cap, max_cap) \
if ((value_to_add > 0) && (value > (max_cap - (value_to_add)))) \

View File

@ -59,6 +59,8 @@ uint32_t util_rand();
std::optional<std::vector<uint8_t>> util_zlib_deflate(const uint8_t* data, size_t data_in_size);
uint8_t* util_zlib_inflate(const uint8_t* data, size_t data_in_size, size_t* data_out_size);
bool util_gzip_compress(FILE* source, FILE* dest);
std::vector<uint8_t> Gzip(const void* data, size_t dataLen);
std::vector<uint8_t> Ungzip(const void* data, size_t dataLen);
int8_t add_clamp_int8_t(int8_t value, int8_t value_to_add);
int16_t add_clamp_int16_t(int16_t value, int16_t value_to_add);
@ -71,13 +73,13 @@ uint8_t soft_light(uint8_t a, uint8_t b);
size_t strcatftime(char* buffer, size_t bufferSize, const char* format, const struct tm* tp);
template<typename T>[[nodiscard]] constexpr uint64_t EnumToFlag(T v)
template<typename T> [[nodiscard]] constexpr uint64_t EnumToFlag(T v)
{
static_assert(std::is_enum_v<T>);
return 1ULL << static_cast<std::underlying_type_t<T>>(v);
}
template<typename... T>[[nodiscard]] constexpr uint64_t EnumsToFlags(T... types)
template<typename... T> [[nodiscard]] constexpr uint64_t EnumsToFlags(T... types)
{
return (EnumToFlag(types) | ...);
}