ruby-changes:62936
From: Jeremy <ko1@a...>
Date: Mon, 14 Sep 2020 17:53:47 +0900 (JST)
Subject: [ruby-changes:62936] d52dffd817 (master): [ruby/zlib] Add Zlib::GzipReader.zcat for handling multiple gzip streams in gz file
https://git.ruby-lang.org/ruby.git/commit/?id=d52dffd817 From d52dffd817d9285f7600138e2f69f46891fff845 Mon Sep 17 00:00:00 2001 From: Jeremy Evans <code@j...> Date: Tue, 26 Nov 2019 17:31:47 -0800 Subject: [ruby/zlib] Add Zlib::GzipReader.zcat for handling multiple gzip streams in gz file Most gzip tools support concatenated gz streams in a gz file. This offers a way to handle such gz files in Ruby. Fixes [Bug #9790] Fixes [Bug #11180] Fixes [Bug #14804] https://github.com/ruby/zlib/commit/e2ce56de7d diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index 5c8aab2..bc41b55 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -3724,6 +3724,60 @@ rb_gzreader_s_open(int argc, VALUE *argv, VALUE klass) https://github.com/ruby/ruby/blob/trunk/ext/zlib/zlib.c#L3724 } /* + * Document-method: Zlib::GzipReader.zcat + * + * call-seq: + * Zlib::GzipReader.zcat(io, options = {}, &block) => nil + * Zlib::GzipReader.zcat(io, options = {}) => string + * + * Decompresses all gzip data in the +io+, handling multiple gzip + * streams until the end of the +io+. There should not be any non-gzip + * data after the gzip streams. + * + * If a block is given, it is yielded strings of uncompressed data, + * and the method returns +nil+. + * If a block is not given, the method returns the concatenation of + * all uncompressed data in all gzip streams. + */ +static VALUE +rb_gzreader_s_zcat(int argc, VALUE *argv, VALUE klass) +{ + VALUE io, unused, obj, buf=0, tmpbuf; + long pos; + + rb_check_arity(argc, 1, 2); + io = argv[0]; + + do { + obj = rb_funcallv(klass, rb_intern("new"), argc, argv); + if (rb_block_given_p()) { + rb_gzreader_each(0, 0, obj); + } + else { + if (!buf) { + buf = rb_str_new(0, 0); + } + tmpbuf = gzfile_read_all(get_gzfile(obj)); + rb_str_cat(buf, RSTRING_PTR(tmpbuf), RSTRING_LEN(tmpbuf)); + } + + rb_gzreader_read(0, 0, obj); + pos = NUM2LONG(rb_funcall(io, rb_intern("pos"), 0)); + unused = rb_gzreader_unused(obj); + rb_gzfile_finish(obj); + if (!NIL_P(unused)) { + pos -= NUM2LONG(rb_funcall(unused, rb_intern("length"), 0)); + rb_funcall(io, rb_intern("pos="), 1, LONG2NUM(pos)); + } + } while (pos < NUM2LONG(rb_funcall(io, rb_intern("size"), 0))); + + if (rb_block_given_p()) { + return Qnil; + } + return buf; +} + +/* * Document-method: Zlib::GzipReader.new * * call-seq: @@ -4696,6 +4750,7 @@ Init_zlib(void) https://github.com/ruby/ruby/blob/trunk/ext/zlib/zlib.c#L4750 rb_define_method(cGzipWriter, "puts", rb_gzwriter_puts, -1); rb_define_singleton_method(cGzipReader, "open", rb_gzreader_s_open,-1); + rb_define_singleton_method(cGzipReader, "zcat", rb_gzreader_s_zcat, -1); rb_define_alloc_func(cGzipReader, rb_gzreader_s_allocate); rb_define_method(cGzipReader, "initialize", rb_gzreader_initialize, -1); rb_define_method(cGzipReader, "rewind", rb_gzreader_rewind, 0); diff --git a/test/zlib/test_zlib.rb b/test/zlib/test_zlib.rb index 7d703d1..c58eafe 100644 --- a/test/zlib/test_zlib.rb +++ b/test/zlib/test_zlib.rb @@ -446,6 +446,30 @@ if defined? Zlib https://github.com/ruby/ruby/blob/trunk/test/zlib/test_zlib.rb#L446 end class TestZlibGzipFile < Test::Unit::TestCase + def test_gzip_reader_zcat + Tempfile.create("test_zlib_gzip_file_to_io") {|t| + gz = Zlib::GzipWriter.new(t) + gz.print("foo") + gz.close + t = File.open(t.path, 'ab') + gz = Zlib::GzipWriter.new(t) + gz.print("bar") + gz.close + + results = [] + t = File.open(t.path) + Zlib::GzipReader.zcat(t) do |str| + results << str + end + assert_equal(["foo", "bar"], results) + t.close + + t = File.open(t.path) + assert_equal("foobar", Zlib::GzipReader.zcat(t)) + t.close + } + end + def test_to_io Tempfile.create("test_zlib_gzip_file_to_io") {|t| t.close -- cgit v0.10.2 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/