diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index f13ef4d..d51ac30 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -1216,6 +1216,8 @@ zstream_run_try(VALUE value_arg) } } } + z->stream.next_in = Z_NULL; + z->stream.avail_in = 0; raise_zlib_error(err, z->stream.msg); } @@ -1225,6 +1227,9 @@ zstream_run_try(VALUE value_arg) if (!NIL_P(old_input)) { rb_str_resize(old_input, 0); } + /* the rest is in z->input now; do not leave next_in in old_input */ + z->stream.next_in = Z_NULL; + z->stream.avail_in = 0; return Qnil; } @@ -2144,7 +2149,8 @@ do_inflate(struct zstream *z, VALUE src) return; } StringValue(src); - if (RSTRING_LEN(src) > 0 || z->stream.avail_in > 0) { /* prevent Z_BUF_ERROR */ + if (RSTRING_LEN(src) > 0 || + (!NIL_P(z->input) && RSTRING_LEN(z->input) > 0)) { /* prevent Z_BUF_ERROR */ zstream_run(z, (Bytef*)RSTRING_PTR(src), RSTRING_LEN(src), Z_SYNC_FLUSH); } } diff --git a/test/zlib/test_zlib.rb b/test/zlib/test_zlib.rb index e1ecbf8..fd85f01 100644 --- a/test/zlib/test_zlib.rb +++ b/test/zlib/test_zlib.rb @@ -102,6 +102,38 @@ def test_deflate_chunked_break assert_equal input, original end + def test_params_after_chunked_break + chunks = [] + r = Random.new 0 + + # small enough that params can flush what zlib holds without Z_BUF_ERROR + z = Zlib::Deflate.new(Zlib::DEFAULT_COMPRESSION, 9, 1) + + input = r.bytes(20000) + z.deflate(input) do |chunk| + chunks << chunk + break + end + + assert_operator 0, :<, z.avail_in + + z.params(Zlib::BEST_SPEED, Zlib::FILTERED) + chunks << z.finish + + assert_equal input, Zlib.inflate(chunks.join) + end + + def test_params_after_failed_deflate + z = Zlib::Deflate.new + z << "foo" + assert_raise(Zlib::StreamError) { z.deflate("bar", 10000) } + assert_equal "bar", z.flush_next_in + + z.params(Zlib::BEST_SPEED, Zlib::FILTERED) + + assert_equal "foo", Zlib::Inflate.inflate(z.finish) + end + def test_addstr z = Zlib::Deflate.new z << "foo" @@ -620,6 +652,24 @@ def test_inflate_dictionary assert_equal "foofoofoo", out end + def test_inflate_empty_after_chunked_break + chunks = [] + input = Random.new(0).bytes(20000) + + z = Zlib::Inflate.new + + z.inflate(Zlib.deflate(input)) do |chunk| + chunks << chunk + break + end + + assert_operator 0, :<, z.avail_in + + chunks << z.inflate("") + + assert_equal input, chunks.join + end + def test_sync z = Zlib::Deflate.new s = z.deflate("foo" * 1000, Zlib::FULL_FLUSH)