From 51e831cbfec54299ca80b6eb6b3bea8edd1e74be Mon Sep 17 00:00:00 2001 From: Caball Date: Mon, 30 Dec 2024 23:26:29 +0100 Subject: [PATCH] Added helper util functions for (de)compression. --- src/common/utils/compression.cpp | 80 ++++++++++++++++++++++++++++++++ src/common/utils/compression.hpp | 5 ++ 2 files changed, 85 insertions(+) diff --git a/src/common/utils/compression.cpp b/src/common/utils/compression.cpp index 1688cee..9c50a4a 100644 --- a/src/common/utils/compression.cpp +++ b/src/common/utils/compression.cpp @@ -109,6 +109,86 @@ namespace utils::compression result.resize(length); return result; } + + std::vector decompress(std::span input, std::size_t exp_output_size, double growth_rate) + { + auto decompress_internal = [](std::uint8_t* output, uLong* output_size, const std::uint8_t* input, uLong* input_size) + { + return uncompress2( + reinterpret_cast(output), output_size, + reinterpret_cast(input), input_size + ); + }; + + auto output_size = static_cast(std::max(exp_output_size, std::size_t(256))); + std::vector output(output_size); + + auto input_size = static_cast(input.size()); + auto status = decompress_internal(output.data(), &output_size, input.data(), &input_size); + + if (status == Z_BUF_ERROR) + { + const auto decompression_ratio = (input_size / static_cast(output.size())) - 0.04; + output_size = static_cast(std::max(input.size() / decompression_ratio, static_cast(output_size))); + output.resize(output_size); + + input_size = static_cast(input.size()); + status = decompress_internal(output.data(), &output_size, input.data(), &input_size); + } + + for (growth_rate = std::max(growth_rate, 1.0); status == Z_BUF_ERROR;) + { + output_size = 4 + static_cast(growth_rate * output.size()); + output.resize(output_size); + + input_size = static_cast(input.size()); + status = decompress_internal(output.data(), &output_size, input.data(), &input_size); + } + + if (status != Z_OK) + { + output.clear(); + return output; + } + + output.resize(output_size); + return output; + } + + std::vector compress(std::span input, std::size_t exp_output_size, double growth_rate) + { + auto compress_internal = [](std::uint8_t* output, uLong* output_size, const std::uint8_t* input, uLong input_size) + { + return compress2( + reinterpret_cast(output), output_size, + reinterpret_cast(input), input_size, + Z_BEST_COMPRESSION + ); + }; + + auto output_size = static_cast(std::max(exp_output_size, std::size_t(256))); + std::vector output(output_size); + + const auto input_size = static_cast(input.size()); + auto status = compress_internal(output.data(), &output_size, input.data(), input_size); + + for (growth_rate = std::max(growth_rate, 1.0); status == Z_BUF_ERROR;) + { + output_size = 4 + static_cast(growth_rate * output.size()); + output.resize(output_size); + + status = compress_internal(output.data(), &output_size, input.data(), input_size); + } + + if (status != Z_OK) + { + output.clear(); + return output; + } + + output.resize(output_size); + return output; + } } namespace zip diff --git a/src/common/utils/compression.hpp b/src/common/utils/compression.hpp index dfe36ad..d1a2a37 100644 --- a/src/common/utils/compression.hpp +++ b/src/common/utils/compression.hpp @@ -1,7 +1,9 @@ #pragma once +#include #include #include +#include #define CHUNK 16384u @@ -11,6 +13,9 @@ namespace utils::compression { std::string compress(const std::string& data); std::string decompress(const std::string& data); + + std::vector compress(std::span input, std::size_t exp_output_size, double growth_rate = 2.0); + std::vector decompress(std::span input, std::size_t exp_output_size, double growth_rate = 2.0); } namespace zip