diff --git a/include/boost/iostreams/filter/gzip.hpp b/include/boost/iostreams/filter/gzip.hpp index e236983e0..e13a325d9 100644 --- a/include/boost/iostreams/filter/gzip.hpp +++ b/include/boost/iostreams/filter/gzip.hpp @@ -193,6 +193,7 @@ class basic_gzip_compressor : basic_zlib_compressor { struct category : dual_use, filter_tag, + flushable_tag, multichar_tag, closable_tag { }; @@ -271,6 +272,12 @@ class basic_gzip_compressor : basic_zlib_compressor { } close_impl(); } + + template + bool flush(Sink& snk) { + base_type::force_flush(snk); + return true; + } private: static gzip_params normalize_params(gzip_params p); void prepare_footer(); diff --git a/include/boost/iostreams/filter/symmetric.hpp b/include/boost/iostreams/filter/symmetric.hpp index f18089f4f..b387799e4 100644 --- a/include/boost/iostreams/filter/symmetric.hpp +++ b/include/boost/iostreams/filter/symmetric.hpp @@ -185,6 +185,28 @@ class symmetric_filter { close_impl(); } } + + template + void force_flush(Sink &snk) { + if (!(state() & f_write)) + begin_write(); + try { + buffer_type& buf = pimpl_->buf_; + char_type dummy; + const char_type* end = &dummy; + // Repeatedly invoke filter() with no input. + bool again = true; + while(again) { + if(buf.ptr() != buf.eptr()) { + again = filter().force_flush(end, end, buf.ptr(), buf.eptr()); + } + flush(snk); + } + } catch (...) { + throw; + } + } + SymmetricFilter& filter() { return *pimpl_; } string_type unconsumed_input() const; diff --git a/include/boost/iostreams/filter/zlib.hpp b/include/boost/iostreams/filter/zlib.hpp index e57870a51..b71cde412 100644 --- a/include/boost/iostreams/filter/zlib.hpp +++ b/include/boost/iostreams/filter/zlib.hpp @@ -84,6 +84,7 @@ BOOST_IOSTREAMS_DECL extern const int buf_error; BOOST_IOSTREAMS_DECL extern const int finish; BOOST_IOSTREAMS_DECL extern const int no_flush; BOOST_IOSTREAMS_DECL extern const int sync_flush; +BOOST_IOSTREAMS_DECL extern const int full_flush; // Code for current OS @@ -232,6 +233,8 @@ class zlib_compressor_impl : public zlib_base, public zlib_allocator { bool filter( const char*& src_begin, const char* src_end, char*& dest_begin, char* dest_end, bool flush ); void close(); + bool force_flush( const char*& src_begin, const char* src_end, + char*& dest_begin, char* dest_end); }; // @@ -361,6 +364,18 @@ bool zlib_compressor_impl::filter template void zlib_compressor_impl::close() { reset(true, true); } +template +bool zlib_compressor_impl::force_flush + ( const char*& src_begin, const char* src_end, + char*& dest_begin, char* dest_end) +{ + before(src_begin, src_end, dest_begin, dest_end); + int result = xdeflate(zlib::full_flush); + after(src_begin, dest_begin, true); + zlib_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(result); + return result == zlib::okay; +} + //------------------Implementation of zlib_decompressor_impl------------------// template diff --git a/src/zlib.cpp b/src/zlib.cpp index 66380689b..9eb64ce8e 100644 --- a/src/zlib.cpp +++ b/src/zlib.cpp @@ -58,6 +58,7 @@ const int buf_error = Z_BUF_ERROR; const int finish = Z_FINISH; const int no_flush = Z_NO_FLUSH; const int sync_flush = Z_SYNC_FLUSH; +const int full_flush = Z_FULL_FLUSH; // Code for current OS @@ -76,7 +77,7 @@ void zlib_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(int error) switch (error) { case Z_OK: case Z_STREAM_END: - //case Z_BUF_ERROR: + case Z_BUF_ERROR: return; case Z_MEM_ERROR: boost::throw_exception(std::bad_alloc());