From 92cd5ca0c4ba731dc35852153a7899bafd1e9caf Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Fri, 11 Sep 2020 08:56:12 -0700 Subject: [PATCH 1/2] Allow Zlib.crc32 and .adler32 to accept IO instance This reads from the IO in 8192 byte chunks, so you don't need to have the entire string in memory. Fixes #16 --- ext/zlib/zlib.c | 16 +++++++++++++++- test/zlib/test_zlib.rb | 26 ++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index bc41b55..30fda3e 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -407,6 +407,16 @@ do_checksum(int argc, VALUE *argv, uLong (*func)(uLong, const Bytef*, uInt)) if (NIL_P(str)) { sum = func(sum, Z_NULL, 0); } + else if (rb_obj_is_kind_of(str, rb_cIO)) { + VALUE buf; + VALUE buflen = INT2NUM(8192); + ID meth = rb_intern("read"); + + while (!NIL_P(buf = rb_funcall(str, meth, 1, buflen))) { + StringValue(buf); + sum = checksum_long(func, sum, (Bytef*)RSTRING_PTR(buf), RSTRING_LEN(buf)); + } + } else { StringValue(str); sum = checksum_long(func, sum, (Bytef*)RSTRING_PTR(str), RSTRING_LEN(str)); @@ -422,6 +432,8 @@ do_checksum(int argc, VALUE *argv, uLong (*func)(uLong, const Bytef*, uInt)) * Calculates Adler-32 checksum for +string+, and returns updated value of * +adler+. If +string+ is omitted, it returns the Adler-32 initial value. If * +adler+ is omitted, it assumes that the initial value is given to +adler+. + * If +string+ is an IO instance, reads from the IO until the IO returns nil + * and returns Adler-32 of all read data. * * Example usage: * @@ -466,7 +478,9 @@ rb_zlib_adler32_combine(VALUE klass, VALUE adler1, VALUE adler2, VALUE len2) * * Calculates CRC checksum for +string+, and returns updated value of +crc+. If * +string+ is omitted, it returns the CRC initial value. If +crc+ is omitted, it - * assumes that the initial value is given to +crc+. + * assumes that the initial value is given to +crc+. If +string+ is an IO instance, + * reads from the IO until the IO returns nil and returns CRC checksum of all read + * data. * * FIXME: expression. */ diff --git a/test/zlib/test_zlib.rb b/test/zlib/test_zlib.rb index c58eafe..c72fe76 100644 --- a/test/zlib/test_zlib.rb +++ b/test/zlib/test_zlib.rb @@ -1145,6 +1145,19 @@ def test_adler32 assert_equal(0x02820145, Zlib.adler32("foo")) assert_equal(0x02820145, Zlib.adler32("o", Zlib.adler32("fo"))) assert_equal(0x8a62c964, Zlib.adler32("abc\x01\x02\x03" * 10000)) + Tempfile.create("test_zlib_gzip_file_to_io") {|t| + File.binwrite(t.path, "foo") + t.rewind + assert_equal(0x02820145, Zlib.adler32(t)) + + t.rewind + crc = Zlib.adler32(t.read(2)) + assert_equal(0x02820145, Zlib.adler32(t, crc)) + + File.binwrite(t.path, "abc\x01\x02\x03" * 10000) + t.rewind + assert_equal(0x8a62c964, Zlib.adler32(t)) + } end def test_adler32_combine @@ -1167,6 +1180,19 @@ def test_crc32 assert_equal(0x8c736521, Zlib.crc32("foo")) assert_equal(0x8c736521, Zlib.crc32("o", Zlib.crc32("fo"))) assert_equal(0x07f0d68f, Zlib.crc32("abc\x01\x02\x03" * 10000)) + Tempfile.create("test_zlib_gzip_file_to_io") {|t| + File.binwrite(t.path, "foo") + t.rewind + assert_equal(0x8c736521, Zlib.crc32(t)) + + t.rewind + crc = Zlib.crc32(t.read(2)) + assert_equal(0x8c736521, Zlib.crc32(t, crc)) + + File.binwrite(t.path, "abc\x01\x02\x03" * 10000) + t.rewind + assert_equal(0x07f0d68f, Zlib.crc32(t)) + } end def test_crc32_combine From 9e9a8d5a9c3a6b8996b0eeba38239b07edd0bbd3 Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Wed, 28 Oct 2020 10:49:04 -0700 Subject: [PATCH 2/2] Use id_read --- ext/zlib/zlib.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index 30fda3e..2e8c37e 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -56,7 +56,7 @@ max_uint(long n) #define MAX_UINT(n) (uInt)(n) #endif -static ID id_dictionaries; +static ID id_dictionaries, id_read; /*--------- Prototypes --------*/ @@ -410,9 +410,8 @@ do_checksum(int argc, VALUE *argv, uLong (*func)(uLong, const Bytef*, uInt)) else if (rb_obj_is_kind_of(str, rb_cIO)) { VALUE buf; VALUE buflen = INT2NUM(8192); - ID meth = rb_intern("read"); - while (!NIL_P(buf = rb_funcall(str, meth, 1, buflen))) { + while (!NIL_P(buf = rb_funcall(str, id_read, 1, buflen))) { StringValue(buf); sum = checksum_long(func, sum, (Bytef*)RSTRING_PTR(buf), RSTRING_LEN(buf)); } @@ -2212,7 +2211,7 @@ rb_inflate_set_dictionary(VALUE obj, VALUE dic) #define OS_CODE OS_UNIX #endif -static ID id_write, id_read, id_readpartial, id_flush, id_seek, id_close, id_path, id_input; +static ID id_write, id_readpartial, id_flush, id_seek, id_close, id_path, id_input; static VALUE cGzError, cNoFooter, cCRCError, cLengthError;