From c1d7fa7e8b3db197fcfb95c0c78f14718d2e7437 Mon Sep 17 00:00:00 2001 From: robert-yates Date: Sat, 11 Jan 2025 16:32:44 +0100 Subject: [PATCH] add compression utils --- .gitmodules | 5 ++ deps/CMakeLists.txt | 1 + deps/zlib | 1 + deps/zlib.cmake | 4 ++ src/common/CMakeLists.txt | 1 + src/common/utils/compression.cpp | 105 +++++++++++++++++++++++++++++++ src/common/utils/compression.hpp | 16 +++++ 7 files changed, 133 insertions(+) create mode 160000 deps/zlib create mode 100644 deps/zlib.cmake create mode 100644 src/common/utils/compression.cpp create mode 100644 src/common/utils/compression.hpp diff --git a/.gitmodules b/.gitmodules index 21cf3d31..9f7d3d9a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -14,3 +14,8 @@ [submodule "deps/googletest"] path = deps/googletest url = https://github.com/google/googletest.git +[submodule "deps/zlib"] + path = deps/zlib + url = https://github.com/madler/zlib.git + branch = develop + ignore = dirty \ No newline at end of file diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt index 8d55e778..168d6006 100644 --- a/deps/CMakeLists.txt +++ b/deps/CMakeLists.txt @@ -13,3 +13,4 @@ target_include_directories(reflect INTERFACE include(mini-gdbstub.cmake) include(googletest.cmake) +include(zlib.cmake) diff --git a/deps/zlib b/deps/zlib new file mode 160000 index 00000000..ef24c4c7 --- /dev/null +++ b/deps/zlib @@ -0,0 +1 @@ +Subproject commit ef24c4c7502169f016dcd2a26923dbaf3216748c diff --git a/deps/zlib.cmake b/deps/zlib.cmake new file mode 100644 index 00000000..b2f92fb6 --- /dev/null +++ b/deps/zlib.cmake @@ -0,0 +1,4 @@ +set(ZLIB_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) +add_subdirectory(zlib) +target_compile_definitions(zlibstatic PUBLIC ZLIB_CONST=1) +target_include_directories(zlibstatic PUBLIC ${zlib_SOURCE_DIR} ${zlib_BINARY_DIR}) \ No newline at end of file diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 42753b78..dfc64b78 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -13,4 +13,5 @@ set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) target_link_libraries(emulator-common PUBLIC Threads::Threads + zlibstatic ) diff --git a/src/common/utils/compression.cpp b/src/common/utils/compression.cpp new file mode 100644 index 00000000..a9d03b2a --- /dev/null +++ b/src/common/utils/compression.cpp @@ -0,0 +1,105 @@ +#include "compression.hpp" + +#include +#include + +namespace utils::compression +{ + namespace zlib + { + namespace + { + class zlib_stream + { + public: + zlib_stream() + { + memset(&stream_, 0, sizeof(stream_)); + valid_ = inflateInit(&stream_) == Z_OK; + } + + zlib_stream(zlib_stream&&) = delete; + zlib_stream(const zlib_stream&) = delete; + zlib_stream& operator=(zlib_stream&&) = delete; + zlib_stream& operator=(const zlib_stream&) = delete; + + ~zlib_stream() + { + if (valid_) + { + inflateEnd(&stream_); + } + } + + z_stream& get() + { + return stream_; // + } + + bool is_valid() const + { + return valid_; + } + + private: + bool valid_{false}; + z_stream stream_{}; + }; + } + + std::vector decompress(const std::vector& data) + { + std::vector buffer{}; + zlib_stream stream_container{}; + if (!stream_container.is_valid()) + { + return {}; + } + + int ret{}; + size_t offset = 0; + static thread_local uint8_t dest[CHUNK] = {0}; + auto& stream = stream_container.get(); + + do + { + const auto input_size = std::min(sizeof(dest), data.size() - offset); + stream.avail_in = static_cast(input_size); + stream.next_in = reinterpret_cast(data.data()) + offset; + offset += stream.avail_in; + + do + { + stream.avail_out = sizeof(dest); + stream.next_out = dest; + + ret = inflate(&stream, Z_NO_FLUSH); + if (ret != Z_OK && ret != Z_STREAM_END) + { + return {}; + } + + buffer.insert(buffer.end(), dest, dest + sizeof(dest) - stream.avail_out); + } while (stream.avail_out == 0); + } while (ret != Z_STREAM_END); + + return buffer; + } + + std::vector compress(const std::vector& data) + { + std::vector result{}; + auto length = compressBound(static_cast(data.size())); + result.resize(length); + + if (compress2(reinterpret_cast(result.data()), &length, reinterpret_cast(data.data()), + static_cast(data.size()), Z_BEST_COMPRESSION) != Z_OK) + { + return {}; + } + + result.resize(length); + return result; + } + } +} \ No newline at end of file diff --git a/src/common/utils/compression.hpp b/src/common/utils/compression.hpp new file mode 100644 index 00000000..ec423368 --- /dev/null +++ b/src/common/utils/compression.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include +#include +#include + +#define CHUNK 16384u + +namespace utils::compression +{ + namespace zlib + { + std::vector compress(const std::vector& data); + std::vector decompress(const std::vector& data); + } +}; \ No newline at end of file