diff --git a/include/beast/zlib/basic_deflate_stream.hpp b/include/beast/zlib/basic_deflate_stream.hpp index e4e5f9019f..907ba0c521 100644 --- a/include/beast/zlib/basic_deflate_stream.hpp +++ b/include/beast/zlib/basic_deflate_stream.hpp @@ -49,7 +49,7 @@ namespace zlib { This is a port of zlib's "deflate" functionality to C++. */ template -class basic_deflate_stream : public z_stream +class basic_deflate_stream : public z_params { // maximum heap size static std::uint16_t constexpr HEAP_SIZE = 2 * limits::lCodes + 1; diff --git a/include/beast/zlib/basic_inflate_stream.hpp b/include/beast/zlib/basic_inflate_stream.hpp index 2de04dd2b7..15e7baf1bd 100644 --- a/include/beast/zlib/basic_inflate_stream.hpp +++ b/include/beast/zlib/basic_inflate_stream.hpp @@ -52,7 +52,7 @@ namespace zlib { This is a port of zlib's "inflate" functionality to C++. */ template -class basic_inflate_stream : public z_stream +class basic_inflate_stream : public z_params { public: struct params @@ -142,13 +142,13 @@ class basic_inflate_stream : public z_stream } void - inflate_fast(z_stream& zs, unsigned start); + inflate_fast(z_params& zs, unsigned start); int - write(z_stream& zs, int flush); + write(z_params& zs, int flush); void - resetKeep(z_stream& zs); + resetKeep(z_params& zs); void fixedTables(); diff --git a/include/beast/zlib/detail/bitstream.hpp b/include/beast/zlib/detail/bitstream.hpp index db2e0de17a..d7477442b3 100644 --- a/include/beast/zlib/detail/bitstream.hpp +++ b/include/beast/zlib/detail/bitstream.hpp @@ -37,6 +37,7 @@ #include #include +#include namespace beast { namespace zlib { diff --git a/include/beast/zlib/impl/basic_inflate_stream.ipp b/include/beast/zlib/impl/basic_inflate_stream.ipp index 79a7892495..b77a521399 100644 --- a/include/beast/zlib/impl/basic_inflate_stream.ipp +++ b/include/beast/zlib/impl/basic_inflate_stream.ipp @@ -94,7 +94,7 @@ write(int flush) template void basic_inflate_stream:: -resetKeep(z_stream& zs) +resetKeep(z_params& zs) { zs.total_in = 0; zs.total_out = 0; @@ -200,8 +200,12 @@ updatewindow(const Byte *end, unsigned copy) template int basic_inflate_stream:: -write(z_stream& zs, int flush) +write(z_params& zs, int flush) { + unsigned in; + unsigned out; // save starting available input and output + int result = Z_OK; + auto put = zs.next_out; auto next = zs.next_in; auto const outend = put + zs.avail_out; @@ -220,12 +224,11 @@ write(z_stream& zs, int flush) zs.avail_out = outend - put; zs.next_in = next; zs.avail_in = end - next; - return Z_OK; + if (((in == 0 && out == 0) || flush == Z_FINISH) && result == Z_OK) + result = Z_BUF_ERROR; + return result; }; - unsigned in, out; // save starting available input and output - int ret = Z_OK; - if(zs.next_out == 0 || (zs.next_in == 0 && zs.avail_in != 0)) return Z_STREAM_ERROR; @@ -373,9 +376,9 @@ write(z_stream& zs, int flush) next_ = &codes_[0]; lencode_ = next_; lenbits_ = 7; - ret = inflate_table(detail::CODES, &lens_[0], + result = inflate_table(detail::CODES, &lens_[0], order.size(), &next_, &lenbits_, work_); - if(ret) + if(result) { zs.msg = (char *)"invalid code lengths set"; mode_ = BAD; @@ -463,9 +466,9 @@ write(z_stream& zs, int flush) next_ = &codes_[0]; lencode_ = next_; lenbits_ = 9; - ret = inflate_table(detail::LENS, + result = inflate_table(detail::LENS, &lens_[0], nlen_, &next_, &lenbits_, work_); - if(ret) + if(result) { zs.msg = (char *)"invalid literal/lengths set"; mode_ = BAD; @@ -473,9 +476,9 @@ write(z_stream& zs, int flush) } distcode_ = next_; distbits_ = 6; - ret = inflate_table(detail::DISTS, + result = inflate_table(detail::DISTS, lens_ + nlen_, ndist_, &next_, &distbits_, work_); - if(ret) + if(result) { zs.msg = (char *)"invalid distances set"; mode_ = BAD; @@ -497,7 +500,7 @@ write(z_stream& zs, int flush) if(avail_in >= 6 && avail_out >= 258) { auto const nwritten = put - zs.next_out; - z_stream zc = zs; + z_params zc = zs; zc.next_out = put; zc.avail_out = outend - put; zc.next_in = next; @@ -677,11 +680,11 @@ write(z_stream& zs, int flush) // fall through case DONE: - ret = Z_STREAM_END; + result = Z_STREAM_END; goto inf_leave; case BAD: - ret = Z_DATA_ERROR; + result = Z_DATA_ERROR; goto inf_leave; case MEM: @@ -716,9 +719,9 @@ write(z_stream& zs, int flush) zs.data_type = bits_ + (last_ ? 64 : 0) + (mode_ == TYPE ? 128 : 0) + (mode_ == LEN_ || mode_ == COPY_ ? 256 : 0); - if(((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) - ret = Z_BUF_ERROR; - return ret; + if(((in == 0 && out == 0) || flush == Z_FINISH) && result == Z_OK) + result = Z_BUF_ERROR; + return result; } /* @@ -760,7 +763,7 @@ template void basic_inflate_stream:: inflate_fast( - z_stream& zs, + z_params& zs, unsigned start) // inflate()'s starting value for strm->avail_out { unsigned char const* in; // local strm->next_in diff --git a/include/beast/zlib/zlib.hpp b/include/beast/zlib/zlib.hpp index fd14a6f85b..fc458d2a81 100644 --- a/include/beast/zlib/zlib.hpp +++ b/include/beast/zlib/zlib.hpp @@ -73,7 +73,7 @@ typedef unsigned int uInt; /* 16 bits or more */ uncompressed data and may be saved for use in the decompressor (particularly if the decompressor wants to decompress everything in a single step). */ -struct z_stream +struct z_params { Byte const* next_in; // next input byte std::size_t avail_in; // number of bytes available at next_in diff --git a/test/Jamfile b/test/Jamfile index 17ae411fc8..297ae4569a 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -100,8 +100,10 @@ unit-test zlib-tests : zlib/zlib-1.2.8/trees.c zlib/zlib-1.2.8/uncompr.c zlib/zlib-1.2.8/zutil.c - zlib/inflate_stream.cpp + zlib/basic_deflate_stream.cpp + zlib/basic_inflate_stream.cpp zlib/deflate_stream.cpp + zlib/error.cpp zlib/inflate_stream.cpp zlib/zlib.cpp ; diff --git a/test/zlib/CMakeLists.txt b/test/zlib/CMakeLists.txt index 20a2a9fac6..86aa1512b1 100644 --- a/test/zlib/CMakeLists.txt +++ b/test/zlib/CMakeLists.txt @@ -39,6 +39,7 @@ add_executable (zlib-tests error.cpp inflate_stream.cpp zlib.cpp + ) if (NOT WIN32) diff --git a/test/zlib/inflate_stream.cpp b/test/zlib/inflate_stream.cpp index b52c38823c..5a0a372182 100644 --- a/test/zlib/inflate_stream.cpp +++ b/test/zlib/inflate_stream.cpp @@ -17,9 +17,13 @@ namespace zlib { class inflate_stream_test : public beast::unit_test::suite { public: + using self = inflate_stream_test; + typedef void(self::*pmf_t)( + int windowBits, std::string const& in, std::string const& check); + // Decompress using ZLib void - doInflate(int windowBits, + doInflate_zlib(int windowBits, std::string const& in, std::string const& check) { BEAST_EXPECT(in.size() > 1); @@ -72,9 +76,9 @@ class inflate_stream_test : public beast::unit_test::suite } } - // Decompress using ZLib + // Decompress using Beast void - doInflate2(int windowBits, + doInflate(int windowBits, std::string const& in, std::string const& check) { BEAST_EXPECT(in.size() > 1); @@ -131,18 +135,51 @@ class inflate_stream_test : public beast::unit_test::suite } void - doMatrix(std::string const& check) + doMatrix1(std::string const& check, pmf_t pmf) { - z_deflator zd; - doInflate2(15, zd(check), check); + for(int level = 0; level <= 9; ++level) + { + for(int windowBits = 8; windowBits <= 15; ++windowBits) + { + for(int strategy = 0; strategy <= 4; ++strategy) + { + z_deflator zd; + zd.level(level); + zd.windowBits(windowBits); + zd.strategy(strategy); + auto const in = zd(check); + (this->*pmf)(windowBits, in, check); + doInflate_zlib(windowBits, in, check); + } + } + } } void testInflate() { - doMatrix("Hello, world!"); - doMatrix("Hello, world! Hello, world!"); - doMatrix("Hello, world! Hello, world! Hello, world! Hello, world! Hello, world!"); + doMatrix1("Hello, world!", &self::doInflate_zlib); + doMatrix1("Hello, world!", &self::doInflate); + + doMatrix1( + "iEYEARECAAYFAjdY" + "CQoACgkQJ9S6ULt1" + "dqz6IwCfQ7wP6i/i" + "8HhbcOSKF4ELyQB1" + "oCoAoOuqpRqEzr4k" + "OkQqHRLE/b8/Rw2k", + &self::doInflate_zlib); + + doMatrix1( + "iEYEARECAAYFAjdY" + "CQoACgkQJ9S6ULt1" + "dqz6IwCfQ7wP6i/i" + "8HhbcOSKF4ELyQB1" + "oCoAoOuqpRqEzr4k" + "OkQqHRLE/b8/Rw2k", + &self::doInflate); + + //doMatrix("Hello, world! Hello, world! Hello, world! Hello, world! Hello, world!"); } void diff --git a/test/zlib/zlib.cpp b/test/zlib/zlib.cpp index c610f62d2d..411c43bdd0 100644 --- a/test/zlib/zlib.cpp +++ b/test/zlib/zlib.cpp @@ -224,7 +224,7 @@ class zlib_test : public beast::unit_test::suite } }; -BEAST_DEFINE_TESTSUITE(zlib,core,beast); +//BEAST_DEFINE_TESTSUITE(zlib,core,beast); } // zlib } // beast diff --git a/test/zlib/ztest.hpp b/test/zlib/ztest.hpp index bf2c4bf48e..bce7f637cc 100644 --- a/test/zlib/ztest.hpp +++ b/test/zlib/ztest.hpp @@ -13,7 +13,39 @@ class z_deflator { + int level_ = Z_DEFAULT_COMPRESSION; + int windowBits_ = 15; + int memLevel_ = 4; + int strategy_ = Z_DEFAULT_STRATEGY; + public: + // -1 = default + // 0 = none + // 1..9 = faster<-->better + void + level(int n) + { + level_ = n; + } + + void + windowBits(int n) + { + windowBits_ = n; + } + + void + memLevel(int n) + { + memLevel_ = n; + } + + void + strategy(int n) + { + strategy_ = n; + } + std::string operator()(std::string const& in) { @@ -22,12 +54,14 @@ class z_deflator memset(&zs, 0, sizeof(zs)); result = deflateInit2( &zs, - Z_DEFAULT_COMPRESSION, + level_, Z_DEFLATED, - -15, - 4, - Z_DEFAULT_STRATEGY + -windowBits_, + memLevel_, + strategy_ ); + if(result != Z_OK) + throw std::logic_error("deflateInit2 failed"); std::string out; out.resize(deflateBound(&zs, in.size())); zs.next_in = (Bytef*)in.data(); @@ -35,6 +69,8 @@ class z_deflator zs.next_out = (Bytef*)&out[0]; zs.avail_out = out.size(); result = deflate(&zs, Z_FULL_FLUSH); + if(result != Z_OK) + throw std::logic_error("deflate failed"); out.resize(zs.total_out); deflateEnd(&zs); return out;