/* * Copyright (c) 2017-2023 zhllxt * * author : zhllxt * email : 37792738@qq.com * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) * * https://github.com/r-lyeh-archived/bundle * */ #ifndef __ASIO2_ZLIB_HPP__ #define __ASIO2_ZLIB_HPP__ #if defined(_MSC_VER) && (_MSC_VER >= 1200) #pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include #include #include #include #include #include #ifdef ASIO2_HEADER_ONLY namespace bho::beast::zlib #else namespace boost::beast::zlib #endif { /** * impl : use the beast::zlib for compress and uncompress * Problem: compress data with beast::zlib and uncompress data with zlib(www.zlib.net) will fail */ class impl { public: impl( beast::zlib::Flush compress_flush = beast::zlib::Flush::sync, beast::zlib::Flush uncompress_flush = beast::zlib::Flush::sync ) : deflate_flush_( compress_flush) , inflate_flush_(uncompress_flush) { } ~impl() = default; impl(impl&&) = delete; impl(const impl&) = delete; impl& operator=(impl&&) = delete; impl& operator=(const impl&) = delete; inline std::string compress(std::string_view data) { return work(deflate_stream_, deflate_flush_, data, asio2::get_last_error()); } inline std::string uncompress(std::string_view data) { return work(inflate_stream_, inflate_flush_, data, asio2::get_last_error()); } inline static std::size_t compress_bound(std::size_t size) { return beast::zlib::deflate_upper_bound(size); } inline static std::size_t uncompress_bound(std::size_t size) { std::size_t bound = size; std::size_t deflate_bound = beast::zlib::deflate_upper_bound(bound) + 5 + 6 + 1; while (deflate_bound < size) { bound += (size - deflate_bound) * 2; deflate_bound = beast::zlib::deflate_upper_bound(bound) + 5 + 6 + 1; } return (std::max)(bound, deflate_bound); } inline beast::zlib::deflate_stream& compressor() { return deflate_stream_; } inline beast::zlib::inflate_stream& uncompressor() { return inflate_stream_; } protected: template inline std::size_t calc_bound(CompressOrUncompress&, beast::zlib::Flush, std::size_t size) { using optype = std::remove_cv_t>; if constexpr /**/ (std::is_same_v) { return compress_bound(size); } else if constexpr (std::is_same_v) { return uncompress_bound(size); } else { // http://www.purecpp.cn/detail?id=2293 static_assert(!sizeof(CompressOrUncompress)); } } template inline std::string work(CompressOrUncompress& op, beast::zlib::Flush flush, std::string_view data, asio::error_code& ec) { ec.clear(); std::string result{}; result.resize(calc_bound(op, flush, data.size())); beast::zlib::z_params zs{}; zs.next_in = decltype(zs.next_in)(data.data()); zs.avail_in = data.size(); zs.next_out = decltype(zs.next_out)(result.data()); zs.avail_out = result.size(); while (true) { op.write(zs, flush, ec); if (ec) break; if (zs.avail_in == std::size_t(0)) break; result.resize(result.size() + calc_bound(op, flush, zs.avail_in)); zs.next_out = decltype(zs.next_out)(result.data() + zs.total_out); zs.avail_out = result.size() - zs.total_out; } if (!ec) result.resize(zs.total_out); else result.resize(0); return result; } protected: beast::zlib::deflate_stream deflate_stream_{}; beast::zlib::inflate_stream inflate_stream_{}; beast::zlib::Flush deflate_flush_{ beast::zlib::Flush::sync }; beast::zlib::Flush inflate_flush_{ beast::zlib::Flush::sync }; }; } #endif // !__ASIO2_ZLIB_HPP__