From 264ec99e7bae08710449262e609c20ad76383615 Mon Sep 17 00:00:00 2001 From: ljfa-ag Date: Wed, 16 Sep 2015 18:41:45 +0200 Subject: Changes to deflate_streambuf and ozlibstream constructors --- include/io/izlibstream.h | 3 ++- include/io/ozlibstream.h | 33 ++++++++++++++++++--------------- 2 files changed, 20 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/include/io/izlibstream.h b/include/io/izlibstream.h index 6d58d56b86..43d2d2c02e 100644 --- a/include/io/izlibstream.h +++ b/include/io/izlibstream.h @@ -38,7 +38,8 @@ public: * @param input the istream to wrap * @param bufsize the size of the internal buffers * @param window_bits the base two logarithm of the maximum window size that - * zlib will use. This parameter also determines which type of input to expect. + * zlib will use. + * This parameter also determines which type of input to expect. * The default argument will autodetect between zlib and gzip data. * Refer to the zlib documentation of inflateInit2 for more details. * diff --git a/include/io/ozlibstream.h b/include/io/ozlibstream.h index 0e19aaaa2b..0be792d482 100644 --- a/include/io/ozlibstream.h +++ b/include/io/ozlibstream.h @@ -29,12 +29,21 @@ namespace zlib /** * @brief Stream buffer used by zlib::ozlibstream - * @see ozlibstream + * @sa ozlibstream */ class deflate_streambuf : public std::streambuf { public: - explicit deflate_streambuf(std::ostream& output, int level = -1, int window_bits = 15, int mem_level = 8, int strategy = Z_DEFAULT_STRATEGY); + /** + * @param output the ostream to wrap + * @param bufsize the size of the internal buffers + * @param level the compression level, ranges from 0 to 9 + * + * Refer to the zlib documentation of deflateInit2 for details about the arguments. + * + * @throw zlib_error if zlib encounters a problem during initialization + */ + explicit deflate_streambuf(std::ostream& output, size_t bufsize = 32768, int level = Z_DEFAULT_COMPRESSION, int window_bits = 15, int mem_level = 8, int strategy = Z_DEFAULT_STRATEGY); ~deflate_streambuf() noexcept; std::ostream& get_ostr() const { return os; } @@ -56,28 +65,22 @@ private: * * This ostream wraps another ostream. Data written to an ozlibstream will be * deflated (compressed) with zlib and written to the wrapped ostream. + * + * @sa deflate_streambuf */ class ozlibstream : public std::ostream { public: /** * @param output the ostream to wrap - * @param level the compression level. Ranges from 0 to 9, or -1 for the default - * @param gzip_header whether to write a gzip header rather than a zlib header + * @param level the compression level, ranges from 0 to 9 + * @param gzip if true, the output will be in gzip format rather than zlib + * @param bufsize the size of the internal buffers */ - explicit ozlibstream(std::ostream& output, int level, bool gzip): - ozlibstream(output, level, 15 + (gzip ? 16 : 0)) + explicit ozlibstream(std::ostream& output, int level = Z_DEFAULT_COMPRESSION, bool gzip = false, size_t bufsize = 32768): + std::ostream(&buf), buf(output, level, bufsize, 15 + (gzip ? 16 : 0)) {} - /** - * @param output the ostream to wrap - * @param level the compression level. Ranges from 0 to 9, or -1 for the default - * - * Refer to the zlib documentation of deflateInit2 for a detailed explanation of the arguments. - */ - explicit ozlibstream(std::ostream& output, int level = -1, int window_bits = 15, int mem_level = 8, int strategy = Z_DEFAULT_STRATEGY): - std::ostream(&buf), buf(output, level, window_bits, mem_level, strategy) - {} ///@return the wrapped ostream std::ostream& get_ostr() const { return buf.get_ostr(); } -- cgit 0.0.5-2-1-g0f52 From 84d2896da1c3f3ef0be80476585422d8b1230289 Mon Sep 17 00:00:00 2001 From: ljfa-ag Date: Sun, 20 Sep 2015 19:15:27 +0200 Subject: Implement ozlibstream --- CMakeLists.txt | 1 + include/io/ozlibstream.h | 2 +- src/io/ozlibstream.cpp | 87 ++++++++++++++++++++++++++++++++++++++++++++++++ test/zlibstream_test.h | 20 +++++++++++ 4 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 src/io/ozlibstream.cpp (limited to 'include') diff --git a/CMakeLists.txt b/CMakeLists.txt index bed0ca668a..39a3a5759c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,7 @@ add_library(nbt++ STATIC src/value_initializer.cpp src/io/izlibstream.cpp + src/io/ozlibstream.cpp src/io/stream_reader.cpp src/io/stream_writer.cpp diff --git a/include/io/ozlibstream.h b/include/io/ozlibstream.h index 0be792d482..d4ea8c2840 100644 --- a/include/io/ozlibstream.h +++ b/include/io/ozlibstream.h @@ -78,7 +78,7 @@ public: * @param bufsize the size of the internal buffers */ explicit ozlibstream(std::ostream& output, int level = Z_DEFAULT_COMPRESSION, bool gzip = false, size_t bufsize = 32768): - std::ostream(&buf), buf(output, level, bufsize, 15 + (gzip ? 16 : 0)) + std::ostream(&buf), buf(output, bufsize, level, 15 + (gzip ? 16 : 0)) {} ///@return the wrapped ostream diff --git a/src/io/ozlibstream.cpp b/src/io/ozlibstream.cpp new file mode 100644 index 0000000000..97702a37e1 --- /dev/null +++ b/src/io/ozlibstream.cpp @@ -0,0 +1,87 @@ +/* + * libnbt++ - A library for the Minecraft Named Binary Tag format. + * Copyright (C) 2013, 2015 ljfa-ag + * + * This file is part of libnbt++. + * + * libnbt++ is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libnbt++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libnbt++. If not, see . + */ +#include "io/ozlibstream.h" +#include "io/zlib_error.h" + +namespace zlib +{ + +deflate_streambuf::deflate_streambuf(std::ostream& output, size_t bufsize, int level, int window_bits, int mem_level, int strategy): + os(output), in(bufsize), out(bufsize) +{ + zstr.zalloc = Z_NULL; + zstr.zfree = Z_NULL; + zstr.opaque = Z_NULL; + int ret = deflateInit2(&zstr, level, Z_DEFLATED, window_bits, mem_level, strategy); + if(ret != Z_OK) + throw zlib_error(zstr.msg, ret); + + setp(in.data(), in.data() + in.size()); +} + +deflate_streambuf::~deflate_streambuf() noexcept +{ + try + { + deflate_chunk(Z_FINISH); + } + catch(...) + { + //ignore as we can't do anything about it + } + deflateEnd(&zstr); +} + +void deflate_streambuf::deflate_chunk(int flush) +{ + zstr.next_in = reinterpret_cast(pbase()); + zstr.avail_in = pptr() - pbase(); + do + { + zstr.next_out = reinterpret_cast(out.data()); + zstr.avail_out = out.size(); + int ret = deflate(&zstr, flush); + if(ret != Z_OK && ret != Z_STREAM_END) + throw zlib_error(zstr.msg, ret); + int have = out.size() - zstr.avail_out; + if(!os.write(out.data(), have)) + throw std::ios_base::failure("Could not write to the output stream"); + } while(zstr.avail_out == 0); + setp(in.data(), in.data() + in.size()); +} + +deflate_streambuf::int_type deflate_streambuf::overflow(int_type ch) +{ + deflate_chunk(); + if(ch != traits_type::eof()) + { + *pptr() = ch; + pbump(1); + } + return ch; +} + +int deflate_streambuf::sync() +{ + deflate_chunk(); + return 0; +} + +} diff --git a/test/zlibstream_test.h b/test/zlibstream_test.h index 2a94ab7ccb..e0b22c1356 100644 --- a/test/zlibstream_test.h +++ b/test/zlibstream_test.h @@ -133,4 +133,24 @@ public: TS_ASSERT(igzs.bad()); } } + + void test_deflate_zlib() + { + //Here we assume that inflating works and has already been tested + std::stringstream str; + std::stringbuf output; + //Small buffer + { + ozlibstream ozls(str, -1, false, 256); + ozls.exceptions(std::ios::failbit | std::ios::badbit); + ozls << bigtest; + TS_ASSERT(ozls.good()); + } + { + izlibstream izls(str); + izls >> &output; + TS_ASSERT(izls); + } + TS_ASSERT_EQUALS(output.str(), bigtest); + } }; -- cgit 0.0.5-2-1-g0f52