ext/zlib/zlib.c in zlib-3.1.1 vs ext/zlib/zlib.c in zlib-3.2.0

- old
+ new

@@ -23,11 +23,11 @@ #else # define VALGRIND_MAKE_MEM_DEFINED(p, n) 0 # define VALGRIND_MAKE_MEM_UNDEFINED(p, n) 0 #endif -#define RUBY_ZLIB_VERSION "3.1.1" +#define RUBY_ZLIB_VERSION "3.2.0" #ifndef RB_PASS_CALLED_KEYWORDS # define rb_class_new_instance_kw(argc, argv, klass, kw_splat) rb_class_new_instance(argc, argv, klass) #endif @@ -88,11 +88,11 @@ static void zstream_expand_buffer(struct zstream*); 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); static void zstream_discard_input(struct zstream*, long); static void zstream_reset_input(struct zstream*); @@ -168,12 +168,12 @@ static void gzfile_read_header(struct gzfile*, VALUE outbuf); 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); static void gzfile_writer_end(struct gzfile*); static VALUE gzfile_reader_end_run(VALUE); @@ -818,23 +818,35 @@ return dst; } 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); buflen = (long)rb_str_capacity(z->buf) - ZSTREAM_BUF_FILLED(z); if (buflen > ZSTREAM_AVAIL_OUT_STEP_MAX) { @@ -1086,10 +1098,16 @@ int flush = args->flush; int err; VALUE old_input = Qnil; + /* 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*)""; z->stream.avail_in = 0; } else { @@ -1153,43 +1171,26 @@ } if (!NIL_P(old_input)) { rb_str_resize(old_input, 0); } - if (args->jump_state) - rb_jump_tag(args->jump_state); - 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. */ - args->z->flags &= ~ZSTREAM_IN_PROGRESS; + z->flags &= ~ZSTREAM_IN_PROGRESS; + rb_mutex_unlock(z->mutex); return Qnil; } -static VALUE -zstream_run_synchronized(VALUE value_arg) -{ - struct zstream_run_args *args = (struct zstream_run_args *)value_arg; - - /* Cannot start zstream while it is in progress. */ - if (args->z->flags & ZSTREAM_IN_PROGRESS) { - rb_raise(cInProgressError, "zlib stream is in progress"); - } - args->z->flags |= ZSTREAM_IN_PROGRESS; - - rb_ensure(zstream_run_try, value_arg, zstream_run_ensure, value_arg); - - return Qnil; -} - static void zstream_run(struct zstream *z, Bytef *src, long len, int flush) { struct zstream_run_args args = { .z = z, @@ -1198,11 +1199,14 @@ .flush = flush, .interrupt = 0, .jump_state = 0, .stream_output = !ZSTREAM_IS_GZFILE(z) && rb_block_given_p(), }; - rb_mutex_synchronize(z->mutex, zstream_run_synchronized, (VALUE)&args); + rb_mutex_lock(z->mutex); + rb_ensure(zstream_run_try, (VALUE)&args, zstream_run_ensure, (VALUE)&args); + if (args.jump_state) + rb_jump_tag(args.jump_state); } static VALUE zstream_sync(struct zstream *z, Bytef *src, long len) { @@ -1507,11 +1511,11 @@ { return rb_uint2inum(get_zstream(obj)->stream.total_out); } /* - * 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>. */ static VALUE rb_zstream_data_type(VALUE obj) @@ -2872,37 +2876,50 @@ return rb_str_conv_enc_opts(str, gz->enc2, gz->enc, gz->ecflags, gz->ecopts); } 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; } return len < ZSTREAM_BUF_FILLED(&gz->z) ? len : ZSTREAM_BUF_FILLED(&gz->z); } 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; } static VALUE @@ -2931,33 +2948,30 @@ if (!NIL_P(outbuf)) rb_str_resize(outbuf, 0); 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)); - 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); } dst = zstream_detach_buffer(&gz->z); if (NIL_P(dst)) return dst; @@ -2991,19 +3005,19 @@ se = sp + ZSTREAM_BUF_FILLED(&gz->z); ds = dp = (unsigned char *)RSTRING_PTR(cbuf); 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; } 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); } } @@ -3907,11 +3921,11 @@ } else { 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)); } rb_gzreader_read(0, 0, obj); pos = NUM2LONG(rb_funcall(io, rb_intern("pos"), 0)); @@ -4009,32 +4023,32 @@ */ 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); } /* * Document-method: Zlib::GzipReader#readpartial * * 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. * It raises <code>EOFError</code> on end of file. */ @@ -4094,11 +4108,11 @@ 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); } return dst; } @@ -4205,21 +4219,22 @@ p = RSTRING_PTR(gz->z.buf); 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; gzfile_read_more(gz, Qnil); } n = 0; p = RSTRING_PTR(gz->z.buf); } } - str = zstream_shift_buffer(&gz->z, n - 1); + str = zstream_shift_buffer(&gz->z, n - 1, Qnil); gzfile_calc_crc(gz, str); } static void rscheck(const char *rsptr, long rslen, VALUE rs) @@ -4236,11 +4251,11 @@ char *p = rb_enc_left_char_head(s, s + n - 1, e, gz->enc); long l = p - s; if (l < n) { 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))) > 0) { + if ((l = gzfile_fill(gz, n + MBCLEN_NEEDMORE_LEN(n_bytes), Qnil)) > 0) { return l; } } else if (MBCLEN_CHARFOUND_P(n_bytes)) { return l + MBCLEN_CHARFOUND_LEN(n_bytes); @@ -4288,24 +4303,24 @@ } } 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 { if (maxlen > 1 && n >= limit && !GZFILE_IS_FINISHED(gz)) { n = gzreader_charboundary(gz, n); } 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); } gz->lineno++; @@ -4328,11 +4343,11 @@ } 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); } p = RSTRING_PTR(gz->z.buf); @@ -4365,11 +4380,11 @@ if (maxlen > 1 && n == limit && (ZSTREAM_BUF_FILLED(&gz->z) > n || !ZSTREAM_IS_FINISHED(&gz->z))) { n = gzreader_charboundary(gz, n); } 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); } RB_GC_GUARD(rs); @@ -4613,9 +4628,10 @@ struct gzfile *gz = (struct gzfile *)arg; VALUE dst; 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"); } if (NIL_P(gz->z.input)) {