Skip to content

Commit bc63ec5

Browse files
jeremyevanshsbt
authored andcommitted
[ruby/zlib] 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 ruby/zlib@ba9793c550
1 parent a60dfff commit bc63ec5

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)