ext/zlib/zlib.c in zlib-2.1.1 vs ext/zlib/zlib.c in zlib-3.0.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 "2.1.1" +#define RUBY_ZLIB_VERSION "3.0.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 @@ -42,10 +42,18 @@ #else #define DEF_MEM_LEVEL MAX_MEM_LEVEL #endif #endif +#if defined(HAVE_TYPE_Z_SIZE_T) +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) { if (n > UINT_MAX) n = UINT_MAX; @@ -63,11 +71,11 @@ /*--------- Prototypes --------*/ 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); static voidpf zlib_mem_alloc(voidpf, uInt, uInt); static void zlib_mem_free(voidpf, voidpf); @@ -286,10 +294,11 @@ * - Zlib::DataError * - Zlib::StreamError * - Zlib::MemError * - Zlib::BufError * - Zlib::VersionError + * - Zlib::InProgressError * * (if you have GZIP_SUPPORT) * - Zlib::GzipReader * - Zlib::GzipWriter * - Zlib::GzipFile @@ -302,11 +311,11 @@ 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) { VALUE exc; @@ -371,30 +380,36 @@ 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_TYPE_Z_SIZE_T) 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; rb_scan_args(argc, argv, "02", &str, &vsum); @@ -408,11 +423,11 @@ else { sum = func(0, Z_NULL, 0); } 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; VALUE buflen = INT2NUM(8192); @@ -458,11 +473,11 @@ /* * Document-method: Zlib.adler32_combine * * 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+. * */ static VALUE @@ -555,18 +570,19 @@ int (*end)(z_streamp); int (*run)(z_streamp, int); } *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) #define ZSTREAM_IS_FINISHED(z) ((z)->flags & ZSTREAM_FLAG_FINISHED) #define ZSTREAM_IS_CLOSING(z) ((z)->flags & ZSTREAM_FLAG_CLOSING) @@ -591,11 +607,13 @@ static const struct zstream_funcs inflate_funcs = { inflateReset, inflateEnd, inflate, }; 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 */ int stream_output; /* for streaming zlib processing */ }; @@ -892,11 +910,10 @@ if (newlen < 0) { newlen = 0; } rb_str_resize(z->input, newlen); if (newlen == 0) { - rb_gc_force_recycle(z->input); z->input = Qnil; } else { rb_str_set_len(z->input, newlen); } @@ -1057,23 +1074,22 @@ struct zstream_run_args *args = (struct zstream_run_args *)ptr; args->interrupt = 1; } -static void -zstream_run0(struct zstream *z, Bytef *src, long len, int flush) +static VALUE +zstream_run_try(VALUE value_arg) { - struct zstream_run_args args; + 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(); - if (NIL_P(z->input) && len == 0) { z->stream.next_in = (Bytef*)""; z->stream.avail_in = 0; } else { @@ -1091,21 +1107,21 @@ zstream_expand_buffer(z); } 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); + 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, + err = (int)(VALUE)rb_nogvl(zstream_run_func, (void *)args, + zstream_unblock_func, (void *)args, RB_NOGVL_UBF_ASYNC_SAFE); #endif /* retry if no exception is thrown */ - if (err == Z_OK && args.interrupt) { - args.interrupt = 0; + if (err == Z_OK && args->interrupt) { + args->interrupt = 0; goto loop; } if (flush != Z_FINISH && err == Z_BUF_ERROR && z->stream.avail_out > 0) { @@ -1135,41 +1151,58 @@ if (z->stream.avail_in > 0) { zstream_append_input(z, z->stream.next_in, z->stream.avail_in); } if (!NIL_P(old_input)) { rb_str_resize(old_input, 0); - rb_gc_force_recycle(old_input); } - if (args.jump_state) - rb_jump_tag(args.jump_state); + if (args->jump_state) + rb_jump_tag(args->jump_state); + + return Qnil; } -struct zstream_run_synchronized_args { - struct zstream *z; - Bytef *src; - long len; - int flush; -}; +static VALUE +zstream_run_ensure(VALUE value_arg) +{ + struct zstream_run_args *args = (struct zstream_run_args *)value_arg; + /* Remove ZSTREAM_IN_PROGRESS flag to signal that this zstream is not in use. */ + args->z->flags &= ~ZSTREAM_IN_PROGRESS; + + return Qnil; +} + static VALUE zstream_run_synchronized(VALUE value_arg) { - struct zstream_run_synchronized_args *run_args = (struct zstream_run_synchronized_args *)value_arg; - zstream_run0(run_args->z, run_args->src, run_args->len, run_args->flush); + 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_synchronized_args run_args; - run_args.z = z; - run_args.src = src; - run_args.len = len; - run_args.flush = flush; - rb_mutex_synchronize(z->mutex, zstream_run_synchronized, (VALUE)&run_args); + 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_mutex_synchronize(z->mutex, zstream_run_synchronized, (VALUE)&args); } static VALUE zstream_sync(struct zstream *z, Bytef *src, long len) { @@ -2904,12 +2937,10 @@ 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; } @@ -4617,10 +4648,11 @@ cDataError = rb_define_class_under(mZlib, "DataError", cZError); cStreamError = rb_define_class_under(mZlib, "StreamError", cZError); 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); rb_define_module_function(mZlib, "adler32_combine", rb_zlib_adler32_combine, 3); rb_define_module_function(mZlib, "crc32", rb_zlib_crc32, -1); @@ -4924,10 +4956,11 @@ * - Zlib::DataError * - Zlib::StreamError * - Zlib::MemError * - Zlib::BufError * - Zlib::VersionError + * - Zlib::InProgressError * */ /* * Document-class: Zlib::StreamEnd @@ -4996,9 +5029,23 @@ * * Subclass of Zlib::Error when zlib returns a Z_DATA_ERROR. * * Usually if a stream was prematurely freed. * + */ + +/* + * 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 *