Skip to content

Commit ba9793c

Browse files
authored
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
1 parent 448e41e commit ba9793c

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed

ext/zlib/zlib.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ max_uint(long n)
5656
#define MAX_UINT(n) (uInt)(n)
5757
#endif
5858

59-
static ID id_dictionaries;
59+
static ID id_dictionaries, id_read;
6060

6161
/*--------- Prototypes --------*/
6262

@@ -407,6 +407,15 @@ do_checksum(int argc, VALUE *argv, uLong (*func)(uLong, const Bytef*, uInt))
407407
if (NIL_P(str)) {
408408
sum = func(sum, Z_NULL, 0);
409409
}
410+
else if (rb_obj_is_kind_of(str, rb_cIO)) {
411+
VALUE buf;
412+
VALUE buflen = INT2NUM(8192);
413+
414+
while (!NIL_P(buf = rb_funcall(str, id_read, 1, buflen))) {
415+
StringValue(buf);
416+
sum = checksum_long(func, sum, (Bytef*)RSTRING_PTR(buf), RSTRING_LEN(buf));
417+
}
418+
}
410419
else {
411420
StringValue(str);
412421
sum = checksum_long(func, sum, (Bytef*)RSTRING_PTR(str), RSTRING_LEN(str));
@@ -422,6 +431,8 @@ do_checksum(int argc, VALUE *argv, uLong (*func)(uLong, const Bytef*, uInt))
422431
* Calculates Adler-32 checksum for +string+, and returns updated value of
423432
* +adler+. If +string+ is omitted, it returns the Adler-32 initial value. If
424433
* +adler+ is omitted, it assumes that the initial value is given to +adler+.
434+
* If +string+ is an IO instance, reads from the IO until the IO returns nil
435+
* and returns Adler-32 of all read data.
425436
*
426437
* Example usage:
427438
*
@@ -466,7 +477,9 @@ rb_zlib_adler32_combine(VALUE klass, VALUE adler1, VALUE adler2, VALUE len2)
466477
*
467478
* Calculates CRC checksum for +string+, and returns updated value of +crc+. If
468479
* +string+ is omitted, it returns the CRC initial value. If +crc+ is omitted, it
469-
* assumes that the initial value is given to +crc+.
480+
* assumes that the initial value is given to +crc+. If +string+ is an IO instance,
481+
* reads from the IO until the IO returns nil and returns CRC checksum of all read
482+
* data.
470483
*
471484
* FIXME: expression.
472485
*/
@@ -2198,7 +2211,7 @@ rb_inflate_set_dictionary(VALUE obj, VALUE dic)
21982211
#define OS_CODE OS_UNIX
21992212
#endif
22002213

2201-
static ID id_write, id_read, id_readpartial, id_flush, id_seek, id_close, id_path, id_input;
2214+
static ID id_write, id_readpartial, id_flush, id_seek, id_close, id_path, id_input;
22022215
static VALUE cGzError, cNoFooter, cCRCError, cLengthError;
22032216

22042217

test/zlib/test_zlib.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,6 +1145,19 @@ def test_adler32
11451145
assert_equal(0x02820145, Zlib.adler32("foo"))
11461146
assert_equal(0x02820145, Zlib.adler32("o", Zlib.adler32("fo")))
11471147
assert_equal(0x8a62c964, Zlib.adler32("abc\x01\x02\x03" * 10000))
1148+
Tempfile.create("test_zlib_gzip_file_to_io") {|t|
1149+
File.binwrite(t.path, "foo")
1150+
t.rewind
1151+
assert_equal(0x02820145, Zlib.adler32(t))
1152+
1153+
t.rewind
1154+
crc = Zlib.adler32(t.read(2))
1155+
assert_equal(0x02820145, Zlib.adler32(t, crc))
1156+
1157+
File.binwrite(t.path, "abc\x01\x02\x03" * 10000)
1158+
t.rewind
1159+
assert_equal(0x8a62c964, Zlib.adler32(t))
1160+
}
11481161
end
11491162

11501163
def test_adler32_combine
@@ -1167,6 +1180,19 @@ def test_crc32
11671180
assert_equal(0x8c736521, Zlib.crc32("foo"))
11681181
assert_equal(0x8c736521, Zlib.crc32("o", Zlib.crc32("fo")))
11691182
assert_equal(0x07f0d68f, Zlib.crc32("abc\x01\x02\x03" * 10000))
1183+
Tempfile.create("test_zlib_gzip_file_to_io") {|t|
1184+
File.binwrite(t.path, "foo")
1185+
t.rewind
1186+
assert_equal(0x8c736521, Zlib.crc32(t))
1187+
1188+
t.rewind
1189+
crc = Zlib.crc32(t.read(2))
1190+
assert_equal(0x8c736521, Zlib.crc32(t, crc))
1191+
1192+
File.binwrite(t.path, "abc\x01\x02\x03" * 10000)
1193+
t.rewind
1194+
assert_equal(0x07f0d68f, Zlib.crc32(t))
1195+
}
11701196
end
11711197

11721198
def test_crc32_combine

0 commit comments

Comments
 (0)