From 1516f8eb9f1c3957d5d97c85e35fdefade9ae137 Mon Sep 17 00:00:00 2001 From: drbrain Date: Sat, 11 Feb 2012 00:37:44 +0000 Subject: * ext/zlib/zlib.c (rb_inflate_add_dictionary): Added Zlib::Inflate#add_dictionary to allow users to pre-specify for using during #inflate. [ruby-trunk - Feature #5937] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@34553 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 6 ++++++ ext/zlib/zlib.c | 40 +++++++++++++++++++++++++++++++++++++--- test/zlib/test_zlib.rb | 17 +++++++++++++++++ 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3722311746..d3ff66d588 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Sat Feb 11 08:34:42 2012 Eric Hodel + + * ext/zlib/zlib.c (rb_inflate_add_dictionary): Added + Zlib::Inflate#add_dictionary to allow users to pre-specify + for using during #inflate. [ruby-trunk - Feature #5937] + Sat Feb 11 08:23:02 2012 Eric Hodel * ext/zlib/zlib.c (do_inflate): Inflate more data if buffered data diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index 6cc6d5571f..748a76a423 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -56,6 +56,8 @@ max_uint(long n) #define sizeof(x) ((int)sizeof(x)) +static ID id_dictionaries; + /*--------- Prototypes --------*/ static NORETURN(void raise_zlib_error(int, const char*)); @@ -875,6 +877,15 @@ zstream_run(struct zstream *z, Bytef *src, long len, int flush) if (z->stream.avail_in > 0) { zstream_append_input(z, z->stream.next_in, z->stream.avail_in); } + if (err == Z_NEED_DICT) { + VALUE self = (VALUE)z->stream.opaque; + VALUE dicts = rb_ivar_get(self, id_dictionaries); + VALUE dict = rb_hash_aref(dicts, rb_uint2inum(z->stream.adler)); + if (!NIL_P(dict)) { + rb_inflate_set_dictionary(self, dict); + continue; + } + } raise_zlib_error(err, z->stream.msg); } if (z->stream.avail_out > 0) { @@ -965,6 +976,7 @@ zstream_new(VALUE klass, const struct zstream_funcs *funcs) obj = Data_Make_Struct(klass, struct zstream, zstream_mark, zstream_free, z); zstream_init(z, funcs); + z->stream.opaque = (voidpf)obj; return obj; } @@ -1602,12 +1614,12 @@ rb_deflate_set_dictionary(VALUE obj, VALUE dic) * dup) itself. */ - - static VALUE rb_inflate_s_allocate(VALUE klass) { - return zstream_inflate_new(klass); + VALUE inflate = zstream_inflate_new(klass); + rb_ivar_set(inflate, id_dictionaries, rb_hash_new()); + return inflate; } /* @@ -1737,6 +1749,25 @@ do_inflate(struct zstream *z, VALUE src) } } +/* Document-method: Zlib::Inflate#add_dictionary + * + * call-seq: add_dictionary(string) + * + * Provide the inflate stream with a dictionary that may be required in the + * future. Multiple dictionaries may be provided. The inflate stream will + * automatically choose the correct user-provided dictionary based on the + * stream's required dictionary. + */ +static VALUE +rb_inflate_add_dictionary(VALUE obj, VALUE dictionary) { + VALUE dictionaries = rb_ivar_get(obj, id_dictionaries); + VALUE checksum = do_checksum(1, &dictionary, adler32); + + rb_hash_aset(dictionaries, checksum, dictionary); + + return obj; +} + /* * Document-method: Zlib::Inflate#inflate * @@ -4018,6 +4049,8 @@ Init_zlib() mZlib = rb_define_module("Zlib"); + id_dictionaries = rb_intern("@dictionaries"); + cZError = rb_define_class_under(mZlib, "Error", rb_eStandardError); cStreamEnd = rb_define_class_under(mZlib, "StreamEnd", cZError); cNeedDict = rb_define_class_under(mZlib, "NeedDict", cZError); @@ -4086,6 +4119,7 @@ Init_zlib() rb_define_singleton_method(mZlib, "inflate", rb_inflate_s_inflate, 1); rb_define_alloc_func(cInflate, rb_inflate_s_allocate); rb_define_method(cInflate, "initialize", rb_inflate_initialize, -1); + rb_define_method(cInflate, "add_dictionary", rb_inflate_add_dictionary, 1); rb_define_method(cInflate, "inflate", rb_inflate_inflate, 1); rb_define_method(cInflate, "<<", rb_inflate_addstr, 1); rb_define_method(cInflate, "sync", rb_inflate_sync, 1); diff --git a/test/zlib/test_zlib.rb b/test/zlib/test_zlib.rb index da4f74c475..b526d24df9 100644 --- a/test/zlib/test_zlib.rb +++ b/test/zlib/test_zlib.rb @@ -185,6 +185,23 @@ if defined? Zlib assert_equal("foo", z.finish) end + def test_add_dictionary + dictionary = "foo" + + deflate = Zlib::Deflate.new + deflate.set_dictionary dictionary + compressed = deflate.deflate "foofoofoo", Zlib::FINISH + deflate.close + + out = nil + inflate = Zlib::Inflate.new + inflate.add_dictionary "foo" + + out = inflate.inflate compressed + + assert_equal "foofoofoo", out + end + def test_inflate s = Zlib::Deflate.deflate("foo") z = Zlib::Inflate.new -- cgit v1.2.3