diff options
Diffstat (limited to 'ext/zlib')
| -rw-r--r-- | ext/zlib/depend | 43 | ||||
| -rw-r--r-- | ext/zlib/extconf.rb | 20 | ||||
| -rw-r--r-- | ext/zlib/extlibs | 8 | ||||
| -rw-r--r-- | ext/zlib/win32/zlib-1.2.11-mswin.patch | 95 | ||||
| -rw-r--r-- | ext/zlib/zlib.c | 621 | ||||
| -rw-r--r-- | ext/zlib/zlib.gemspec | 6 |
6 files changed, 443 insertions, 350 deletions
diff --git a/ext/zlib/depend b/ext/zlib/depend index 5433affc69..22e9ca867a 100644 --- a/ext/zlib/depend +++ b/ext/zlib/depend @@ -2,6 +2,20 @@ zlib.o: $(RUBY_EXTCONF_H) zlib.o: $(arch_hdrdir)/ruby/config.h zlib.o: $(hdrdir)/ruby.h +zlib.o: $(hdrdir)/ruby/assert.h +zlib.o: $(hdrdir)/ruby/backward.h +zlib.o: $(hdrdir)/ruby/backward/2/assume.h +zlib.o: $(hdrdir)/ruby/backward/2/attributes.h +zlib.o: $(hdrdir)/ruby/backward/2/bool.h +zlib.o: $(hdrdir)/ruby/backward/2/inttypes.h +zlib.o: $(hdrdir)/ruby/backward/2/limits.h +zlib.o: $(hdrdir)/ruby/backward/2/long_long.h +zlib.o: $(hdrdir)/ruby/backward/2/stdalign.h +zlib.o: $(hdrdir)/ruby/backward/2/stdarg.h +zlib.o: $(hdrdir)/ruby/defines.h +zlib.o: $(hdrdir)/ruby/encoding.h +zlib.o: $(hdrdir)/ruby/intern.h +zlib.o: $(hdrdir)/ruby/internal/abi.h zlib.o: $(hdrdir)/ruby/internal/anyargs.h zlib.o: $(hdrdir)/ruby/internal/arithmetic.h zlib.o: $(hdrdir)/ruby/internal/arithmetic/char.h @@ -39,6 +53,7 @@ zlib.o: $(hdrdir)/ruby/internal/attr/noexcept.h zlib.o: $(hdrdir)/ruby/internal/attr/noinline.h zlib.o: $(hdrdir)/ruby/internal/attr/nonnull.h zlib.o: $(hdrdir)/ruby/internal/attr/noreturn.h +zlib.o: $(hdrdir)/ruby/internal/attr/packed_struct.h zlib.o: $(hdrdir)/ruby/internal/attr/pure.h zlib.o: $(hdrdir)/ruby/internal/attr/restrict.h zlib.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h @@ -71,6 +86,15 @@ zlib.o: $(hdrdir)/ruby/internal/core/rtypeddata.h zlib.o: $(hdrdir)/ruby/internal/ctype.h zlib.o: $(hdrdir)/ruby/internal/dllexport.h zlib.o: $(hdrdir)/ruby/internal/dosish.h +zlib.o: $(hdrdir)/ruby/internal/encoding/coderange.h +zlib.o: $(hdrdir)/ruby/internal/encoding/ctype.h +zlib.o: $(hdrdir)/ruby/internal/encoding/encoding.h +zlib.o: $(hdrdir)/ruby/internal/encoding/pathname.h +zlib.o: $(hdrdir)/ruby/internal/encoding/re.h +zlib.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +zlib.o: $(hdrdir)/ruby/internal/encoding/string.h +zlib.o: $(hdrdir)/ruby/internal/encoding/symbol.h +zlib.o: $(hdrdir)/ruby/internal/encoding/transcode.h zlib.o: $(hdrdir)/ruby/internal/error.h zlib.o: $(hdrdir)/ruby/internal/eval.h zlib.o: $(hdrdir)/ruby/internal/event.h @@ -98,7 +122,6 @@ zlib.o: $(hdrdir)/ruby/internal/intern/enumerator.h zlib.o: $(hdrdir)/ruby/internal/intern/error.h zlib.o: $(hdrdir)/ruby/internal/intern/eval.h zlib.o: $(hdrdir)/ruby/internal/intern/file.h -zlib.o: $(hdrdir)/ruby/internal/intern/gc.h zlib.o: $(hdrdir)/ruby/internal/intern/hash.h zlib.o: $(hdrdir)/ruby/internal/intern/io.h zlib.o: $(hdrdir)/ruby/internal/intern/load.h @@ -115,6 +138,7 @@ zlib.o: $(hdrdir)/ruby/internal/intern/re.h zlib.o: $(hdrdir)/ruby/internal/intern/ruby.h zlib.o: $(hdrdir)/ruby/internal/intern/select.h zlib.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +zlib.o: $(hdrdir)/ruby/internal/intern/set.h zlib.o: $(hdrdir)/ruby/internal/intern/signal.h zlib.o: $(hdrdir)/ruby/internal/intern/sprintf.h zlib.o: $(hdrdir)/ruby/internal/intern/string.h @@ -129,33 +153,18 @@ zlib.o: $(hdrdir)/ruby/internal/memory.h zlib.o: $(hdrdir)/ruby/internal/method.h zlib.o: $(hdrdir)/ruby/internal/module.h zlib.o: $(hdrdir)/ruby/internal/newobj.h -zlib.o: $(hdrdir)/ruby/internal/rgengc.h zlib.o: $(hdrdir)/ruby/internal/scan_args.h zlib.o: $(hdrdir)/ruby/internal/special_consts.h zlib.o: $(hdrdir)/ruby/internal/static_assert.h zlib.o: $(hdrdir)/ruby/internal/stdalign.h zlib.o: $(hdrdir)/ruby/internal/stdbool.h +zlib.o: $(hdrdir)/ruby/internal/stdckdint.h zlib.o: $(hdrdir)/ruby/internal/symbol.h -zlib.o: $(hdrdir)/ruby/internal/token_paste.h zlib.o: $(hdrdir)/ruby/internal/value.h zlib.o: $(hdrdir)/ruby/internal/value_type.h zlib.o: $(hdrdir)/ruby/internal/variable.h zlib.o: $(hdrdir)/ruby/internal/warning_push.h zlib.o: $(hdrdir)/ruby/internal/xmalloc.h -zlib.o: $(hdrdir)/ruby/assert.h -zlib.o: $(hdrdir)/ruby/backward.h -zlib.o: $(hdrdir)/ruby/backward/2/assume.h -zlib.o: $(hdrdir)/ruby/backward/2/attributes.h -zlib.o: $(hdrdir)/ruby/backward/2/bool.h -zlib.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h -zlib.o: $(hdrdir)/ruby/backward/2/inttypes.h -zlib.o: $(hdrdir)/ruby/backward/2/limits.h -zlib.o: $(hdrdir)/ruby/backward/2/long_long.h -zlib.o: $(hdrdir)/ruby/backward/2/stdalign.h -zlib.o: $(hdrdir)/ruby/backward/2/stdarg.h -zlib.o: $(hdrdir)/ruby/defines.h -zlib.o: $(hdrdir)/ruby/encoding.h -zlib.o: $(hdrdir)/ruby/intern.h zlib.o: $(hdrdir)/ruby/io.h zlib.o: $(hdrdir)/ruby/missing.h zlib.o: $(hdrdir)/ruby/onigmo.h diff --git a/ext/zlib/extconf.rb b/ext/zlib/extconf.rb index 76cd34582e..2b2dbb1a5b 100644 --- a/ext/zlib/extconf.rb +++ b/ext/zlib/extconf.rb @@ -10,11 +10,11 @@ require 'rbconfig' dir_config 'zlib' +libs = $libs +have_zlib = %w'z libz zlib1 zlib zdll zlibwapi'.any? {|z| have_library(z, 'deflateReset(NULL)', 'zlib.h')} -if %w'z libz zlib1 zlib zdll zlibwapi'.find {|z| have_library(z, 'deflateReset')} and - have_header('zlib.h') then - have_zlib = true -else +unless have_zlib + $libs = libs unless File.directory?(zsrc = "#{$srcdir}/zlib") dirs = Dir.open($srcdir) {|z| z.grep(/\Azlib-\d+[.\d]*\z/) {|x|"#{$srcdir}/#{x}"}} dirs.delete_if {|x| !File.directory?(x)} @@ -46,7 +46,7 @@ else end m = File.read(m) zimplib = m[/^IMPLIB[ \t]*=[ \t]*(\S+)/, 1] - $LOCAL_LIBS << " " << zimplib + ($LOCAL_LIBS << " ./" << zimplib).strip! unless $nmake or /^TOP[ \t]/ =~ m m.gsub!(/win32\/zlib\.def/, '$(TOP)/\&') m.gsub!(/^(\t.*[ \t])(\S+\.rc)/, '\1-I$(<D) $<') @@ -62,7 +62,7 @@ else "$(TARGET_SO): $(ZIMPLIB)\n", "$(ZIMPLIB):\n", "#{zmk} $(ZOPTS) $@\n", - "install-so: $(topdir)/#{dll}", + "install-so static: $(topdir)/#{dll}", "$(topdir)/#{dll}: $(ZIMPLIB)\n", "\t$(Q) $(COPY) #{dll} $(@D)\n", "clean: clean-zsrc\n", @@ -120,10 +120,18 @@ if have_zlib $defs << "-DHAVE_CRC32_COMBINE" $defs << "-DHAVE_ADLER32_COMBINE" $defs << "-DHAVE_TYPE_Z_CRC_T" + $defs << "-DHAVE_CRC32_Z" + $defs << "-DHAVE_ADLER32_Z" + $defs << "-DHAVE_ZLIB_SIZE_T_FUNCS" else have_func('crc32_combine', 'zlib.h') have_func('adler32_combine', 'zlib.h') have_type('z_crc_t', 'zlib.h') + if (have_type('z_size_t', 'zlib.h') && + have_func('crc32_z', 'zlib.h') && + have_func('adler32_z', 'zlib.h')) + $defs << "-DHAVE_ZLIB_SIZE_T_FUNCS" + end end create_makefile('zlib') {|conf| diff --git a/ext/zlib/extlibs b/ext/zlib/extlibs deleted file mode 100644 index a64b37ba5f..0000000000 --- a/ext/zlib/extlibs +++ /dev/null @@ -1,8 +0,0 @@ -ver = 1.2.11 -pkg = zlib-$(ver) - -https://zlib.net/$(pkg).tar.gz \ - md5:1c9f62f0778697a09d36121ead88e08e \ - sha512:73fd3fff4adeccd4894084c15ddac89890cd10ef105dd5e1835e1e9bbb6a49ff229713bd197d203edfa17c2727700fce65a2a235f07568212d820dca88b528ae \ - # - win32/$(pkg)-mswin.patch -p0 diff --git a/ext/zlib/win32/zlib-1.2.11-mswin.patch b/ext/zlib/win32/zlib-1.2.11-mswin.patch deleted file mode 100644 index 8810b4403c..0000000000 --- a/ext/zlib/win32/zlib-1.2.11-mswin.patch +++ /dev/null @@ -1,95 +0,0 @@ -diff -ru zlib-1.2.11/gzread.c zlib-1.2.11/gzread.c ---- zlib-1.2.11/gzread.c 2016-12-31 23:37:10.000000000 +0900 -+++ zlib-1.2.11/gzread.c 2020-11-23 19:35:00.550987184 +0900 -@@ -316,7 +316,7 @@ - /* set n to the maximum amount of len that fits in an unsigned int */ - n = -1; - if (n > len) -- n = len; -+ n = (unsigned)len; - - /* first just try copying data from the output buffer */ - if (state->x.have) { -@@ -397,7 +397,7 @@ - } - - /* read len or fewer bytes to buf */ -- len = gz_read(state, buf, len); -+ len = (unsigned)gz_read(state, buf, len); - - /* check for an error */ - if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR) -@@ -469,7 +469,7 @@ - } - - /* nothing there -- try gz_read() */ -- ret = gz_read(state, buf, 1); -+ ret = (int)gz_read(state, buf, 1); - return ret < 1 ? -1 : buf[0]; - } - -diff -ru zlib-1.2.11/gzwrite.c zlib-1.2.11/gzwrite.c ---- zlib-1.2.11/gzwrite.c 2017-01-15 09:29:40.000000000 +0900 -+++ zlib-1.2.11/gzwrite.c 2020-11-23 19:35:41.530494030 +0900 -@@ -209,7 +209,7 @@ - state->in); - copy = state->size - have; - if (copy > len) -- copy = len; -+ copy = (unsigned)len; - memcpy(state->in + have, buf, copy); - state->strm.avail_in += copy; - state->x.pos += copy; -@@ -229,7 +229,7 @@ - do { - unsigned n = (unsigned)-1; - if (n > len) -- n = len; -+ n = (unsigned)len; - state->strm.avail_in = n; - state->x.pos += n; - if (gz_comp(state, Z_NO_FLUSH) == -1) -@@ -368,7 +368,7 @@ - - /* write string */ - len = strlen(str); -- ret = gz_write(state, str, len); -+ ret = (int)gz_write(state, str, len); - return ret == 0 && len != 0 ? -1 : ret; - } - -diff -ru zlib-1.2.11/win32/Makefile.msc zlib-1.2.11/win32/Makefile.msc ---- zlib-1.2.11/win32/Makefile.msc 2017-01-15 09:07:08.000000000 +0900 -+++ zlib-1.2.11/win32/Makefile.msc 2020-11-23 22:37:19.746500208 +0900 -@@ -37,6 +37,22 @@ - gzwrite.obj infback.obj inflate.obj inftrees.obj inffast.obj trees.obj uncompr.obj zutil.obj - OBJA = - -+!ifdef USE_ASM -+LOC = -DASMV -DASMINF -+!if "$(ARCH)" == "i386" -+OBJA = inffas32.obj match686.obj -+!else if "$(ARCH)" == "x64" -+AS = ml64 -+LOC = $(LOC) -I. -+OBJA = inffasx64.obj gvmat64.obj inffas8664.obj -+!endif -+!endif -+ -+!if "$(ARCH)" == "x64" -+ZBASE = 0x5A4C000000 -+!else -+ZBASE = 0x5A4C0000 -+!endif - - # targets - all: $(STATICLIB) $(SHAREDLIB) $(IMPLIB) \ -@@ -49,7 +65,7 @@ - - $(SHAREDLIB): $(TOP)/win32/zlib.def $(OBJS) $(OBJA) zlib1.res - $(LD) $(LDFLAGS) -def:$(TOP)/win32/zlib.def -dll -implib:$(IMPLIB) \ -- -out:$@ -base:0x5A4C0000 $(OBJS) $(OBJA) zlib1.res -+ -out:$@ -base:$(ZBASE) $(OBJS) $(OBJA) zlib1.res - if exist $@.manifest \ - mt -nologo -manifest $@.manifest -outputresource:$@;2 - diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index 90fa5a61ef..481d74b2b6 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -25,7 +25,7 @@ # define VALGRIND_MAKE_MEM_UNDEFINED(p, n) 0 #endif -#define RUBY_ZLIB_VERSION "1.1.0" +#define RUBY_ZLIB_VERSION "3.2.3" #ifndef RB_PASS_CALLED_KEYWORDS # define rb_class_new_instance_kw(argc, argv, klass, kw_splat) rb_class_new_instance(argc, argv, klass) @@ -44,6 +44,14 @@ #endif #endif +#if defined(HAVE_ZLIB_SIZE_T_FUNCS) +typedef uLong (*checksum_func)(uLong, const Bytef*, z_size_t); +# define crc32 crc32_z +# define adler32 adler32_z +#else +typedef uLong (*checksum_func)(uLong, const Bytef*, uInt); +#endif + #if SIZEOF_LONG > SIZEOF_INT static inline uInt max_uint(long n) @@ -65,7 +73,7 @@ static ID id_dictionaries, id_read, id_buffer; static NORETURN(void raise_zlib_error(int, const char*)); static VALUE rb_zlib_version(VALUE); -static VALUE do_checksum(int, VALUE*, uLong (*)(uLong, const Bytef*, uInt)); +static VALUE do_checksum(int, VALUE*, checksum_func); static VALUE rb_zlib_adler32(int, VALUE*, VALUE); static VALUE rb_zlib_crc32(int, VALUE*, VALUE); static VALUE rb_zlib_crc_table(VALUE); @@ -82,7 +90,7 @@ static void zstream_expand_buffer_into(struct zstream*, unsigned long); static int zstream_expand_buffer_non_stream(struct zstream *z); static void zstream_append_buffer(struct zstream*, const Bytef*, long); static VALUE zstream_detach_buffer(struct zstream*); -static VALUE zstream_shift_buffer(struct zstream*, long); +static VALUE zstream_shift_buffer(struct zstream*, long, VALUE); static void zstream_buffer_ungets(struct zstream*, const Bytef*, unsigned long); static void zstream_buffer_ungetbyte(struct zstream*, int); static void zstream_append_input(struct zstream*, const Bytef*, long); @@ -162,8 +170,8 @@ static void gzfile_check_footer(struct gzfile*, VALUE outbuf); static void gzfile_write(struct gzfile*, Bytef*, long); static long gzfile_read_more(struct gzfile*, VALUE outbuf); static void gzfile_calc_crc(struct gzfile*, VALUE); -static VALUE gzfile_read(struct gzfile*, long); -static VALUE gzfile_read_all(struct gzfile*); +static VALUE gzfile_read(struct gzfile*, long, VALUE); +static VALUE gzfile_read_all(struct gzfile*, VALUE); static void gzfile_ungets(struct gzfile*, const Bytef*, long); static void gzfile_ungetbyte(struct gzfile*, int); static VALUE gzfile_writer_end_run(VALUE); @@ -288,6 +296,7 @@ static VALUE rb_gzreader_readlines(int, VALUE*, VALUE); * - Zlib::MemError * - Zlib::BufError * - Zlib::VersionError + * - Zlib::InProgressError * * (if you have GZIP_SUPPORT) * - Zlib::GzipReader @@ -304,7 +313,7 @@ void Init_zlib(void); /*--------- Exceptions --------*/ static VALUE cZError, cStreamEnd, cNeedDict; -static VALUE cStreamError, cDataError, cMemError, cBufError, cVersionError; +static VALUE cStreamError, cDataError, cMemError, cBufError, cVersionError, cInProgressError; static void raise_zlib_error(int err, const char *msg) @@ -354,7 +363,9 @@ raise_zlib_error(int err, const char *msg) static void finalizer_warn(const char *msg) { +#if 0 fprintf(stderr, "zlib(finalizer): %s\n", msg); +#endif } @@ -371,26 +382,32 @@ rb_zlib_version(VALUE klass) return rb_str_new2(zlibVersion()); } -#if SIZEOF_LONG > SIZEOF_INT +#if SIZEOF_LONG * CHAR_BIT > 32 +# define mask32(x) ((x) & 0xffffffff) +#else +# define mask32(x) (x) +#endif + +#if SIZEOF_LONG > SIZEOF_INT && !defined(HAVE_ZLIB_SIZE_T_FUNCS) static uLong checksum_long(uLong (*func)(uLong, const Bytef*, uInt), uLong sum, const Bytef *ptr, long len) { if (len > UINT_MAX) { do { - sum = func(sum, ptr, UINT_MAX); + sum = func(mask32(sum), ptr, UINT_MAX); ptr += UINT_MAX; len -= UINT_MAX; } while (len >= UINT_MAX); } - if (len > 0) sum = func(sum, ptr, (uInt)len); + if (len > 0) sum = func(mask32(sum), ptr, (uInt)len); return sum; } #else -#define checksum_long(func, sum, ptr, len) (func)((sum), (ptr), (len)) +#define checksum_long(func, sum, ptr, len) (func)(mask32(sum), (ptr), (len)) #endif static VALUE -do_checksum(int argc, VALUE *argv, uLong (*func)(uLong, const Bytef*, uInt)) +do_checksum(int argc, VALUE *argv, checksum_func func) { VALUE str, vsum; unsigned long sum; @@ -408,7 +425,7 @@ do_checksum(int argc, VALUE *argv, uLong (*func)(uLong, const Bytef*, uInt)) } if (NIL_P(str)) { - sum = func(sum, Z_NULL, 0); + sum = func(mask32(sum), Z_NULL, 0); } else if (rb_obj_is_kind_of(str, rb_cIO)) { VALUE buf; @@ -458,7 +475,7 @@ rb_zlib_adler32(int argc, VALUE *argv, VALUE klass) * * call-seq: Zlib.adler32_combine(adler1, adler2, len2) * - * Combine two Adler-32 check values in to one. +alder1+ is the first Adler-32 + * Combine two Adler-32 check values in to one. +adler1+ is the first Adler-32 * value, +adler2+ is the second Adler-32 value. +len2+ is the length of the * string used to generate +adler2+. * @@ -546,6 +563,7 @@ struct zstream { unsigned long flags; VALUE buf; VALUE input; + VALUE mutex; z_stream stream; const struct zstream_funcs { int (*reset)(z_streamp); @@ -554,14 +572,15 @@ struct zstream { } *func; }; -#define ZSTREAM_FLAG_READY 0x1 -#define ZSTREAM_FLAG_IN_STREAM 0x2 -#define ZSTREAM_FLAG_FINISHED 0x4 -#define ZSTREAM_FLAG_CLOSING 0x8 -#define ZSTREAM_FLAG_GZFILE 0x10 /* disallows yield from expand_buffer for +#define ZSTREAM_FLAG_READY (1 << 0) +#define ZSTREAM_FLAG_IN_STREAM (1 << 1) +#define ZSTREAM_FLAG_FINISHED (1 << 2) +#define ZSTREAM_FLAG_CLOSING (1 << 3) +#define ZSTREAM_FLAG_GZFILE (1 << 4) /* disallows yield from expand_buffer for gzip*/ -#define ZSTREAM_REUSE_BUFFER 0x20 -#define ZSTREAM_FLAG_UNUSED 0x40 +#define ZSTREAM_REUSE_BUFFER (1 << 5) +#define ZSTREAM_IN_PROGRESS (1 << 6) +#define ZSTREAM_FLAG_UNUSED (1 << 7) #define ZSTREAM_READY(z) ((z)->flags |= ZSTREAM_FLAG_READY) #define ZSTREAM_IS_READY(z) ((z)->flags & ZSTREAM_FLAG_READY) @@ -590,7 +609,9 @@ static const struct zstream_funcs inflate_funcs = { }; struct zstream_run_args { - struct zstream * z; + struct zstream *const z; + Bytef *src; + long len; int flush; /* stream flush value for inflate() or deflate() */ int interrupt; /* stop processing the stream and return to ruby */ int jump_state; /* for buffer expansion block break or exception */ @@ -621,6 +642,7 @@ zstream_init(struct zstream *z, const struct zstream_funcs *func) z->flags = 0; z->buf = Qnil; z->input = Qnil; + z->mutex = rb_mutex_new(); z->stream.zalloc = zlib_mem_alloc; z->stream.zfree = zlib_mem_free; z->stream.opaque = Z_NULL; @@ -652,7 +674,7 @@ zstream_expand_buffer(struct zstream *z) rb_obj_reveal(z->buf, rb_cString); } - rb_protect(rb_yield, z->buf, &state); + rb_protect(rb_yield, z->buf, &state); if (ZSTREAM_REUSE_BUFFER_P(z)) { rb_str_modify(z->buf); @@ -696,15 +718,14 @@ zstream_expand_buffer_into(struct zstream *z, unsigned long size) } } -static void * -zstream_expand_buffer_protect(void *ptr) +static int +zstream_expand_buffer_protect(struct zstream *z) { - struct zstream *z = (struct zstream *)ptr; int state = 0; rb_protect((VALUE (*)(VALUE))zstream_expand_buffer, (VALUE)z, &state); - return (void *)(VALUE)state; + return state; } static int @@ -796,19 +817,31 @@ zstream_detach_buffer(struct zstream *z) } static VALUE -zstream_shift_buffer(struct zstream *z, long len) +zstream_shift_buffer(struct zstream *z, long len, VALUE dst) { - VALUE dst; char *bufptr; long buflen = ZSTREAM_BUF_FILLED(z); if (buflen <= len) { - return zstream_detach_buffer(z); + if (NIL_P(dst) || (!ZSTREAM_IS_FINISHED(z) && !ZSTREAM_IS_GZFILE(z) && + rb_block_given_p())) { + return zstream_detach_buffer(z); + } else { + bufptr = RSTRING_PTR(z->buf); + rb_str_resize(dst, buflen); + memcpy(RSTRING_PTR(dst), bufptr, buflen); + } + buflen = 0; + } else { + bufptr = RSTRING_PTR(z->buf); + if (NIL_P(dst)) { + dst = rb_str_new(bufptr, len); + } else { + rb_str_resize(dst, len); + memcpy(RSTRING_PTR(dst), bufptr, len); + } + buflen -= len; } - - bufptr = RSTRING_PTR(z->buf); - dst = rb_str_new(bufptr, len); - buflen -= len; memmove(bufptr, bufptr + len, buflen); rb_str_set_len(z->buf, buflen); z->stream.next_out = (Bytef*)RSTRING_END(z->buf); @@ -827,9 +860,7 @@ zstream_buffer_ungets(struct zstream *z, const Bytef *b, unsigned long len) char *bufptr; long filled; - if (NIL_P(z->buf) || (long)rb_str_capacity(z->buf) <= ZSTREAM_BUF_FILLED(z)) { - zstream_expand_buffer_into(z, len); - } + zstream_expand_buffer_into(z, len); RSTRING_GETMEM(z->buf, bufptr, filled); memmove(bufptr + len, bufptr, filled); @@ -888,7 +919,6 @@ zstream_discard_input(struct zstream *z, long len) } rb_str_resize(z->input, newlen); if (newlen == 0) { - rb_gc_force_recycle(z->input); z->input = Qnil; } else { @@ -900,7 +930,7 @@ zstream_discard_input(struct zstream *z, long len) z->input = Qnil; } else { - z->input = rb_str_substr(z->input, len, + z->input = rb_str_subseq(z->input, len, RSTRING_LEN(z->input) - len); } } @@ -988,57 +1018,14 @@ zstream_ensure_end(VALUE v) } static void * -zstream_run_func(void *ptr) +zstream_run_once(void *_arguments) { - struct zstream_run_args *args = (struct zstream_run_args *)ptr; - int err, state, flush = args->flush; - struct zstream *z = args->z; - uInt n; - - err = Z_OK; - while (!args->interrupt) { - n = z->stream.avail_out; - err = z->func->run(&z->stream, flush); - rb_str_set_len(z->buf, ZSTREAM_BUF_FILLED(z) + (n - z->stream.avail_out)); + struct zstream_run_args *arguments = (struct zstream_run_args *)_arguments; + struct zstream *z = arguments->z; - if (err == Z_STREAM_END) { - z->flags &= ~ZSTREAM_FLAG_IN_STREAM; - z->flags |= ZSTREAM_FLAG_FINISHED; - break; - } - - if (err != Z_OK && err != Z_BUF_ERROR) - break; + uintptr_t error = z->func->run(&z->stream, arguments->flush); - if (z->stream.avail_out > 0) { - z->flags |= ZSTREAM_FLAG_IN_STREAM; - break; - } - - if (z->stream.avail_in == 0 && z->func == &inflate_funcs) { - /* break here because inflate() return Z_BUF_ERROR when avail_in == 0. */ - /* but deflate() could be called with avail_in == 0 (there's hidden buffer - in zstream->state) */ - z->flags |= ZSTREAM_FLAG_IN_STREAM; - break; - } - - if (args->stream_output) { - state = (int)(VALUE)rb_thread_call_with_gvl(zstream_expand_buffer_protect, - (void *)z); - } - else { - state = zstream_expand_buffer_non_stream(z); - } - - if (state) { - err = Z_OK; /* buffer expanded but stream processing was stopped */ - args->jump_state = state; - break; - } - } - - return (void *)(VALUE)err; + return (void*)error; } /* @@ -1053,18 +1040,109 @@ zstream_unblock_func(void *ptr) args->interrupt = 1; } -static void -zstream_run(struct zstream *z, Bytef *src, long len, int flush) +#ifndef RB_NOGVL_OFFLOAD_SAFE +// Default to no-op if it's not defined: +#define RB_NOGVL_OFFLOAD_SAFE 0 +#endif + +static VALUE +zstream_run_once_begin(VALUE _arguments) +{ + struct zstream_run_args *arguments = (struct zstream_run_args *)_arguments; + struct zstream *z = arguments->z; + + rb_str_locktmp(z->buf); + +#ifndef RB_NOGVL_UBF_ASYNC_SAFE + return (VALUE)rb_thread_call_without_gvl(zstream_run_once, (void *)arguments, zstream_unblock_func, (void *)arguments); +#else + return (VALUE)rb_nogvl(zstream_run_once, (void *)arguments, zstream_unblock_func, (void *)arguments, RB_NOGVL_UBF_ASYNC_SAFE | RB_NOGVL_OFFLOAD_SAFE); +#endif +} + +static VALUE +zstream_run_once_ensure(VALUE _arguments) { - struct zstream_run_args args; + struct zstream_run_args *arguments = (struct zstream_run_args *)_arguments; + struct zstream *z = arguments->z; + + rb_str_unlocktmp(z->buf); + + return Qnil; +} + +static int +zstream_run_func(struct zstream_run_args *args) +{ + struct zstream *z = args->z; + int state; + uInt n; + + int err = Z_OK; + while (!args->interrupt) { + n = z->stream.avail_out; + + err = (int)(VALUE)rb_ensure(zstream_run_once_begin, (VALUE)args, zstream_run_once_ensure, (VALUE)args); + + rb_str_set_len(z->buf, ZSTREAM_BUF_FILLED(z) + (n - z->stream.avail_out)); + + if (err == Z_STREAM_END) { + z->flags &= ~ZSTREAM_FLAG_IN_STREAM; + z->flags |= ZSTREAM_FLAG_FINISHED; + break; + } + + if (err != Z_OK && err != Z_BUF_ERROR) { + break; + } + + if (z->stream.avail_out > 0) { + z->flags |= ZSTREAM_FLAG_IN_STREAM; + break; + } + + if (z->stream.avail_in == 0 && z->func == &inflate_funcs) { + /* break here because inflate() return Z_BUF_ERROR when avail_in == 0. */ + /* but deflate() could be called with avail_in == 0 (there's hidden buffer + in zstream->state) */ + z->flags |= ZSTREAM_FLAG_IN_STREAM; + break; + } + + if (args->stream_output) { + state = zstream_expand_buffer_protect(z); + } + else { + state = zstream_expand_buffer_non_stream(z); + } + + if (state) { + err = Z_OK; /* buffer expanded but stream processing was stopped */ + args->jump_state = state; + break; + } + } + + return err; +} + +static VALUE +zstream_run_try(VALUE value_arg) +{ + struct zstream_run_args *args = (struct zstream_run_args *)value_arg; + struct zstream *z = args->z; + Bytef *src = args->src; + long len = args->len; + int flush = args->flush; + int err; VALUE old_input = Qnil; - args.z = z; - args.flush = flush; - args.interrupt = 0; - args.jump_state = 0; - args.stream_output = !ZSTREAM_IS_GZFILE(z) && rb_block_given_p(); + /* Cannot start zstream while it is in progress. */ + if (z->flags & ZSTREAM_IN_PROGRESS) { + rb_raise(cInProgressError, "zlib stream is in progress"); + } + z->flags |= ZSTREAM_IN_PROGRESS; if (NIL_P(z->input) && len == 0) { z->stream.next_in = (Bytef*)""; @@ -1086,18 +1164,22 @@ zstream_run(struct zstream *z, Bytef *src, long len, int flush) } loop: -#ifndef RB_NOGVL_UBF_ASYNC_SAFE - err = (int)(VALUE)rb_thread_call_without_gvl(zstream_run_func, (void *)&args, - zstream_unblock_func, (void *)&args); -#else - err = (int)(VALUE)rb_nogvl(zstream_run_func, (void *)&args, - zstream_unblock_func, (void *)&args, - RB_NOGVL_UBF_ASYNC_SAFE); -#endif + err = zstream_run_func(args); - if (flush != Z_FINISH && err == Z_BUF_ERROR - && z->stream.avail_out > 0) { - z->flags |= ZSTREAM_FLAG_IN_STREAM; + /* retry if no exception is thrown */ + if (err == Z_OK && args->interrupt) { + args->interrupt = 0; + + /* Retry only if both avail_in > 0 (more input to process) and avail_out > 0 + * (output buffer has space). If avail_out == 0, the buffer is full and should + * be consumed by the caller first. If avail_in == 0, there's nothing more to process. */ + if (z->stream.avail_in > 0 && z->stream.avail_out > 0) { + goto loop; + } + } + + if (flush != Z_FINISH && err == Z_BUF_ERROR && z->stream.avail_out > 0) { + z->flags |= ZSTREAM_FLAG_IN_STREAM; } zstream_reset_input(z); @@ -1125,9 +1207,37 @@ loop: } if (!NIL_P(old_input)) { rb_str_resize(old_input, 0); - rb_gc_force_recycle(old_input); } + return Qnil; +} + +static VALUE +zstream_run_ensure(VALUE value_arg) +{ + struct zstream_run_args *args = (struct zstream_run_args *)value_arg; + struct zstream *z = args->z; + + /* Remove ZSTREAM_IN_PROGRESS flag to signal that this zstream is not in use. */ + z->flags &= ~ZSTREAM_IN_PROGRESS; + + return Qnil; +} + +static void +zstream_run(struct zstream *z, Bytef *src, long len, int flush) +{ + struct zstream_run_args args = { + .z = z, + .src = src, + .len = len, + .flush = flush, + .interrupt = 0, + .jump_state = 0, + .stream_output = !ZSTREAM_IS_GZFILE(z) && rb_block_given_p(), + }; + + rb_ensure(zstream_run_try, (VALUE)&args, zstream_run_ensure, (VALUE)&args); if (args.jump_state) rb_jump_tag(args.jump_state); } @@ -1177,6 +1287,7 @@ zstream_mark(void *p) struct zstream *z = p; rb_gc_mark(z->buf); rb_gc_mark(z->input); + rb_gc_mark(z->mutex); } static void @@ -1349,6 +1460,7 @@ rb_zstream_finish(VALUE obj) * call-seq: * flush_next_in -> input * + * Flushes input buffer and returns all data in that buffer. */ static VALUE rb_zstream_flush_next_in(VALUE obj) @@ -1437,7 +1549,7 @@ rb_zstream_total_out(VALUE obj) } /* - * Guesses the type of the data which have been inputed into the stream. The + * Guesses the type of the data which have been inputted into the stream. The * returned value is either <tt>BINARY</tt>, <tt>ASCII</tt>, or * <tt>UNKNOWN</tt>. */ @@ -1694,6 +1806,22 @@ do_deflate(struct zstream *z, VALUE src, int flush) } } +struct rb_zlib_deflate_arguments { + struct zstream *z; + VALUE src; + int flush; +}; + +static VALUE +rb_deflate_deflate_body(VALUE args) +{ + struct rb_zlib_deflate_arguments *arguments = (struct rb_zlib_deflate_arguments *)args; + + do_deflate(arguments->z, arguments->src, arguments->flush); + + return zstream_detach_buffer(arguments->z); +} + /* * Document-method: Zlib::Deflate#deflate * @@ -1725,11 +1853,10 @@ rb_deflate_deflate(int argc, VALUE *argv, VALUE obj) { struct zstream *z = get_zstream(obj); VALUE src, flush; - rb_scan_args(argc, argv, "11", &src, &flush); - do_deflate(z, src, ARG_FLUSH(flush)); + struct rb_zlib_deflate_arguments arguments = {z, src, ARG_FLUSH(flush)}; - return zstream_detach_buffer(z); + return rb_mutex_synchronize(z->mutex, rb_deflate_deflate_body, (VALUE)&arguments); } /* @@ -2025,56 +2152,19 @@ rb_inflate_add_dictionary(VALUE obj, VALUE dictionary) return obj; } -/* - * Document-method: Zlib::Inflate#inflate - * - * call-seq: - * inflate(deflate_string, buffer: nil) -> String - * inflate(deflate_string, buffer: nil) { |chunk| ... } -> nil - * - * Inputs +deflate_string+ into the inflate stream and returns the output from - * the stream. Calling this method, both the input and the output buffer of - * the stream are flushed. If string is +nil+, this method finishes the - * stream, just like Zlib::ZStream#finish. - * - * If a block is given consecutive inflated chunks from the +deflate_string+ - * are yielded to the block and +nil+ is returned. - * - * If a :buffer keyword argument is given and not nil: - * - * * The :buffer keyword should be a String, and will used as the output buffer. - * Using this option can reuse the memory required during inflation. - * * When not passing a block, the return value will be the same object as the - * :buffer keyword argument. - * * When passing a block, the yielded chunks will be the same value as the - * :buffer keyword argument. - * - * Raises a Zlib::NeedDict exception if a preset dictionary is needed to - * decompress. Set the dictionary by Zlib::Inflate#set_dictionary and then - * call this method again with an empty string to flush the stream: - * - * inflater = Zlib::Inflate.new - * - * begin - * out = inflater.inflate compressed - * rescue Zlib::NeedDict - * # ensure the dictionary matches the stream's required dictionary - * raise unless inflater.adler == Zlib.adler32(dictionary) - * - * inflater.set_dictionary dictionary - * inflater.inflate '' - * end - * - * # ... - * - * inflater.close - * - * See also Zlib::Inflate.new - */ +struct rb_zlib_inflate_arguments { + struct zstream *z; + int argc; + VALUE *argv; +}; + static VALUE -rb_inflate_inflate(int argc, VALUE* argv, VALUE obj) +rb_inflate_inflate_body(VALUE _arguments) { - struct zstream *z = get_zstream(obj); + struct rb_zlib_inflate_arguments *arguments = (struct rb_zlib_inflate_arguments*)_arguments; + struct zstream *z = arguments->z; + int argc = arguments->argc; + VALUE *argv = arguments->argv; VALUE dst, src, opts, buffer = Qnil; if (OPTHASH_GIVEN_P(opts)) { @@ -2130,6 +2220,60 @@ rb_inflate_inflate(int argc, VALUE* argv, VALUE obj) } /* + * Document-method: Zlib::Inflate#inflate + * + * call-seq: + * inflate(deflate_string, buffer: nil) -> String + * inflate(deflate_string, buffer: nil) { |chunk| ... } -> nil + * + * Inputs +deflate_string+ into the inflate stream and returns the output from + * the stream. Calling this method, both the input and the output buffer of + * the stream are flushed. If string is +nil+, this method finishes the + * stream, just like Zlib::ZStream#finish. + * + * If a block is given consecutive inflated chunks from the +deflate_string+ + * are yielded to the block and +nil+ is returned. + * + * If a :buffer keyword argument is given and not nil: + * + * * The :buffer keyword should be a String, and will used as the output buffer. + * Using this option can reuse the memory required during inflation. + * * When not passing a block, the return value will be the same object as the + * :buffer keyword argument. + * * When passing a block, the yielded chunks will be the same value as the + * :buffer keyword argument. + * + * Raises a Zlib::NeedDict exception if a preset dictionary is needed to + * decompress. Set the dictionary by Zlib::Inflate#set_dictionary and then + * call this method again with an empty string to flush the stream: + * + * inflater = Zlib::Inflate.new + * + * begin + * out = inflater.inflate compressed + * rescue Zlib::NeedDict + * # ensure the dictionary matches the stream's required dictionary + * raise unless inflater.adler == Zlib.adler32(dictionary) + * + * inflater.set_dictionary dictionary + * inflater.inflate '' + * end + * + * # ... + * + * inflater.close + * + * See also Zlib::Inflate.new + */ +static VALUE +rb_inflate_inflate(int argc, VALUE* argv, VALUE obj) +{ + struct zstream *z = get_zstream(obj); + struct rb_zlib_inflate_arguments arguments = {z, argc, argv}; + return rb_mutex_synchronize(z->mutex, rb_inflate_inflate_body, (VALUE)&arguments); +} + +/* * call-seq: << string * * Inputs +string+ into the inflate stream just like Zlib::Inflate#inflate, but @@ -2305,17 +2449,16 @@ struct gzfile { #define GZFILE_READ_SIZE 2048 +enum { read_raw_arg_len, read_raw_arg_buf, read_raw_arg__count}; struct read_raw_arg { VALUE io; - union { - const VALUE argv[2]; /* for rb_funcallv */ - struct { - VALUE len; - VALUE buf; - } in; - } as; + const VALUE argv[read_raw_arg__count]; /* for rb_funcallv */ }; +#define read_raw_arg_argc(ra) \ + ((int)read_raw_arg__count - NIL_P((ra)->argv[read_raw_arg__count - 1])) +#define read_raw_arg_init(io, len, buf) { io, { len, buf } } + static void gzfile_mark(void *p) { @@ -2441,9 +2584,9 @@ gzfile_read_raw_partial(VALUE arg) { struct read_raw_arg *ra = (struct read_raw_arg *)arg; VALUE str; - int argc = NIL_P(ra->as.argv[1]) ? 1 : 2; + int argc = read_raw_arg_argc(ra); - str = rb_funcallv(ra->io, id_readpartial, argc, ra->as.argv); + str = rb_funcallv(ra->io, id_readpartial, argc, ra->argv); Check_Type(str, T_STRING); return str; } @@ -2454,8 +2597,8 @@ gzfile_read_raw_rescue(VALUE arg, VALUE _) struct read_raw_arg *ra = (struct read_raw_arg *)arg; VALUE str = Qnil; if (rb_obj_is_kind_of(rb_errinfo(), rb_eNoMethodError)) { - int argc = NIL_P(ra->as.argv[1]) ? 1 : 2; - str = rb_funcallv(ra->io, id_read, argc, ra->as.argv); + int argc = read_raw_arg_argc(ra); + str = rb_funcallv(ra->io, id_read, argc, ra->argv); if (!NIL_P(str)) { Check_Type(str, T_STRING); } @@ -2466,11 +2609,8 @@ gzfile_read_raw_rescue(VALUE arg, VALUE _) static VALUE gzfile_read_raw(struct gzfile *gz, VALUE outbuf) { - struct read_raw_arg ra; - - ra.io = gz->io; - ra.as.in.len = INT2FIX(GZFILE_READ_SIZE); - ra.as.in.buf = outbuf; + struct read_raw_arg ra = + read_raw_arg_init(gz->io, INT2FIX(GZFILE_READ_SIZE), outbuf); return rb_rescue2(gzfile_read_raw_partial, (VALUE)&ra, gzfile_read_raw_rescue, (VALUE)&ra, @@ -2802,18 +2942,18 @@ gzfile_newstr(struct gzfile *gz, VALUE str) } static long -gzfile_fill(struct gzfile *gz, long len) +gzfile_fill(struct gzfile *gz, long len, VALUE outbuf) { if (len < 0) rb_raise(rb_eArgError, "negative length %ld given", len); if (len == 0) return 0; while (!ZSTREAM_IS_FINISHED(&gz->z) && ZSTREAM_BUF_FILLED(&gz->z) < len) { - gzfile_read_more(gz, Qnil); + gzfile_read_more(gz, outbuf); } if (GZFILE_IS_FINISHED(gz)) { if (!(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) { - gzfile_check_footer(gz, Qnil); + gzfile_check_footer(gz, outbuf); } return -1; } @@ -2821,14 +2961,27 @@ gzfile_fill(struct gzfile *gz, long len) } static VALUE -gzfile_read(struct gzfile *gz, long len) +gzfile_read(struct gzfile *gz, long len, VALUE outbuf) { VALUE dst; - len = gzfile_fill(gz, len); - if (len == 0) return rb_str_new(0, 0); - if (len < 0) return Qnil; - dst = zstream_shift_buffer(&gz->z, len); + len = gzfile_fill(gz, len, outbuf); + + if (len < 0) { + if (!NIL_P(outbuf)) + rb_str_resize(outbuf, 0); + return Qnil; + } + if (len == 0) { + if (NIL_P(outbuf)) + return rb_str_new(0, 0); + else { + rb_str_resize(outbuf, 0); + return outbuf; + } + } + + dst = zstream_shift_buffer(&gz->z, len, outbuf); if (!NIL_P(dst)) gzfile_calc_crc(gz, dst); return dst; } @@ -2861,31 +3014,26 @@ gzfile_readpartial(struct gzfile *gz, long len, VALUE outbuf) rb_raise(rb_eEOFError, "end of file reached"); } - dst = zstream_shift_buffer(&gz->z, len); + dst = zstream_shift_buffer(&gz->z, len, outbuf); gzfile_calc_crc(gz, dst); - if (!NIL_P(outbuf)) { - rb_str_resize(outbuf, RSTRING_LEN(dst)); - memcpy(RSTRING_PTR(outbuf), RSTRING_PTR(dst), RSTRING_LEN(dst)); - rb_str_resize(dst, 0); - rb_gc_force_recycle(dst); - dst = outbuf; - } return dst; } static VALUE -gzfile_read_all(struct gzfile *gz) +gzfile_read_all(struct gzfile *gz, VALUE dst) { - VALUE dst; - while (!ZSTREAM_IS_FINISHED(&gz->z)) { - gzfile_read_more(gz, Qnil); + gzfile_read_more(gz, dst); } if (GZFILE_IS_FINISHED(gz)) { if (!(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) { - gzfile_check_footer(gz, Qnil); + gzfile_check_footer(gz, dst); } + if (!NIL_P(dst)) { + rb_str_resize(dst, 0); + return dst; + } return rb_str_new(0, 0); } @@ -2923,7 +3071,7 @@ gzfile_getc(struct gzfile *gz) de = (unsigned char *)ds + GZFILE_CBUF_CAPA; (void)rb_econv_convert(gz->ec, &sp, se, &dp, de, ECONV_PARTIAL_INPUT|ECONV_AFTER_OUTPUT); rb_econv_check_error(gz->ec); - dst = zstream_shift_buffer(&gz->z, sp - ss); + dst = zstream_shift_buffer(&gz->z, sp - ss, Qnil); gzfile_calc_crc(gz, dst); rb_str_resize(cbuf, dp - ds); return cbuf; @@ -2931,7 +3079,7 @@ gzfile_getc(struct gzfile *gz) else { buf = gz->z.buf; len = rb_enc_mbclen(RSTRING_PTR(buf), RSTRING_END(buf), gz->enc); - dst = gzfile_read(gz, len); + dst = gzfile_read(gz, len, Qnil); if (NIL_P(dst)) return dst; return gzfile_newstr(gz, dst); } @@ -3430,6 +3578,9 @@ static VALUE rb_gzfile_eof_p(VALUE obj) { struct gzfile *gz = get_gzfile(obj); + while (!ZSTREAM_IS_FINISHED(&gz->z) && ZSTREAM_BUF_FILLED(&gz->z) == 0) { + gzfile_read_more(gz, Qnil); + } return GZFILE_IS_FINISHED(gz) ? Qtrue : Qfalse; } @@ -3514,6 +3665,16 @@ rb_gzfile_path(VALUE obj) return gz->path; } +static VALUE +gzfile_initialize_path_partial(VALUE obj) +{ + struct gzfile* gz; + TypedData_Get_Struct(obj, struct gzfile, &gzfile_data_type, gz); + gz->path = rb_funcall(gz->io, id_path, 0); + rb_define_singleton_method(obj, "path", rb_gzfile_path, 0); + return Qnil; +} + static void rb_gzfile_ecopts(struct gzfile *gz, VALUE opts) { @@ -3622,8 +3783,8 @@ rb_gzwriter_initialize(int argc, VALUE *argv, VALUE obj) rb_gzfile_ecopts(gz, opt); if (rb_respond_to(io, id_path)) { - gz->path = rb_funcall(gz->io, id_path, 0); - rb_define_singleton_method(obj, "path", rb_gzfile_path, 0); + /* File#path may raise IOError in case when a path is unavailable */ + rb_rescue2(gzfile_initialize_path_partial, obj, NULL, Qnil, rb_eIOError, (VALUE)0); } return obj; @@ -3826,7 +3987,7 @@ rb_gzreader_s_zcat(int argc, VALUE *argv, VALUE klass) if (!buf) { buf = rb_str_new(0, 0); } - tmpbuf = gzfile_read_all(get_gzfile(obj)); + tmpbuf = gzfile_read_all(get_gzfile(obj), Qnil); rb_str_cat(buf, RSTRING_PTR(tmpbuf), RSTRING_LEN(tmpbuf)); } @@ -3884,8 +4045,8 @@ rb_gzreader_initialize(int argc, VALUE *argv, VALUE obj) rb_gzfile_ecopts(gz, opt); if (rb_respond_to(io, id_path)) { - gz->path = rb_funcall(gz->io, id_path, 0); - rb_define_singleton_method(obj, "path", rb_gzfile_path, 0); + /* File#path may raise IOError in case when a path is unavailable */ + rb_rescue2(gzfile_initialize_path_partial, obj, NULL, Qnil, rb_eIOError, (VALUE)0); } return obj; @@ -3928,19 +4089,19 @@ static VALUE rb_gzreader_read(int argc, VALUE *argv, VALUE obj) { struct gzfile *gz = get_gzfile(obj); - VALUE vlen; + VALUE vlen, outbuf; long len; - rb_scan_args(argc, argv, "01", &vlen); + rb_scan_args(argc, argv, "02", &vlen, &outbuf); if (NIL_P(vlen)) { - return gzfile_read_all(gz); + return gzfile_read_all(gz, outbuf); } len = NUM2INT(vlen); if (len < 0) { rb_raise(rb_eArgError, "negative length %ld given", len); } - return gzfile_read(gz, len); + return gzfile_read(gz, len, outbuf); } /* @@ -3949,7 +4110,7 @@ rb_gzreader_read(int argc, VALUE *argv, VALUE obj) * call-seq: * gzipreader.readpartial(maxlen [, outbuf]) => string, outbuf * - * Reads at most <i>maxlen</i> bytes from the gziped stream but + * Reads at most <i>maxlen</i> bytes from the gzipped stream but * it blocks only if <em>gzipreader</em> has no data immediately available. * If the optional <i>outbuf</i> argument is present, * it must reference a String, which will receive the data. @@ -4013,7 +4174,7 @@ rb_gzreader_getbyte(VALUE obj) struct gzfile *gz = get_gzfile(obj); VALUE dst; - dst = gzfile_read(gz, 1); + dst = gzfile_read(gz, 1, Qnil); if (!NIL_P(dst)) { dst = INT2FIX((unsigned int)(RSTRING_PTR(dst)[0]) & 0xff); } @@ -4124,6 +4285,7 @@ gzreader_skip_linebreaks(struct gzfile *gz) while (n++, *(p++) == '\n') { if (n >= ZSTREAM_BUF_FILLED(&gz->z)) { str = zstream_detach_buffer(&gz->z); + ASSUME(!NIL_P(str)); gzfile_calc_crc(gz, str); while (ZSTREAM_BUF_FILLED(&gz->z) == 0) { if (GZFILE_IS_FINISHED(gz)) return; @@ -4134,7 +4296,7 @@ gzreader_skip_linebreaks(struct gzfile *gz) } } - str = zstream_shift_buffer(&gz->z, n - 1); + str = zstream_shift_buffer(&gz->z, n - 1, Qnil); gzfile_calc_crc(gz, str); } @@ -4150,17 +4312,17 @@ gzreader_charboundary(struct gzfile *gz, long n) { char *s = RSTRING_PTR(gz->z.buf); char *e = s + ZSTREAM_BUF_FILLED(&gz->z); - char *p = rb_enc_left_char_head(s, s + n, e, gz->enc); + char *p = rb_enc_left_char_head(s, s + n - 1, e, gz->enc); long l = p - s; if (l < n) { - n = rb_enc_precise_mbclen(p, e, gz->enc); - if (MBCLEN_NEEDMORE_P(n)) { - if ((l = gzfile_fill(gz, l + MBCLEN_NEEDMORE_LEN(n))) > 0) { + int n_bytes = rb_enc_precise_mbclen(p, e, gz->enc); + if (MBCLEN_NEEDMORE_P(n_bytes)) { + if ((l = gzfile_fill(gz, n + MBCLEN_NEEDMORE_LEN(n_bytes), Qnil)) > 0) { return l; } } - else if (MBCLEN_CHARFOUND_P(n)) { - return l + MBCLEN_CHARFOUND_LEN(n); + else if (MBCLEN_CHARFOUND_P(n_bytes)) { + return l + MBCLEN_CHARFOUND_LEN(n_bytes); } } return n; @@ -4207,10 +4369,10 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj) if (NIL_P(rs)) { if (limit < 0) { - dst = gzfile_read_all(gz); + dst = gzfile_read_all(gz, Qnil); if (RSTRING_LEN(dst) == 0) return Qnil; } - else if ((n = gzfile_fill(gz, limit)) <= 0) { + else if ((n = gzfile_fill(gz, limit, Qnil)) <= 0) { return Qnil; } else { @@ -4220,7 +4382,7 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj) else { n = limit; } - dst = zstream_shift_buffer(&gz->z, n); + dst = zstream_shift_buffer(&gz->z, n, Qnil); if (NIL_P(dst)) return dst; gzfile_calc_crc(gz, dst); dst = gzfile_newstr(gz, dst); @@ -4247,7 +4409,7 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj) while (ZSTREAM_BUF_FILLED(&gz->z) < rslen) { if (ZSTREAM_IS_FINISHED(&gz->z)) { if (ZSTREAM_BUF_FILLED(&gz->z) > 0) gz->lineno++; - return gzfile_read(gz, rslen); + return gzfile_read(gz, rslen, Qnil); } gzfile_read_more(gz, Qnil); } @@ -4284,7 +4446,7 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj) } gz->lineno++; - dst = gzfile_read(gz, n); + dst = gzfile_read(gz, n, Qnil); if (NIL_P(dst)) return dst; if (rspara) { gzreader_skip_linebreaks(gz); @@ -4532,6 +4694,7 @@ zlib_gunzip_run(VALUE arg) gzfile_read_header(gz, Qnil); dst = zstream_detach_buffer(&gz->z); + ASSUME(!NIL_P(dst)); gzfile_calc_crc(gz, dst); if (!ZSTREAM_IS_FINISHED(&gz->z)) { rb_raise(cGzError, "unexpected end of file"); @@ -4548,7 +4711,7 @@ zlib_gunzip_run(VALUE arg) void Init_zlib(void) { -#if HAVE_RB_EXT_RACTOR_SAFE +#ifdef HAVE_RB_EXT_RACTOR_SAFE rb_ext_ractor_safe(true); #endif @@ -4570,6 +4733,7 @@ Init_zlib(void) cMemError = rb_define_class_under(mZlib, "MemError", cZError); cBufError = rb_define_class_under(mZlib, "BufError", cZError); cVersionError = rb_define_class_under(mZlib, "VersionError", cZError); + cInProgressError = rb_define_class_under(mZlib, "InProgressError", cZError); rb_define_module_function(mZlib, "zlib_version", rb_zlib_version, 0); rb_define_module_function(mZlib, "adler32", rb_zlib_adler32, -1); @@ -4877,6 +5041,7 @@ Init_zlib(void) * - Zlib::MemError * - Zlib::BufError * - Zlib::VersionError + * - Zlib::InProgressError * */ @@ -4952,6 +5117,20 @@ Init_zlib(void) */ /* + * Document-class: Zlib::InProgressError + * + * Subclass of Zlib::Error. This error is raised when the zlib + * stream is currently in progress. + * + * For example: + * + * inflater = Zlib::Inflate.new + * inflater.inflate(compressed) do + * inflater.inflate(compressed) # Raises Zlib::InProgressError + * end + */ + +/* * Document-class: Zlib::GzipFile::Error * * Base class of errors that occur when processing GZIP files. diff --git a/ext/zlib/zlib.gemspec b/ext/zlib/zlib.gemspec index 714afcc02f..345dc5f225 100644 --- a/ext/zlib/zlib.gemspec +++ b/ext/zlib/zlib.gemspec @@ -22,10 +22,10 @@ Gem::Specification.new do |spec| spec.homepage = "https://github.com/ruby/zlib" spec.licenses = ["Ruby", "BSD-2-Clause"] - spec.files = [".gitignore", ".travis.yml", "Gemfile", "LICENSE.txt", "README.md", "Rakefile", "bin/console", "bin/setup", "ext/zlib/extconf.rb", "ext/zlib/zlib.c", "zlib.gemspec"] + spec.files = ["COPYING", "BSDL", "README.md", "ext/zlib/extconf.rb", "ext/zlib/zlib.c", "zlib.gemspec"] spec.bindir = "exe" - spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } + spec.executables = [] spec.require_paths = ["lib"] spec.extensions = "ext/zlib/extconf.rb" - spec.required_ruby_version = ">= 2.3.0" + spec.required_ruby_version = ">= 2.5.0" end |
