zlib 0.1.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/ext/zlib/zlib.c CHANGED
@@ -25,7 +25,11 @@
25
25
  # define VALGRIND_MAKE_MEM_UNDEFINED(p, n) 0
26
26
  #endif
27
27
 
28
- #define RUBY_ZLIB_VERSION "0.6.0"
28
+ #define RUBY_ZLIB_VERSION "2.1.0"
29
+
30
+ #ifndef RB_PASS_CALLED_KEYWORDS
31
+ # define rb_class_new_instance_kw(argc, argv, klass, kw_splat) rb_class_new_instance(argc, argv, klass)
32
+ #endif
29
33
 
30
34
  #ifndef GZIP_SUPPORT
31
35
  #define GZIP_SUPPORT 1
@@ -52,7 +56,10 @@ max_uint(long n)
52
56
  #define MAX_UINT(n) (uInt)(n)
53
57
  #endif
54
58
 
55
- static ID id_dictionaries;
59
+ #define OPTHASH_GIVEN_P(opts) \
60
+ (argc > 0 && !NIL_P((opts) = rb_check_hash_type(argv[argc-1])) && (--argc, 1))
61
+
62
+ static ID id_dictionaries, id_read, id_buffer;
56
63
 
57
64
  /*--------- Prototypes --------*/
58
65
 
@@ -85,6 +92,7 @@ static void zstream_passthrough_input(struct zstream*);
85
92
  static VALUE zstream_detach_input(struct zstream*);
86
93
  static void zstream_reset(struct zstream*);
87
94
  static VALUE zstream_end(struct zstream*);
95
+ static VALUE zstream_ensure_end(VALUE v);
88
96
  static void zstream_run(struct zstream*, Bytef*, long, int);
89
97
  static VALUE zstream_sync(struct zstream*, Bytef*, long);
90
98
  static void zstream_mark(void*);
@@ -125,7 +133,7 @@ static VALUE rb_inflate_s_allocate(VALUE);
125
133
  static VALUE rb_inflate_initialize(int, VALUE*, VALUE);
126
134
  static VALUE rb_inflate_s_inflate(VALUE, VALUE);
127
135
  static void do_inflate(struct zstream*, VALUE);
128
- static VALUE rb_inflate_inflate(VALUE, VALUE);
136
+ static VALUE rb_inflate_inflate(int, VALUE*, VALUE);
129
137
  static VALUE rb_inflate_addstr(VALUE, VALUE);
130
138
  static VALUE rb_inflate_sync(VALUE, VALUE);
131
139
  static VALUE rb_inflate_sync_point_p(VALUE);
@@ -140,19 +148,19 @@ static void gzfile_reset(struct gzfile*);
140
148
  static void gzfile_close(struct gzfile*, int);
141
149
  static void gzfile_write_raw(struct gzfile*);
142
150
  static VALUE gzfile_read_raw_partial(VALUE);
143
- static VALUE gzfile_read_raw_rescue(VALUE);
144
- static VALUE gzfile_read_raw(struct gzfile*);
145
- static int gzfile_read_raw_ensure(struct gzfile*, long);
151
+ static VALUE gzfile_read_raw_rescue(VALUE,VALUE);
152
+ static VALUE gzfile_read_raw(struct gzfile*, VALUE outbuf);
153
+ static int gzfile_read_raw_ensure(struct gzfile*, long, VALUE outbuf);
146
154
  static char *gzfile_read_raw_until_zero(struct gzfile*, long);
147
155
  static unsigned int gzfile_get16(const unsigned char*);
148
156
  static unsigned long gzfile_get32(const unsigned char*);
149
157
  static void gzfile_set32(unsigned long n, unsigned char*);
150
158
  static void gzfile_make_header(struct gzfile*);
151
159
  static void gzfile_make_footer(struct gzfile*);
152
- static void gzfile_read_header(struct gzfile*);
153
- static void gzfile_check_footer(struct gzfile*);
160
+ static void gzfile_read_header(struct gzfile*, VALUE outbuf);
161
+ static void gzfile_check_footer(struct gzfile*, VALUE outbuf);
154
162
  static void gzfile_write(struct gzfile*, Bytef*, long);
155
- static long gzfile_read_more(struct gzfile*);
163
+ static long gzfile_read_more(struct gzfile*, VALUE outbuf);
156
164
  static void gzfile_calc_crc(struct gzfile*, VALUE);
157
165
  static VALUE gzfile_read(struct gzfile*, long);
158
166
  static VALUE gzfile_read_all(struct gzfile*);
@@ -197,7 +205,7 @@ static VALUE rb_gzwriter_s_allocate(VALUE);
197
205
  static VALUE rb_gzwriter_s_open(int, VALUE*, VALUE);
198
206
  static VALUE rb_gzwriter_initialize(int, VALUE*, VALUE);
199
207
  static VALUE rb_gzwriter_flush(int, VALUE*, VALUE);
200
- static VALUE rb_gzwriter_write(VALUE, VALUE);
208
+ static VALUE rb_gzwriter_write(int, VALUE*, VALUE);
201
209
  static VALUE rb_gzwriter_putc(VALUE, VALUE);
202
210
 
203
211
  static VALUE rb_gzreader_s_allocate(VALUE);
@@ -346,7 +354,9 @@ raise_zlib_error(int err, const char *msg)
346
354
  static void
347
355
  finalizer_warn(const char *msg)
348
356
  {
357
+ #if 0
349
358
  fprintf(stderr, "zlib(finalizer): %s\n", msg);
359
+ #endif
350
360
  }
351
361
 
352
362
 
@@ -360,11 +370,7 @@ finalizer_warn(const char *msg)
360
370
  static VALUE
361
371
  rb_zlib_version(VALUE klass)
362
372
  {
363
- VALUE str;
364
-
365
- str = rb_str_new2(zlibVersion());
366
- OBJ_TAINT(str); /* for safe */
367
- return str;
373
+ return rb_str_new2(zlibVersion());
368
374
  }
369
375
 
370
376
  #if SIZEOF_LONG > SIZEOF_INT
@@ -406,6 +412,15 @@ do_checksum(int argc, VALUE *argv, uLong (*func)(uLong, const Bytef*, uInt))
406
412
  if (NIL_P(str)) {
407
413
  sum = func(sum, Z_NULL, 0);
408
414
  }
415
+ else if (rb_obj_is_kind_of(str, rb_cIO)) {
416
+ VALUE buf;
417
+ VALUE buflen = INT2NUM(8192);
418
+
419
+ while (!NIL_P(buf = rb_funcall(str, id_read, 1, buflen))) {
420
+ StringValue(buf);
421
+ sum = checksum_long(func, sum, (Bytef*)RSTRING_PTR(buf), RSTRING_LEN(buf));
422
+ }
423
+ }
409
424
  else {
410
425
  StringValue(str);
411
426
  sum = checksum_long(func, sum, (Bytef*)RSTRING_PTR(str), RSTRING_LEN(str));
@@ -421,6 +436,8 @@ do_checksum(int argc, VALUE *argv, uLong (*func)(uLong, const Bytef*, uInt))
421
436
  * Calculates Adler-32 checksum for +string+, and returns updated value of
422
437
  * +adler+. If +string+ is omitted, it returns the Adler-32 initial value. If
423
438
  * +adler+ is omitted, it assumes that the initial value is given to +adler+.
439
+ * If +string+ is an IO instance, reads from the IO until the IO returns nil
440
+ * and returns Adler-32 of all read data.
424
441
  *
425
442
  * Example usage:
426
443
  *
@@ -451,7 +468,7 @@ rb_zlib_adler32(int argc, VALUE *argv, VALUE klass)
451
468
  static VALUE
452
469
  rb_zlib_adler32_combine(VALUE klass, VALUE adler1, VALUE adler2, VALUE len2)
453
470
  {
454
- return ULONG2NUM(
471
+ return ULONG2NUM(
455
472
  adler32_combine(NUM2ULONG(adler1), NUM2ULONG(adler2), NUM2LONG(len2)));
456
473
  }
457
474
  #else
@@ -465,7 +482,9 @@ rb_zlib_adler32_combine(VALUE klass, VALUE adler1, VALUE adler2, VALUE len2)
465
482
  *
466
483
  * Calculates CRC checksum for +string+, and returns updated value of +crc+. If
467
484
  * +string+ is omitted, it returns the CRC initial value. If +crc+ is omitted, it
468
- * assumes that the initial value is given to +crc+.
485
+ * assumes that the initial value is given to +crc+. If +string+ is an IO instance,
486
+ * reads from the IO until the IO returns nil and returns CRC checksum of all read
487
+ * data.
469
488
  *
470
489
  * FIXME: expression.
471
490
  */
@@ -489,7 +508,7 @@ rb_zlib_crc32(int argc, VALUE *argv, VALUE klass)
489
508
  static VALUE
490
509
  rb_zlib_crc32_combine(VALUE klass, VALUE crc1, VALUE crc2, VALUE len2)
491
510
  {
492
- return ULONG2NUM(
511
+ return ULONG2NUM(
493
512
  crc32_combine(NUM2ULONG(crc1), NUM2ULONG(crc2), NUM2LONG(len2)));
494
513
  }
495
514
  #else
@@ -529,6 +548,7 @@ struct zstream {
529
548
  unsigned long flags;
530
549
  VALUE buf;
531
550
  VALUE input;
551
+ VALUE mutex;
532
552
  z_stream stream;
533
553
  const struct zstream_funcs {
534
554
  int (*reset)(z_streamp);
@@ -543,7 +563,8 @@ struct zstream {
543
563
  #define ZSTREAM_FLAG_CLOSING 0x8
544
564
  #define ZSTREAM_FLAG_GZFILE 0x10 /* disallows yield from expand_buffer for
545
565
  gzip*/
546
- #define ZSTREAM_FLAG_UNUSED 0x20
566
+ #define ZSTREAM_REUSE_BUFFER 0x20
567
+ #define ZSTREAM_FLAG_UNUSED 0x40
547
568
 
548
569
  #define ZSTREAM_READY(z) ((z)->flags |= ZSTREAM_FLAG_READY)
549
570
  #define ZSTREAM_IS_READY(z) ((z)->flags & ZSTREAM_FLAG_READY)
@@ -552,6 +573,8 @@ struct zstream {
552
573
  #define ZSTREAM_IS_GZFILE(z) ((z)->flags & ZSTREAM_FLAG_GZFILE)
553
574
  #define ZSTREAM_BUF_FILLED(z) (NIL_P((z)->buf) ? 0 : RSTRING_LEN((z)->buf))
554
575
 
576
+ #define ZSTREAM_REUSE_BUFFER_P(z) ((z)->flags & ZSTREAM_REUSE_BUFFER)
577
+
555
578
  #define ZSTREAM_EXPAND_BUFFER_OK 0
556
579
 
557
580
  /* I think that more better value should be found,
@@ -601,6 +624,7 @@ zstream_init(struct zstream *z, const struct zstream_funcs *func)
601
624
  z->flags = 0;
602
625
  z->buf = Qnil;
603
626
  z->input = Qnil;
627
+ z->mutex = rb_mutex_new();
604
628
  z->stream.zalloc = zlib_mem_alloc;
605
629
  z->stream.zfree = zlib_mem_free;
606
630
  z->stream.opaque = Z_NULL;
@@ -627,14 +651,22 @@ zstream_expand_buffer(struct zstream *z)
627
651
  long buf_filled = ZSTREAM_BUF_FILLED(z);
628
652
  if (buf_filled >= ZSTREAM_AVAIL_OUT_STEP_MAX) {
629
653
  int state = 0;
630
- VALUE self = (VALUE)z->stream.opaque;
631
654
 
632
- rb_obj_reveal(z->buf, rb_cString);
633
- OBJ_INFECT(z->buf, self);
655
+ if (!ZSTREAM_REUSE_BUFFER_P(z)) {
656
+ rb_obj_reveal(z->buf, rb_cString);
657
+ }
634
658
 
659
+ rb_mutex_unlock(z->mutex);
635
660
  rb_protect(rb_yield, z->buf, &state);
636
-
637
- z->buf = Qnil;
661
+ rb_mutex_lock(z->mutex);
662
+
663
+ if (ZSTREAM_REUSE_BUFFER_P(z)) {
664
+ rb_str_modify(z->buf);
665
+ rb_str_set_len(z->buf, 0);
666
+ }
667
+ else {
668
+ z->buf = Qnil;
669
+ }
638
670
  zstream_expand_buffer_into(z, ZSTREAM_AVAIL_OUT_STEP_MAX);
639
671
 
640
672
  if (state)
@@ -644,7 +676,7 @@ zstream_expand_buffer(struct zstream *z)
644
676
  }
645
677
  else {
646
678
  zstream_expand_buffer_into(z,
647
- ZSTREAM_AVAIL_OUT_STEP_MAX - buf_filled);
679
+ ZSTREAM_AVAIL_OUT_STEP_MAX - buf_filled);
648
680
  }
649
681
  }
650
682
  else {
@@ -738,7 +770,7 @@ zstream_append_buffer(struct zstream *z, const Bytef *src, long len)
738
770
  static VALUE
739
771
  zstream_detach_buffer(struct zstream *z)
740
772
  {
741
- VALUE dst, self = (VALUE)z->stream.opaque;
773
+ VALUE dst;
742
774
 
743
775
  if (!ZSTREAM_IS_FINISHED(z) && !ZSTREAM_IS_GZFILE(z) &&
744
776
  rb_block_given_p()) {
@@ -752,11 +784,11 @@ zstream_detach_buffer(struct zstream *z)
752
784
  }
753
785
  else {
754
786
  dst = z->buf;
755
- rb_obj_reveal(dst, rb_cString);
787
+ if (!ZSTREAM_REUSE_BUFFER_P(z)) {
788
+ rb_obj_reveal(dst, rb_cString);
789
+ }
756
790
  }
757
791
 
758
- OBJ_INFECT(dst, self);
759
-
760
792
  z->buf = Qnil;
761
793
  z->stream.next_out = 0;
762
794
  z->stream.avail_out = 0;
@@ -845,19 +877,50 @@ zstream_append_input(struct zstream *z, const Bytef *src, long len)
845
877
  static void
846
878
  zstream_discard_input(struct zstream *z, long len)
847
879
  {
848
- if (NIL_P(z->input) || RSTRING_LEN(z->input) <= len) {
849
- z->input = Qnil;
880
+ if (NIL_P(z->input)) {
850
881
  }
851
- else {
852
- z->input = rb_str_substr(z->input, len,
853
- RSTRING_LEN(z->input) - len);
882
+ else if (RBASIC_CLASS(z->input) == 0) {
883
+ /* hidden, we created z->input and have complete control */
884
+ char *ptr;
885
+ long oldlen, newlen;
886
+
887
+ RSTRING_GETMEM(z->input, ptr, oldlen);
888
+ newlen = oldlen - len;
889
+ if (newlen > 0) {
890
+ memmove(ptr, ptr + len, newlen);
891
+ }
892
+ if (newlen < 0) {
893
+ newlen = 0;
894
+ }
895
+ rb_str_resize(z->input, newlen);
896
+ if (newlen == 0) {
897
+ rb_gc_force_recycle(z->input);
898
+ z->input = Qnil;
899
+ }
900
+ else {
901
+ rb_str_set_len(z->input, newlen);
902
+ }
903
+ }
904
+ else { /* do not mangle user-provided data */
905
+ if (RSTRING_LEN(z->input) <= len) {
906
+ z->input = Qnil;
907
+ }
908
+ else {
909
+ z->input = rb_str_substr(z->input, len,
910
+ RSTRING_LEN(z->input) - len);
911
+ }
854
912
  }
855
913
  }
856
914
 
857
915
  static void
858
916
  zstream_reset_input(struct zstream *z)
859
917
  {
860
- z->input = Qnil;
918
+ if (!NIL_P(z->input) && RBASIC_CLASS(z->input) == 0) {
919
+ rb_str_resize(z->input, 0);
920
+ }
921
+ else {
922
+ z->input = Qnil;
923
+ }
861
924
  }
862
925
 
863
926
  static void
@@ -882,7 +945,6 @@ zstream_detach_input(struct zstream *z)
882
945
  rb_obj_reveal(dst, rb_cString);
883
946
  }
884
947
  z->input = Qnil;
885
- rb_obj_reveal(dst, rb_cString);
886
948
  return dst;
887
949
  }
888
950
 
@@ -925,6 +987,12 @@ zstream_end(struct zstream *z)
925
987
  return Qnil;
926
988
  }
927
989
 
990
+ static VALUE
991
+ zstream_ensure_end(VALUE v)
992
+ {
993
+ return zstream_end((struct zstream *)v);
994
+ }
995
+
928
996
  static void *
929
997
  zstream_run_func(void *ptr)
930
998
  {
@@ -981,6 +1049,7 @@ zstream_run_func(void *ptr)
981
1049
 
982
1050
  /*
983
1051
  * There is no safe way to interrupt z->run->func().
1052
+ * async-signal-safe
984
1053
  */
985
1054
  static void
986
1055
  zstream_unblock_func(void *ptr)
@@ -991,11 +1060,11 @@ zstream_unblock_func(void *ptr)
991
1060
  }
992
1061
 
993
1062
  static void
994
- zstream_run(struct zstream *z, Bytef *src, long len, int flush)
1063
+ zstream_run0(struct zstream *z, Bytef *src, long len, int flush)
995
1064
  {
996
1065
  struct zstream_run_args args;
997
1066
  int err;
998
- VALUE guard = Qnil;
1067
+ VALUE old_input = Qnil;
999
1068
 
1000
1069
  args.z = z;
1001
1070
  args.flush = flush;
@@ -1009,12 +1078,13 @@ zstream_run(struct zstream *z, Bytef *src, long len, int flush)
1009
1078
  }
1010
1079
  else {
1011
1080
  zstream_append_input(z, src, len);
1012
- z->stream.next_in = (Bytef*)RSTRING_PTR(z->input);
1013
- z->stream.avail_in = MAX_UINT(RSTRING_LEN(z->input));
1014
1081
  /* keep reference to `z->input' so as not to be garbage collected
1015
1082
  after zstream_reset_input() and prevent `z->stream.next_in'
1016
1083
  from dangling. */
1017
- guard = z->input;
1084
+ old_input = zstream_detach_input(z);
1085
+ rb_obj_hide(old_input); /* for GVL release and later recycle */
1086
+ z->stream.next_in = (Bytef*)RSTRING_PTR(old_input);
1087
+ z->stream.avail_in = MAX_UINT(RSTRING_LEN(old_input));
1018
1088
  }
1019
1089
 
1020
1090
  if (z->stream.avail_out == 0) {
@@ -1022,8 +1092,20 @@ zstream_run(struct zstream *z, Bytef *src, long len, int flush)
1022
1092
  }
1023
1093
 
1024
1094
  loop:
1095
+ #ifndef RB_NOGVL_UBF_ASYNC_SAFE
1025
1096
  err = (int)(VALUE)rb_thread_call_without_gvl(zstream_run_func, (void *)&args,
1026
1097
  zstream_unblock_func, (void *)&args);
1098
+ #else
1099
+ err = (int)(VALUE)rb_nogvl(zstream_run_func, (void *)&args,
1100
+ zstream_unblock_func, (void *)&args,
1101
+ RB_NOGVL_UBF_ASYNC_SAFE);
1102
+ #endif
1103
+
1104
+ /* retry if no exception is thrown */
1105
+ if (err == Z_OK && args.interrupt) {
1106
+ args.interrupt = 0;
1107
+ goto loop;
1108
+ }
1027
1109
 
1028
1110
  if (flush != Z_FINISH && err == Z_BUF_ERROR
1029
1111
  && z->stream.avail_out > 0) {
@@ -1052,13 +1134,42 @@ loop:
1052
1134
 
1053
1135
  if (z->stream.avail_in > 0) {
1054
1136
  zstream_append_input(z, z->stream.next_in, z->stream.avail_in);
1055
- RB_GC_GUARD(guard); /* prevent tail call to make guard effective */
1137
+ }
1138
+ if (!NIL_P(old_input)) {
1139
+ rb_str_resize(old_input, 0);
1140
+ rb_gc_force_recycle(old_input);
1056
1141
  }
1057
1142
 
1058
1143
  if (args.jump_state)
1059
1144
  rb_jump_tag(args.jump_state);
1060
1145
  }
1061
1146
 
1147
+ struct zstream_run_synchronized_args {
1148
+ struct zstream *z;
1149
+ Bytef *src;
1150
+ long len;
1151
+ int flush;
1152
+ };
1153
+
1154
+ static VALUE
1155
+ zstream_run_synchronized(VALUE value_arg)
1156
+ {
1157
+ struct zstream_run_synchronized_args *run_args = (struct zstream_run_synchronized_args *)value_arg;
1158
+ zstream_run0(run_args->z, run_args->src, run_args->len, run_args->flush);
1159
+ return Qnil;
1160
+ }
1161
+
1162
+ static void
1163
+ zstream_run(struct zstream *z, Bytef *src, long len, int flush)
1164
+ {
1165
+ struct zstream_run_synchronized_args run_args;
1166
+ run_args.z = z;
1167
+ run_args.src = src;
1168
+ run_args.len = len;
1169
+ run_args.flush = flush;
1170
+ rb_mutex_synchronize(z->mutex, zstream_run_synchronized, (VALUE)&run_args);
1171
+ }
1172
+
1062
1173
  static VALUE
1063
1174
  zstream_sync(struct zstream *z, Bytef *src, long len)
1064
1175
  {
@@ -1104,6 +1215,7 @@ zstream_mark(void *p)
1104
1215
  struct zstream *z = p;
1105
1216
  rb_gc_mark(z->buf);
1106
1217
  rb_gc_mark(z->input);
1218
+ rb_gc_mark(z->mutex);
1107
1219
  }
1108
1220
 
1109
1221
  static void
@@ -1285,7 +1397,6 @@ rb_zstream_flush_next_in(VALUE obj)
1285
1397
 
1286
1398
  TypedData_Get_Struct(obj, struct zstream, &zstream_data_type, z);
1287
1399
  dst = zstream_detach_input(z);
1288
- OBJ_INFECT(dst, obj);
1289
1400
  return dst;
1290
1401
  }
1291
1402
 
@@ -1381,7 +1492,7 @@ rb_zstream_data_type(VALUE obj)
1381
1492
  static VALUE
1382
1493
  rb_zstream_adler(VALUE obj)
1383
1494
  {
1384
- return rb_uint2inum(get_zstream(obj)->stream.adler);
1495
+ return rb_uint2inum(get_zstream(obj)->stream.adler);
1385
1496
  }
1386
1497
 
1387
1498
  /*
@@ -1604,9 +1715,8 @@ rb_deflate_s_deflate(int argc, VALUE *argv, VALUE klass)
1604
1715
 
1605
1716
  args[0] = (VALUE)&z;
1606
1717
  args[1] = src;
1607
- dst = rb_ensure(deflate_run, (VALUE)args, zstream_end, (VALUE)&z);
1718
+ dst = rb_ensure(deflate_run, (VALUE)args, zstream_ensure_end, (VALUE)&z);
1608
1719
 
1609
- OBJ_INFECT(dst, src);
1610
1720
  return dst;
1611
1721
  }
1612
1722
 
@@ -1656,7 +1766,6 @@ rb_deflate_deflate(int argc, VALUE *argv, VALUE obj)
1656
1766
  VALUE src, flush;
1657
1767
 
1658
1768
  rb_scan_args(argc, argv, "11", &src, &flush);
1659
- OBJ_INFECT(obj, src);
1660
1769
  do_deflate(z, src, ARG_FLUSH(flush));
1661
1770
 
1662
1771
  return zstream_detach_buffer(z);
@@ -1674,7 +1783,6 @@ rb_deflate_deflate(int argc, VALUE *argv, VALUE obj)
1674
1783
  static VALUE
1675
1784
  rb_deflate_addstr(VALUE obj, VALUE src)
1676
1785
  {
1677
- OBJ_INFECT(obj, src);
1678
1786
  do_deflate(get_zstream(obj), src, Z_NO_FLUSH);
1679
1787
  return obj;
1680
1788
  }
@@ -1774,7 +1882,6 @@ rb_deflate_set_dictionary(VALUE obj, VALUE dic)
1774
1882
  VALUE src = dic;
1775
1883
  int err;
1776
1884
 
1777
- OBJ_INFECT(obj, dic);
1778
1885
  StringValue(src);
1779
1886
  err = deflateSetDictionary(&z->stream,
1780
1887
  (Bytef*)RSTRING_PTR(src), RSTRING_LENINT(src));
@@ -1919,9 +2026,8 @@ rb_inflate_s_inflate(VALUE obj, VALUE src)
1919
2026
 
1920
2027
  args[0] = (VALUE)&z;
1921
2028
  args[1] = src;
1922
- dst = rb_ensure(inflate_run, (VALUE)args, zstream_end, (VALUE)&z);
2029
+ dst = rb_ensure(inflate_run, (VALUE)args, zstream_ensure_end, (VALUE)&z);
1923
2030
 
1924
- OBJ_INFECT(dst, src);
1925
2031
  return dst;
1926
2032
  }
1927
2033
 
@@ -1962,8 +2068,8 @@ rb_inflate_add_dictionary(VALUE obj, VALUE dictionary)
1962
2068
  * Document-method: Zlib::Inflate#inflate
1963
2069
  *
1964
2070
  * call-seq:
1965
- * inflate(deflate_string) -> String
1966
- * inflate(deflate_string) { |chunk| ... } -> nil
2071
+ * inflate(deflate_string, buffer: nil) -> String
2072
+ * inflate(deflate_string, buffer: nil) { |chunk| ... } -> nil
1967
2073
  *
1968
2074
  * Inputs +deflate_string+ into the inflate stream and returns the output from
1969
2075
  * the stream. Calling this method, both the input and the output buffer of
@@ -1973,6 +2079,15 @@ rb_inflate_add_dictionary(VALUE obj, VALUE dictionary)
1973
2079
  * If a block is given consecutive inflated chunks from the +deflate_string+
1974
2080
  * are yielded to the block and +nil+ is returned.
1975
2081
  *
2082
+ * If a :buffer keyword argument is given and not nil:
2083
+ *
2084
+ * * The :buffer keyword should be a String, and will used as the output buffer.
2085
+ * Using this option can reuse the memory required during inflation.
2086
+ * * When not passing a block, the return value will be the same object as the
2087
+ * :buffer keyword argument.
2088
+ * * When passing a block, the yielded chunks will be the same value as the
2089
+ * :buffer keyword argument.
2090
+ *
1976
2091
  * Raises a Zlib::NeedDict exception if a preset dictionary is needed to
1977
2092
  * decompress. Set the dictionary by Zlib::Inflate#set_dictionary and then
1978
2093
  * call this method again with an empty string to flush the stream:
@@ -1996,12 +2111,37 @@ rb_inflate_add_dictionary(VALUE obj, VALUE dictionary)
1996
2111
  * See also Zlib::Inflate.new
1997
2112
  */
1998
2113
  static VALUE
1999
- rb_inflate_inflate(VALUE obj, VALUE src)
2114
+ rb_inflate_inflate(int argc, VALUE* argv, VALUE obj)
2000
2115
  {
2001
2116
  struct zstream *z = get_zstream(obj);
2002
- VALUE dst;
2117
+ VALUE dst, src, opts, buffer = Qnil;
2003
2118
 
2004
- OBJ_INFECT(obj, src);
2119
+ if (OPTHASH_GIVEN_P(opts)) {
2120
+ VALUE buf;
2121
+ rb_get_kwargs(opts, &id_buffer, 0, 1, &buf);
2122
+ if (buf != Qundef && buf != Qnil) {
2123
+ buffer = StringValue(buf);
2124
+ }
2125
+ }
2126
+ if (buffer != Qnil) {
2127
+ if (!(ZSTREAM_REUSE_BUFFER_P(z) && z->buf == buffer)) {
2128
+ long len = RSTRING_LEN(buffer);
2129
+ if (len >= ZSTREAM_AVAIL_OUT_STEP_MAX) {
2130
+ rb_str_modify(buffer);
2131
+ }
2132
+ else {
2133
+ len = ZSTREAM_AVAIL_OUT_STEP_MAX - len;
2134
+ rb_str_modify_expand(buffer, len);
2135
+ }
2136
+ rb_str_set_len(buffer, 0);
2137
+ z->flags |= ZSTREAM_REUSE_BUFFER;
2138
+ z->buf = buffer;
2139
+ }
2140
+ } else if (ZSTREAM_REUSE_BUFFER_P(z)) {
2141
+ z->flags &= ~ZSTREAM_REUSE_BUFFER;
2142
+ z->buf = Qnil;
2143
+ }
2144
+ rb_scan_args(argc, argv, "10", &src);
2005
2145
 
2006
2146
  if (ZSTREAM_IS_FINISHED(z)) {
2007
2147
  if (NIL_P(src)) {
@@ -2010,8 +2150,11 @@ rb_inflate_inflate(VALUE obj, VALUE src)
2010
2150
  else {
2011
2151
  StringValue(src);
2012
2152
  zstream_append_buffer2(z, src);
2013
- dst = rb_str_new(0, 0);
2014
- OBJ_INFECT(dst, obj);
2153
+ if (ZSTREAM_REUSE_BUFFER_P(z)) {
2154
+ dst = rb_str_resize(buffer, 0);
2155
+ } else {
2156
+ dst = rb_str_new(0, 0);
2157
+ }
2015
2158
  }
2016
2159
  }
2017
2160
  else {
@@ -2037,8 +2180,6 @@ rb_inflate_addstr(VALUE obj, VALUE src)
2037
2180
  {
2038
2181
  struct zstream *z = get_zstream(obj);
2039
2182
 
2040
- OBJ_INFECT(obj, src);
2041
-
2042
2183
  if (ZSTREAM_IS_FINISHED(z)) {
2043
2184
  if (!NIL_P(src)) {
2044
2185
  StringValue(src);
@@ -2068,7 +2209,6 @@ rb_inflate_sync(VALUE obj, VALUE src)
2068
2209
  {
2069
2210
  struct zstream *z = get_zstream(obj);
2070
2211
 
2071
- OBJ_INFECT(obj, src);
2072
2212
  StringValue(src);
2073
2213
  return zstream_sync(z, (Bytef*)RSTRING_PTR(src), RSTRING_LEN(src));
2074
2214
  }
@@ -2110,7 +2250,6 @@ rb_inflate_set_dictionary(VALUE obj, VALUE dic)
2110
2250
  VALUE src = dic;
2111
2251
  int err;
2112
2252
 
2113
- OBJ_INFECT(obj, dic);
2114
2253
  StringValue(src);
2115
2254
  err = inflateSetDictionary(&z->stream,
2116
2255
  (Bytef*)RSTRING_PTR(src), RSTRING_LENINT(src));
@@ -2167,7 +2306,7 @@ rb_inflate_set_dictionary(VALUE obj, VALUE dic)
2167
2306
  #define OS_CODE OS_UNIX
2168
2307
  #endif
2169
2308
 
2170
- static ID id_write, id_read, id_readpartial, id_flush, id_seek, id_close, id_path, id_input;
2309
+ static ID id_write, id_readpartial, id_flush, id_seek, id_close, id_path, id_input;
2171
2310
  static VALUE cGzError, cNoFooter, cCRCError, cLengthError;
2172
2311
 
2173
2312
 
@@ -2191,7 +2330,6 @@ struct gzfile {
2191
2330
  rb_encoding *enc2;
2192
2331
  rb_econv_t *ec;
2193
2332
  VALUE ecopts;
2194
- char *cbuf;
2195
2333
  VALUE path;
2196
2334
  };
2197
2335
  #define GZFILE_CBUF_CAPA 10
@@ -2199,12 +2337,23 @@ struct gzfile {
2199
2337
  #define GZFILE_FLAG_SYNC ZSTREAM_FLAG_UNUSED
2200
2338
  #define GZFILE_FLAG_HEADER_FINISHED (ZSTREAM_FLAG_UNUSED << 1)
2201
2339
  #define GZFILE_FLAG_FOOTER_FINISHED (ZSTREAM_FLAG_UNUSED << 2)
2340
+ #define GZFILE_FLAG_MTIME_IS_SET (ZSTREAM_FLAG_UNUSED << 3)
2202
2341
 
2203
2342
  #define GZFILE_IS_FINISHED(gz) \
2204
2343
  (ZSTREAM_IS_FINISHED(&(gz)->z) && ZSTREAM_BUF_FILLED(&(gz)->z) == 0)
2205
2344
 
2206
2345
  #define GZFILE_READ_SIZE 2048
2207
2346
 
2347
+ struct read_raw_arg {
2348
+ VALUE io;
2349
+ union {
2350
+ const VALUE argv[2]; /* for rb_funcallv */
2351
+ struct {
2352
+ VALUE len;
2353
+ VALUE buf;
2354
+ } in;
2355
+ } as;
2356
+ };
2208
2357
 
2209
2358
  static void
2210
2359
  gzfile_mark(void *p)
@@ -2231,22 +2380,13 @@ gzfile_free(void *p)
2231
2380
  }
2232
2381
  zstream_finalize(z);
2233
2382
  }
2234
- if (gz->cbuf) {
2235
- xfree(gz->cbuf);
2236
- }
2237
2383
  xfree(gz);
2238
2384
  }
2239
2385
 
2240
2386
  static size_t
2241
2387
  gzfile_memsize(const void *p)
2242
2388
  {
2243
- const struct gzfile *gz = p;
2244
- size_t size = sizeof(struct gzfile);
2245
-
2246
- if (gz->cbuf)
2247
- size += GZFILE_CBUF_CAPA;
2248
-
2249
- return size;
2389
+ return sizeof(struct gzfile);
2250
2390
  }
2251
2391
 
2252
2392
  static const rb_data_type_t gzfile_data_type = {
@@ -2275,7 +2415,6 @@ gzfile_init(struct gzfile *gz, const struct zstream_funcs *funcs, void (*endfunc
2275
2415
  gz->ec = NULL;
2276
2416
  gz->ecflags = 0;
2277
2417
  gz->ecopts = Qnil;
2278
- gz->cbuf = 0;
2279
2418
  gz->path = Qnil;
2280
2419
  }
2281
2420
 
@@ -2329,7 +2468,6 @@ gzfile_write_raw(struct gzfile *gz)
2329
2468
 
2330
2469
  if (ZSTREAM_BUF_FILLED(&gz->z) > 0) {
2331
2470
  str = zstream_detach_buffer(&gz->z);
2332
- OBJ_TAINT(str); /* for safe */
2333
2471
  rb_funcall(gz->io, id_write, 1, str);
2334
2472
  if ((gz->z.flags & GZFILE_FLAG_SYNC)
2335
2473
  && rb_respond_to(gz->io, id_flush))
@@ -2340,21 +2478,23 @@ gzfile_write_raw(struct gzfile *gz)
2340
2478
  static VALUE
2341
2479
  gzfile_read_raw_partial(VALUE arg)
2342
2480
  {
2343
- struct gzfile *gz = (struct gzfile*)arg;
2481
+ struct read_raw_arg *ra = (struct read_raw_arg *)arg;
2344
2482
  VALUE str;
2483
+ int argc = NIL_P(ra->as.argv[1]) ? 1 : 2;
2345
2484
 
2346
- str = rb_funcall(gz->io, id_readpartial, 1, INT2FIX(GZFILE_READ_SIZE));
2485
+ str = rb_funcallv(ra->io, id_readpartial, argc, ra->as.argv);
2347
2486
  Check_Type(str, T_STRING);
2348
2487
  return str;
2349
2488
  }
2350
2489
 
2351
2490
  static VALUE
2352
- gzfile_read_raw_rescue(VALUE arg)
2491
+ gzfile_read_raw_rescue(VALUE arg, VALUE _)
2353
2492
  {
2354
- struct gzfile *gz = (struct gzfile*)arg;
2493
+ struct read_raw_arg *ra = (struct read_raw_arg *)arg;
2355
2494
  VALUE str = Qnil;
2356
2495
  if (rb_obj_is_kind_of(rb_errinfo(), rb_eNoMethodError)) {
2357
- str = rb_funcall(gz->io, id_read, 1, INT2FIX(GZFILE_READ_SIZE));
2496
+ int argc = NIL_P(ra->as.argv[1]) ? 1 : 2;
2497
+ str = rb_funcallv(ra->io, id_read, argc, ra->as.argv);
2358
2498
  if (!NIL_P(str)) {
2359
2499
  Check_Type(str, T_STRING);
2360
2500
  }
@@ -2363,15 +2503,21 @@ gzfile_read_raw_rescue(VALUE arg)
2363
2503
  }
2364
2504
 
2365
2505
  static VALUE
2366
- gzfile_read_raw(struct gzfile *gz)
2506
+ gzfile_read_raw(struct gzfile *gz, VALUE outbuf)
2367
2507
  {
2368
- return rb_rescue2(gzfile_read_raw_partial, (VALUE)gz,
2369
- gzfile_read_raw_rescue, (VALUE)gz,
2508
+ struct read_raw_arg ra;
2509
+
2510
+ ra.io = gz->io;
2511
+ ra.as.in.len = INT2FIX(GZFILE_READ_SIZE);
2512
+ ra.as.in.buf = outbuf;
2513
+
2514
+ return rb_rescue2(gzfile_read_raw_partial, (VALUE)&ra,
2515
+ gzfile_read_raw_rescue, (VALUE)&ra,
2370
2516
  rb_eEOFError, rb_eNoMethodError, (VALUE)0);
2371
2517
  }
2372
2518
 
2373
2519
  static int
2374
- gzfile_read_raw_ensure(struct gzfile *gz, long size)
2520
+ gzfile_read_raw_ensure(struct gzfile *gz, long size, VALUE outbuf)
2375
2521
  {
2376
2522
  VALUE str;
2377
2523
 
@@ -2380,7 +2526,7 @@ gzfile_read_raw_ensure(struct gzfile *gz, long size)
2380
2526
  rb_raise(cGzError, "unexpected end of string");
2381
2527
  }
2382
2528
  while (NIL_P(gz->z.input) || RSTRING_LEN(gz->z.input) < size) {
2383
- str = gzfile_read_raw(gz);
2529
+ str = gzfile_read_raw(gz, outbuf);
2384
2530
  if (NIL_P(str)) return 0;
2385
2531
  zstream_append_input2(&gz->z, str);
2386
2532
  }
@@ -2397,7 +2543,7 @@ gzfile_read_raw_until_zero(struct gzfile *gz, long offset)
2397
2543
  p = memchr(RSTRING_PTR(gz->z.input) + offset, '\0',
2398
2544
  RSTRING_LEN(gz->z.input) - offset);
2399
2545
  if (p) break;
2400
- str = gzfile_read_raw(gz);
2546
+ str = gzfile_read_raw(gz, Qnil);
2401
2547
  if (NIL_P(str)) {
2402
2548
  rb_raise(cGzError, "unexpected end of file");
2403
2549
  }
@@ -2478,7 +2624,7 @@ gzfile_make_header(struct gzfile *gz)
2478
2624
  if (!NIL_P(gz->comment)) {
2479
2625
  flags |= GZ_FLAG_COMMENT;
2480
2626
  }
2481
- if (gz->mtime == 0) {
2627
+ if (!(gz->z.flags & GZFILE_FLAG_MTIME_IS_SET)) {
2482
2628
  gz->mtime = time(0);
2483
2629
  }
2484
2630
 
@@ -2522,13 +2668,14 @@ gzfile_make_footer(struct gzfile *gz)
2522
2668
  }
2523
2669
 
2524
2670
  static void
2525
- gzfile_read_header(struct gzfile *gz)
2671
+ gzfile_read_header(struct gzfile *gz, VALUE outbuf)
2526
2672
  {
2527
2673
  const unsigned char *head;
2528
2674
  long len;
2529
2675
  char flags, *p;
2530
2676
 
2531
- if (!gzfile_read_raw_ensure(gz, 10)) { /* 10 is the size of gzip header */
2677
+ /* 10 is the size of gzip header */
2678
+ if (!gzfile_read_raw_ensure(gz, 10, outbuf)) {
2532
2679
  gzfile_raise(gz, cGzError, "not in gzip format");
2533
2680
  }
2534
2681
 
@@ -2567,33 +2714,31 @@ gzfile_read_header(struct gzfile *gz)
2567
2714
  zstream_discard_input(&gz->z, 10);
2568
2715
 
2569
2716
  if (flags & GZ_FLAG_EXTRA) {
2570
- if (!gzfile_read_raw_ensure(gz, 2)) {
2717
+ if (!gzfile_read_raw_ensure(gz, 2, outbuf)) {
2571
2718
  rb_raise(cGzError, "unexpected end of file");
2572
2719
  }
2573
2720
  len = gzfile_get16((Bytef*)RSTRING_PTR(gz->z.input));
2574
- if (!gzfile_read_raw_ensure(gz, 2 + len)) {
2721
+ if (!gzfile_read_raw_ensure(gz, 2 + len, outbuf)) {
2575
2722
  rb_raise(cGzError, "unexpected end of file");
2576
2723
  }
2577
2724
  zstream_discard_input(&gz->z, 2 + len);
2578
2725
  }
2579
2726
  if (flags & GZ_FLAG_ORIG_NAME) {
2580
- if (!gzfile_read_raw_ensure(gz, 1)) {
2727
+ if (!gzfile_read_raw_ensure(gz, 1, outbuf)) {
2581
2728
  rb_raise(cGzError, "unexpected end of file");
2582
2729
  }
2583
2730
  p = gzfile_read_raw_until_zero(gz, 0);
2584
2731
  len = p - RSTRING_PTR(gz->z.input);
2585
2732
  gz->orig_name = rb_str_new(RSTRING_PTR(gz->z.input), len);
2586
- OBJ_TAINT(gz->orig_name); /* for safe */
2587
2733
  zstream_discard_input(&gz->z, len + 1);
2588
2734
  }
2589
2735
  if (flags & GZ_FLAG_COMMENT) {
2590
- if (!gzfile_read_raw_ensure(gz, 1)) {
2736
+ if (!gzfile_read_raw_ensure(gz, 1, outbuf)) {
2591
2737
  rb_raise(cGzError, "unexpected end of file");
2592
2738
  }
2593
2739
  p = gzfile_read_raw_until_zero(gz, 0);
2594
2740
  len = p - RSTRING_PTR(gz->z.input);
2595
2741
  gz->comment = rb_str_new(RSTRING_PTR(gz->z.input), len);
2596
- OBJ_TAINT(gz->comment); /* for safe */
2597
2742
  zstream_discard_input(&gz->z, len + 1);
2598
2743
  }
2599
2744
 
@@ -2603,13 +2748,14 @@ gzfile_read_header(struct gzfile *gz)
2603
2748
  }
2604
2749
 
2605
2750
  static void
2606
- gzfile_check_footer(struct gzfile *gz)
2751
+ gzfile_check_footer(struct gzfile *gz, VALUE outbuf)
2607
2752
  {
2608
2753
  unsigned long crc, length;
2609
2754
 
2610
2755
  gz->z.flags |= GZFILE_FLAG_FOOTER_FINISHED;
2611
2756
 
2612
- if (!gzfile_read_raw_ensure(gz, 8)) { /* 8 is the size of gzip footer */
2757
+ /* 8 is the size of gzip footer */
2758
+ if (!gzfile_read_raw_ensure(gz, 8, outbuf)) {
2613
2759
  gzfile_raise(gz, cNoFooter, "footer is not found");
2614
2760
  }
2615
2761
 
@@ -2643,12 +2789,12 @@ gzfile_write(struct gzfile *gz, Bytef *str, long len)
2643
2789
  }
2644
2790
 
2645
2791
  static long
2646
- gzfile_read_more(struct gzfile *gz)
2792
+ gzfile_read_more(struct gzfile *gz, VALUE outbuf)
2647
2793
  {
2648
2794
  VALUE str;
2649
2795
 
2650
2796
  while (!ZSTREAM_IS_FINISHED(&gz->z)) {
2651
- str = gzfile_read_raw(gz);
2797
+ str = gzfile_read_raw(gz, outbuf);
2652
2798
  if (NIL_P(str)) {
2653
2799
  if (!ZSTREAM_IS_FINISHED(&gz->z)) {
2654
2800
  rb_raise(cGzError, "unexpected end of file");
@@ -2673,7 +2819,7 @@ gzfile_calc_crc(struct gzfile *gz, VALUE str)
2673
2819
  }
2674
2820
  else {
2675
2821
  gz->crc = checksum_long(crc32, gz->crc, (Bytef*)RSTRING_PTR(str) + gz->ungetc,
2676
- RSTRING_LEN(str) - gz->ungetc);
2822
+ RSTRING_LEN(str) - gz->ungetc);
2677
2823
  gz->ungetc = 0;
2678
2824
  }
2679
2825
  }
@@ -2683,13 +2829,11 @@ gzfile_newstr(struct gzfile *gz, VALUE str)
2683
2829
  {
2684
2830
  if (!gz->enc2) {
2685
2831
  rb_enc_associate(str, gz->enc);
2686
- OBJ_TAINT(str); /* for safe */
2687
2832
  return str;
2688
2833
  }
2689
2834
  if (gz->ec && rb_enc_dummy_p(gz->enc2)) {
2690
2835
  str = rb_econv_str_convert(gz->ec, str, ECONV_PARTIAL_INPUT);
2691
2836
  rb_enc_associate(str, gz->enc);
2692
- OBJ_TAINT(str);
2693
2837
  return str;
2694
2838
  }
2695
2839
  return rb_str_conv_enc_opts(str, gz->enc2, gz->enc,
@@ -2704,11 +2848,11 @@ gzfile_fill(struct gzfile *gz, long len)
2704
2848
  if (len == 0)
2705
2849
  return 0;
2706
2850
  while (!ZSTREAM_IS_FINISHED(&gz->z) && ZSTREAM_BUF_FILLED(&gz->z) < len) {
2707
- gzfile_read_more(gz);
2851
+ gzfile_read_more(gz, Qnil);
2708
2852
  }
2709
2853
  if (GZFILE_IS_FINISHED(gz)) {
2710
2854
  if (!(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) {
2711
- gzfile_check_footer(gz);
2855
+ gzfile_check_footer(gz, Qnil);
2712
2856
  }
2713
2857
  return -1;
2714
2858
  }
@@ -2736,9 +2880,6 @@ gzfile_readpartial(struct gzfile *gz, long len, VALUE outbuf)
2736
2880
  if (len < 0)
2737
2881
  rb_raise(rb_eArgError, "negative length %ld given", len);
2738
2882
 
2739
- if (!NIL_P(outbuf))
2740
- OBJ_TAINT(outbuf);
2741
-
2742
2883
  if (len == 0) {
2743
2884
  if (NIL_P(outbuf))
2744
2885
  return rb_str_new(0, 0);
@@ -2748,11 +2889,11 @@ gzfile_readpartial(struct gzfile *gz, long len, VALUE outbuf)
2748
2889
  }
2749
2890
  }
2750
2891
  while (!ZSTREAM_IS_FINISHED(&gz->z) && ZSTREAM_BUF_FILLED(&gz->z) == 0) {
2751
- gzfile_read_more(gz);
2892
+ gzfile_read_more(gz, outbuf);
2752
2893
  }
2753
2894
  if (GZFILE_IS_FINISHED(gz)) {
2754
2895
  if (!(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) {
2755
- gzfile_check_footer(gz);
2896
+ gzfile_check_footer(gz, outbuf);
2756
2897
  }
2757
2898
  if (!NIL_P(outbuf))
2758
2899
  rb_str_resize(outbuf, 0);
@@ -2765,10 +2906,10 @@ gzfile_readpartial(struct gzfile *gz, long len, VALUE outbuf)
2765
2906
  if (!NIL_P(outbuf)) {
2766
2907
  rb_str_resize(outbuf, RSTRING_LEN(dst));
2767
2908
  memcpy(RSTRING_PTR(outbuf), RSTRING_PTR(dst), RSTRING_LEN(dst));
2768
- RB_GC_GUARD(dst);
2909
+ rb_str_resize(dst, 0);
2910
+ rb_gc_force_recycle(dst);
2769
2911
  dst = outbuf;
2770
2912
  }
2771
- OBJ_TAINT(dst); /* for safe */
2772
2913
  return dst;
2773
2914
  }
2774
2915
 
@@ -2778,11 +2919,11 @@ gzfile_read_all(struct gzfile *gz)
2778
2919
  VALUE dst;
2779
2920
 
2780
2921
  while (!ZSTREAM_IS_FINISHED(&gz->z)) {
2781
- gzfile_read_more(gz);
2922
+ gzfile_read_more(gz, Qnil);
2782
2923
  }
2783
2924
  if (GZFILE_IS_FINISHED(gz)) {
2784
2925
  if (!(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) {
2785
- gzfile_check_footer(gz);
2926
+ gzfile_check_footer(gz, Qnil);
2786
2927
  }
2787
2928
  return rb_str_new(0, 0);
2788
2929
  }
@@ -2790,7 +2931,6 @@ gzfile_read_all(struct gzfile *gz)
2790
2931
  dst = zstream_detach_buffer(&gz->z);
2791
2932
  if (NIL_P(dst)) return dst;
2792
2933
  gzfile_calc_crc(gz, dst);
2793
- OBJ_TAINT(dst);
2794
2934
  return gzfile_newstr(gz, dst);
2795
2935
  }
2796
2936
 
@@ -2802,11 +2942,11 @@ gzfile_getc(struct gzfile *gz)
2802
2942
 
2803
2943
  len = rb_enc_mbmaxlen(gz->enc);
2804
2944
  while (!ZSTREAM_IS_FINISHED(&gz->z) && ZSTREAM_BUF_FILLED(&gz->z) < len) {
2805
- gzfile_read_more(gz);
2945
+ gzfile_read_more(gz, Qnil);
2806
2946
  }
2807
2947
  if (GZFILE_IS_FINISHED(gz)) {
2808
2948
  if (!(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) {
2809
- gzfile_check_footer(gz);
2949
+ gzfile_check_footer(gz, Qnil);
2810
2950
  }
2811
2951
  return Qnil;
2812
2952
  }
@@ -2814,22 +2954,18 @@ gzfile_getc(struct gzfile *gz)
2814
2954
  if (gz->ec && rb_enc_dummy_p(gz->enc2)) {
2815
2955
  const unsigned char *ss, *sp, *se;
2816
2956
  unsigned char *ds, *dp, *de;
2957
+ VALUE cbuf = rb_enc_str_new(0, GZFILE_CBUF_CAPA, gz->enc);
2817
2958
 
2818
- if (!gz->cbuf) {
2819
- gz->cbuf = ALLOC_N(char, GZFILE_CBUF_CAPA);
2820
- }
2821
2959
  ss = sp = (const unsigned char*)RSTRING_PTR(gz->z.buf);
2822
2960
  se = sp + ZSTREAM_BUF_FILLED(&gz->z);
2823
- ds = dp = (unsigned char *)gz->cbuf;
2961
+ ds = dp = (unsigned char *)RSTRING_PTR(cbuf);
2824
2962
  de = (unsigned char *)ds + GZFILE_CBUF_CAPA;
2825
2963
  (void)rb_econv_convert(gz->ec, &sp, se, &dp, de, ECONV_PARTIAL_INPUT|ECONV_AFTER_OUTPUT);
2826
2964
  rb_econv_check_error(gz->ec);
2827
2965
  dst = zstream_shift_buffer(&gz->z, sp - ss);
2828
2966
  gzfile_calc_crc(gz, dst);
2829
- dst = rb_str_new(gz->cbuf, dp - ds);
2830
- rb_enc_associate(dst, gz->enc);
2831
- OBJ_TAINT(dst);
2832
- return dst;
2967
+ rb_str_resize(cbuf, dp - ds);
2968
+ return cbuf;
2833
2969
  }
2834
2970
  else {
2835
2971
  buf = gz->z.buf;
@@ -2876,7 +3012,7 @@ gzfile_writer_end(struct gzfile *gz)
2876
3012
  if (ZSTREAM_IS_CLOSING(&gz->z)) return;
2877
3013
  gz->z.flags |= ZSTREAM_FLAG_CLOSING;
2878
3014
 
2879
- rb_ensure(gzfile_writer_end_run, (VALUE)gz, zstream_end, (VALUE)&gz->z);
3015
+ rb_ensure(gzfile_writer_end_run, (VALUE)gz, zstream_ensure_end, (VALUE)&gz->z);
2880
3016
  }
2881
3017
 
2882
3018
  static VALUE
@@ -2886,7 +3022,7 @@ gzfile_reader_end_run(VALUE arg)
2886
3022
 
2887
3023
  if (GZFILE_IS_FINISHED(gz)
2888
3024
  && !(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) {
2889
- gzfile_check_footer(gz);
3025
+ gzfile_check_footer(gz, Qnil);
2890
3026
  }
2891
3027
 
2892
3028
  return Qnil;
@@ -2898,7 +3034,7 @@ gzfile_reader_end(struct gzfile *gz)
2898
3034
  if (ZSTREAM_IS_CLOSING(&gz->z)) return;
2899
3035
  gz->z.flags |= ZSTREAM_FLAG_CLOSING;
2900
3036
 
2901
- rb_ensure(gzfile_reader_end_run, (VALUE)gz, zstream_end, (VALUE)&gz->z);
3037
+ rb_ensure(gzfile_reader_end_run, (VALUE)gz, zstream_ensure_end, (VALUE)&gz->z);
2902
3038
  }
2903
3039
 
2904
3040
  static void
@@ -2923,12 +3059,11 @@ gzfile_reader_get_unused(struct gzfile *gz)
2923
3059
  if (!ZSTREAM_IS_READY(&gz->z)) return Qnil;
2924
3060
  if (!GZFILE_IS_FINISHED(gz)) return Qnil;
2925
3061
  if (!(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) {
2926
- gzfile_check_footer(gz);
3062
+ gzfile_check_footer(gz, Qnil);
2927
3063
  }
2928
3064
  if (NIL_P(gz->z.input)) return Qnil;
2929
3065
 
2930
3066
  str = rb_str_resurrect(gz->z.input);
2931
- OBJ_TAINT(str); /* for safe */
2932
3067
  return str;
2933
3068
  }
2934
3069
 
@@ -2995,7 +3130,7 @@ static VALUE
2995
3130
  new_wrap(VALUE tmp)
2996
3131
  {
2997
3132
  new_wrap_arg_t *arg = (new_wrap_arg_t *)tmp;
2998
- return rb_class_new_instance(arg->argc, arg->argv, arg->klass);
3133
+ return rb_class_new_instance_kw(arg->argc, arg->argv, arg->klass, RB_PASS_CALLED_KEYWORDS);
2999
3134
  }
3000
3135
 
3001
3136
  static VALUE
@@ -3028,7 +3163,7 @@ gzfile_wrap(int argc, VALUE *argv, VALUE klass, int close_io_on_error)
3028
3163
  }
3029
3164
  }
3030
3165
  else {
3031
- obj = rb_class_new_instance(argc, argv, klass);
3166
+ obj = rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
3032
3167
  }
3033
3168
 
3034
3169
  if (rb_block_given_p()) {
@@ -3145,7 +3280,6 @@ rb_gzfile_orig_name(VALUE obj)
3145
3280
  if (!NIL_P(str)) {
3146
3281
  str = rb_str_dup(str);
3147
3282
  }
3148
- OBJ_TAINT(str); /* for safe */
3149
3283
  return str;
3150
3284
  }
3151
3285
 
@@ -3162,7 +3296,6 @@ rb_gzfile_comment(VALUE obj)
3162
3296
  if (!NIL_P(str)) {
3163
3297
  str = rb_str_dup(str);
3164
3298
  }
3165
- OBJ_TAINT(str); /* for safe */
3166
3299
  return str;
3167
3300
  }
3168
3301
 
@@ -3221,6 +3354,7 @@ rb_gzfile_set_mtime(VALUE obj, VALUE mtime)
3221
3354
 
3222
3355
  val = rb_Integer(mtime);
3223
3356
  gz->mtime = NUM2UINT(val);
3357
+ gz->z.flags |= GZFILE_FLAG_MTIME_IS_SET;
3224
3358
 
3225
3359
  return mtime;
3226
3360
  }
@@ -3419,6 +3553,16 @@ rb_gzfile_path(VALUE obj)
3419
3553
  return gz->path;
3420
3554
  }
3421
3555
 
3556
+ static VALUE
3557
+ gzfile_initialize_path_partial(VALUE obj)
3558
+ {
3559
+ struct gzfile* gz;
3560
+ TypedData_Get_Struct(obj, struct gzfile, &gzfile_data_type, gz);
3561
+ gz->path = rb_funcall(gz->io, id_path, 0);
3562
+ rb_define_singleton_method(obj, "path", rb_gzfile_path, 0);
3563
+ return Qnil;
3564
+ }
3565
+
3422
3566
  static void
3423
3567
  rb_gzfile_ecopts(struct gzfile *gz, VALUE opts)
3424
3568
  {
@@ -3527,8 +3671,8 @@ rb_gzwriter_initialize(int argc, VALUE *argv, VALUE obj)
3527
3671
  rb_gzfile_ecopts(gz, opt);
3528
3672
 
3529
3673
  if (rb_respond_to(io, id_path)) {
3530
- gz->path = rb_funcall(gz->io, id_path, 0);
3531
- rb_define_singleton_method(obj, "path", rb_gzfile_path, 0);
3674
+ /* File#path may raise IOError in case when a path is unavailable */
3675
+ rb_rescue2(gzfile_initialize_path_partial, obj, NULL, Qnil, rb_eIOError, (VALUE)0);
3532
3676
  }
3533
3677
 
3534
3678
  return obj;
@@ -3566,18 +3710,23 @@ rb_gzwriter_flush(int argc, VALUE *argv, VALUE obj)
3566
3710
  * Same as IO.
3567
3711
  */
3568
3712
  static VALUE
3569
- rb_gzwriter_write(VALUE obj, VALUE str)
3713
+ rb_gzwriter_write(int argc, VALUE *argv, VALUE obj)
3570
3714
  {
3571
3715
  struct gzfile *gz = get_gzfile(obj);
3572
-
3573
- if (!RB_TYPE_P(str, T_STRING))
3574
- str = rb_obj_as_string(str);
3575
- if (gz->enc2 && gz->enc2 != rb_ascii8bit_encoding()) {
3576
- str = rb_str_conv_enc(str, rb_enc_get(str), gz->enc2);
3716
+ size_t total = 0;
3717
+
3718
+ while (argc-- > 0) {
3719
+ VALUE str = *argv++;
3720
+ if (!RB_TYPE_P(str, T_STRING))
3721
+ str = rb_obj_as_string(str);
3722
+ if (gz->enc2 && gz->enc2 != rb_ascii8bit_encoding()) {
3723
+ str = rb_str_conv_enc(str, rb_enc_get(str), gz->enc2);
3724
+ }
3725
+ gzfile_write(gz, (Bytef*)RSTRING_PTR(str), RSTRING_LEN(str));
3726
+ total += RSTRING_LEN(str);
3727
+ RB_GC_GUARD(str);
3577
3728
  }
3578
- gzfile_write(gz, (Bytef*)RSTRING_PTR(str), RSTRING_LEN(str));
3579
- RB_GC_GUARD(str);
3580
- return INT2FIX(RSTRING_LEN(str));
3729
+ return SIZET2NUM(total);
3581
3730
  }
3582
3731
 
3583
3732
  /*
@@ -3692,6 +3841,60 @@ rb_gzreader_s_open(int argc, VALUE *argv, VALUE klass)
3692
3841
  return gzfile_s_open(argc, argv, klass, "rb");
3693
3842
  }
3694
3843
 
3844
+ /*
3845
+ * Document-method: Zlib::GzipReader.zcat
3846
+ *
3847
+ * call-seq:
3848
+ * Zlib::GzipReader.zcat(io, options = {}, &block) => nil
3849
+ * Zlib::GzipReader.zcat(io, options = {}) => string
3850
+ *
3851
+ * Decompresses all gzip data in the +io+, handling multiple gzip
3852
+ * streams until the end of the +io+. There should not be any non-gzip
3853
+ * data after the gzip streams.
3854
+ *
3855
+ * If a block is given, it is yielded strings of uncompressed data,
3856
+ * and the method returns +nil+.
3857
+ * If a block is not given, the method returns the concatenation of
3858
+ * all uncompressed data in all gzip streams.
3859
+ */
3860
+ static VALUE
3861
+ rb_gzreader_s_zcat(int argc, VALUE *argv, VALUE klass)
3862
+ {
3863
+ VALUE io, unused, obj, buf=0, tmpbuf;
3864
+ long pos;
3865
+
3866
+ rb_check_arity(argc, 1, 2);
3867
+ io = argv[0];
3868
+
3869
+ do {
3870
+ obj = rb_funcallv(klass, rb_intern("new"), argc, argv);
3871
+ if (rb_block_given_p()) {
3872
+ rb_gzreader_each(0, 0, obj);
3873
+ }
3874
+ else {
3875
+ if (!buf) {
3876
+ buf = rb_str_new(0, 0);
3877
+ }
3878
+ tmpbuf = gzfile_read_all(get_gzfile(obj));
3879
+ rb_str_cat(buf, RSTRING_PTR(tmpbuf), RSTRING_LEN(tmpbuf));
3880
+ }
3881
+
3882
+ rb_gzreader_read(0, 0, obj);
3883
+ pos = NUM2LONG(rb_funcall(io, rb_intern("pos"), 0));
3884
+ unused = rb_gzreader_unused(obj);
3885
+ rb_gzfile_finish(obj);
3886
+ if (!NIL_P(unused)) {
3887
+ pos -= NUM2LONG(rb_funcall(unused, rb_intern("length"), 0));
3888
+ rb_funcall(io, rb_intern("pos="), 1, LONG2NUM(pos));
3889
+ }
3890
+ } while (pos < NUM2LONG(rb_funcall(io, rb_intern("size"), 0)));
3891
+
3892
+ if (rb_block_given_p()) {
3893
+ return Qnil;
3894
+ }
3895
+ return buf;
3896
+ }
3897
+
3695
3898
  /*
3696
3899
  * Document-method: Zlib::GzipReader.new
3697
3900
  *
@@ -3726,12 +3929,12 @@ rb_gzreader_initialize(int argc, VALUE *argv, VALUE obj)
3726
3929
  }
3727
3930
  gz->io = io;
3728
3931
  ZSTREAM_READY(&gz->z);
3729
- gzfile_read_header(gz);
3932
+ gzfile_read_header(gz, Qnil);
3730
3933
  rb_gzfile_ecopts(gz, opt);
3731
3934
 
3732
3935
  if (rb_respond_to(io, id_path)) {
3733
- gz->path = rb_funcall(gz->io, id_path, 0);
3734
- rb_define_singleton_method(obj, "path", rb_gzfile_path, 0);
3936
+ /* File#path may raise IOError in case when a path is unavailable */
3937
+ rb_rescue2(gzfile_initialize_path_partial, obj, NULL, Qnil, rb_eIOError, (VALUE)0);
3735
3938
  }
3736
3939
 
3737
3940
  return obj;
@@ -3918,20 +4121,6 @@ rb_gzreader_each_byte(VALUE obj)
3918
4121
  return Qnil;
3919
4122
  }
3920
4123
 
3921
- /*
3922
- * Document-method: Zlib::GzipReader#bytes
3923
- *
3924
- * This is a deprecated alias for <code>each_byte</code>.
3925
- */
3926
- static VALUE
3927
- rb_gzreader_bytes(VALUE obj)
3928
- {
3929
- rb_warn("Zlib::GzipReader#bytes is deprecated; use #each_byte instead");
3930
- if (!rb_block_given_p())
3931
- return rb_enumeratorize(obj, ID2SYM(rb_intern("each_byte")), 0, 0);
3932
- return rb_gzreader_each_byte(obj);
3933
- }
3934
-
3935
4124
  /*
3936
4125
  * Document-method: Zlib::GzipReader#ungetc
3937
4126
  *
@@ -3976,7 +4165,7 @@ gzreader_skip_linebreaks(struct gzfile *gz)
3976
4165
 
3977
4166
  while (ZSTREAM_BUF_FILLED(&gz->z) == 0) {
3978
4167
  if (GZFILE_IS_FINISHED(gz)) return;
3979
- gzfile_read_more(gz);
4168
+ gzfile_read_more(gz, Qnil);
3980
4169
  }
3981
4170
  n = 0;
3982
4171
  p = RSTRING_PTR(gz->z.buf);
@@ -3987,7 +4176,7 @@ gzreader_skip_linebreaks(struct gzfile *gz)
3987
4176
  gzfile_calc_crc(gz, str);
3988
4177
  while (ZSTREAM_BUF_FILLED(&gz->z) == 0) {
3989
4178
  if (GZFILE_IS_FINISHED(gz)) return;
3990
- gzfile_read_more(gz);
4179
+ gzfile_read_more(gz, Qnil);
3991
4180
  }
3992
4181
  n = 0;
3993
4182
  p = RSTRING_PTR(gz->z.buf);
@@ -4109,7 +4298,7 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj)
4109
4298
  if (ZSTREAM_BUF_FILLED(&gz->z) > 0) gz->lineno++;
4110
4299
  return gzfile_read(gz, rslen);
4111
4300
  }
4112
- gzfile_read_more(gz);
4301
+ gzfile_read_more(gz, Qnil);
4113
4302
  }
4114
4303
 
4115
4304
  p = RSTRING_PTR(gz->z.buf);
@@ -4118,7 +4307,7 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj)
4118
4307
  long filled;
4119
4308
  if (n > ZSTREAM_BUF_FILLED(&gz->z)) {
4120
4309
  if (ZSTREAM_IS_FINISHED(&gz->z)) break;
4121
- gzfile_read_more(gz);
4310
+ gzfile_read_more(gz, Qnil);
4122
4311
  p = RSTRING_PTR(gz->z.buf) + n - rslen;
4123
4312
  }
4124
4313
  if (!rspara) rscheck(rsptr, rslen, rs);
@@ -4158,6 +4347,8 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj)
4158
4347
  * Document-method: Zlib::GzipReader#gets
4159
4348
  *
4160
4349
  * See Zlib::GzipReader documentation for a description.
4350
+ * However, note that this method can return +nil+ even if
4351
+ * #eof? returns false, unlike the behavior of File#gets.
4161
4352
  */
4162
4353
  static VALUE
4163
4354
  rb_gzreader_gets(int argc, VALUE *argv, VALUE obj)
@@ -4204,20 +4395,6 @@ rb_gzreader_each(int argc, VALUE *argv, VALUE obj)
4204
4395
  return obj;
4205
4396
  }
4206
4397
 
4207
- /*
4208
- * Document-method: Zlib::GzipReader#lines
4209
- *
4210
- * This is a deprecated alias for <code>each_line</code>.
4211
- */
4212
- static VALUE
4213
- rb_gzreader_lines(int argc, VALUE *argv, VALUE obj)
4214
- {
4215
- rb_warn("Zlib::GzipReader#lines is deprecated; use #each_line instead");
4216
- if (!rb_block_given_p())
4217
- return rb_enumeratorize(obj, ID2SYM(rb_intern("each_line")), argc, argv);
4218
- return rb_gzreader_each(argc, argv, obj);
4219
- }
4220
-
4221
4398
  /*
4222
4399
  * Document-method: Zlib::GzipReader#readlines
4223
4400
  *
@@ -4245,6 +4422,20 @@ rb_gzreader_external_encoding(VALUE self)
4245
4422
  return rb_enc_from_encoding(get_gzfile(self)->enc);
4246
4423
  }
4247
4424
 
4425
+ static VALUE
4426
+ zlib_gzip_end_rescue(VALUE arg)
4427
+ {
4428
+ struct gzfile *gz = (struct gzfile *)arg;
4429
+ gz->end(gz);
4430
+ return Qnil;
4431
+ }
4432
+
4433
+ static VALUE
4434
+ zlib_gzip_ensure(VALUE arg)
4435
+ {
4436
+ return rb_rescue(zlib_gzip_end_rescue, arg, NULL, Qnil);
4437
+ }
4438
+
4248
4439
  static void
4249
4440
  zlib_gzip_end(struct gzfile *gz)
4250
4441
  {
@@ -4254,9 +4445,8 @@ zlib_gzip_end(struct gzfile *gz)
4254
4445
  zstream_end(&gz->z);
4255
4446
  }
4256
4447
 
4257
- #define OPTHASH_GIVEN_P(opts) \
4258
- (argc > 0 && !NIL_P((opts) = rb_check_hash_type(argv[argc-1])) && (--argc, 1))
4259
4448
  static ID id_level, id_strategy;
4449
+ static VALUE zlib_gzip_run(VALUE arg);
4260
4450
 
4261
4451
  /*
4262
4452
  * call-seq:
@@ -4285,9 +4475,8 @@ zlib_s_gzip(int argc, VALUE *argv, VALUE klass)
4285
4475
  {
4286
4476
  struct gzfile gz0;
4287
4477
  struct gzfile *gz = &gz0;
4288
- long len;
4289
4478
  int err;
4290
- VALUE src, opts, level=Qnil, strategy=Qnil;
4479
+ VALUE src, opts, level=Qnil, strategy=Qnil, args[2];
4291
4480
 
4292
4481
  if (OPTHASH_GIVEN_P(opts)) {
4293
4482
  ID keyword_ids[2];
@@ -4309,9 +4498,23 @@ zlib_s_gzip(int argc, VALUE *argv, VALUE klass)
4309
4498
  err = deflateInit2(&gz->z.stream, gz->level, Z_DEFLATED,
4310
4499
  -MAX_WBITS, DEF_MEM_LEVEL, ARG_STRATEGY(strategy));
4311
4500
  if (err != Z_OK) {
4501
+ zlib_gzip_end(gz);
4312
4502
  raise_zlib_error(err, gz->z.stream.msg);
4313
4503
  }
4314
4504
  ZSTREAM_READY(&gz->z);
4505
+ args[0] = (VALUE)gz;
4506
+ args[1] = src;
4507
+ return rb_ensure(zlib_gzip_run, (VALUE)args, zlib_gzip_ensure, (VALUE)gz);
4508
+ }
4509
+
4510
+ static VALUE
4511
+ zlib_gzip_run(VALUE arg)
4512
+ {
4513
+ VALUE *args = (VALUE *)arg;
4514
+ struct gzfile *gz = (struct gzfile *)args[0];
4515
+ VALUE src = args[1];
4516
+ long len;
4517
+
4315
4518
  gzfile_make_header(gz);
4316
4519
  len = RSTRING_LEN(src);
4317
4520
  if (len > 0) {
@@ -4327,10 +4530,11 @@ static void
4327
4530
  zlib_gunzip_end(struct gzfile *gz)
4328
4531
  {
4329
4532
  gz->z.flags |= ZSTREAM_FLAG_CLOSING;
4330
- gzfile_check_footer(gz);
4331
4533
  zstream_end(&gz->z);
4332
4534
  }
4333
4535
 
4536
+ static VALUE zlib_gunzip_run(VALUE arg);
4537
+
4334
4538
  /*
4335
4539
  * call-seq:
4336
4540
  * Zlib.gunzip(src) -> String
@@ -4355,7 +4559,6 @@ zlib_gunzip(VALUE klass, VALUE src)
4355
4559
  struct gzfile gz0;
4356
4560
  struct gzfile *gz = &gz0;
4357
4561
  int err;
4358
- VALUE dst;
4359
4562
 
4360
4563
  StringValue(src);
4361
4564
 
@@ -4367,15 +4570,25 @@ zlib_gunzip(VALUE klass, VALUE src)
4367
4570
  gz->io = Qundef;
4368
4571
  gz->z.input = src;
4369
4572
  ZSTREAM_READY(&gz->z);
4370
- gzfile_read_header(gz);
4573
+ return rb_ensure(zlib_gunzip_run, (VALUE)gz, zlib_gzip_ensure, (VALUE)gz);
4574
+ }
4575
+
4576
+ static VALUE
4577
+ zlib_gunzip_run(VALUE arg)
4578
+ {
4579
+ struct gzfile *gz = (struct gzfile *)arg;
4580
+ VALUE dst;
4581
+
4582
+ gzfile_read_header(gz, Qnil);
4371
4583
  dst = zstream_detach_buffer(&gz->z);
4372
4584
  gzfile_calc_crc(gz, dst);
4373
- if (!ZSTREAM_IS_FINISHED(&gz->z)) {
4374
- rb_raise(cGzError, "unexpected end of file");
4375
- }
4376
- if (NIL_P(gz->z.input))
4585
+ if (!ZSTREAM_IS_FINISHED(&gz->z)) {
4586
+ rb_raise(cGzError, "unexpected end of file");
4587
+ }
4588
+ if (NIL_P(gz->z.input)) {
4377
4589
  rb_raise(cNoFooter, "footer is not found");
4378
- gzfile_check_footer(gz);
4590
+ }
4591
+ gzfile_check_footer(gz, Qnil);
4379
4592
  return dst;
4380
4593
  }
4381
4594
 
@@ -4384,6 +4597,11 @@ zlib_gunzip(VALUE klass, VALUE src)
4384
4597
  void
4385
4598
  Init_zlib(void)
4386
4599
  {
4600
+ #ifdef HAVE_RB_EXT_RACTOR_SAFE
4601
+ rb_ext_ractor_safe(true);
4602
+ #endif
4603
+
4604
+ #undef rb_intern
4387
4605
  VALUE mZlib, cZStream, cDeflate, cInflate;
4388
4606
  #if GZIP_SUPPORT
4389
4607
  VALUE cGzipFile, cGzipWriter, cGzipReader;
@@ -4477,7 +4695,7 @@ Init_zlib(void)
4477
4695
  rb_define_alloc_func(cInflate, rb_inflate_s_allocate);
4478
4696
  rb_define_method(cInflate, "initialize", rb_inflate_initialize, -1);
4479
4697
  rb_define_method(cInflate, "add_dictionary", rb_inflate_add_dictionary, 1);
4480
- rb_define_method(cInflate, "inflate", rb_inflate_inflate, 1);
4698
+ rb_define_method(cInflate, "inflate", rb_inflate_inflate, -1);
4481
4699
  rb_define_method(cInflate, "<<", rb_inflate_addstr, 1);
4482
4700
  rb_define_method(cInflate, "sync", rb_inflate_sync, 1);
4483
4701
  rb_define_method(cInflate, "sync_point?", rb_inflate_sync_point_p, 0);
@@ -4618,7 +4836,7 @@ Init_zlib(void)
4618
4836
  rb_define_alloc_func(cGzipWriter, rb_gzwriter_s_allocate);
4619
4837
  rb_define_method(cGzipWriter, "initialize", rb_gzwriter_initialize,-1);
4620
4838
  rb_define_method(cGzipWriter, "flush", rb_gzwriter_flush, -1);
4621
- rb_define_method(cGzipWriter, "write", rb_gzwriter_write, 1);
4839
+ rb_define_method(cGzipWriter, "write", rb_gzwriter_write, -1);
4622
4840
  rb_define_method(cGzipWriter, "putc", rb_gzwriter_putc, 1);
4623
4841
  rb_define_method(cGzipWriter, "<<", rb_gzwriter_addstr, 1);
4624
4842
  rb_define_method(cGzipWriter, "printf", rb_gzwriter_printf, -1);
@@ -4626,6 +4844,7 @@ Init_zlib(void)
4626
4844
  rb_define_method(cGzipWriter, "puts", rb_gzwriter_puts, -1);
4627
4845
 
4628
4846
  rb_define_singleton_method(cGzipReader, "open", rb_gzreader_s_open,-1);
4847
+ rb_define_singleton_method(cGzipReader, "zcat", rb_gzreader_s_zcat, -1);
4629
4848
  rb_define_alloc_func(cGzipReader, rb_gzreader_s_allocate);
4630
4849
  rb_define_method(cGzipReader, "initialize", rb_gzreader_initialize, -1);
4631
4850
  rb_define_method(cGzipReader, "rewind", rb_gzreader_rewind, 0);
@@ -4638,14 +4857,12 @@ Init_zlib(void)
4638
4857
  rb_define_method(cGzipReader, "readbyte", rb_gzreader_readbyte, 0);
4639
4858
  rb_define_method(cGzipReader, "each_byte", rb_gzreader_each_byte, 0);
4640
4859
  rb_define_method(cGzipReader, "each_char", rb_gzreader_each_char, 0);
4641
- rb_define_method(cGzipReader, "bytes", rb_gzreader_bytes, 0);
4642
4860
  rb_define_method(cGzipReader, "ungetc", rb_gzreader_ungetc, 1);
4643
4861
  rb_define_method(cGzipReader, "ungetbyte", rb_gzreader_ungetbyte, 1);
4644
4862
  rb_define_method(cGzipReader, "gets", rb_gzreader_gets, -1);
4645
4863
  rb_define_method(cGzipReader, "readline", rb_gzreader_readline, -1);
4646
4864
  rb_define_method(cGzipReader, "each", rb_gzreader_each, -1);
4647
4865
  rb_define_method(cGzipReader, "each_line", rb_gzreader_each, -1);
4648
- rb_define_method(cGzipReader, "lines", rb_gzreader_lines, -1);
4649
4866
  rb_define_method(cGzipReader, "readlines", rb_gzreader_readlines, -1);
4650
4867
  rb_define_method(cGzipReader, "external_encoding", rb_gzreader_external_encoding, 0);
4651
4868
 
@@ -4687,6 +4904,7 @@ Init_zlib(void)
4687
4904
 
4688
4905
  id_level = rb_intern("level");
4689
4906
  id_strategy = rb_intern("strategy");
4907
+ id_buffer = rb_intern("buffer");
4690
4908
  #endif /* GZIP_SUPPORT */
4691
4909
  }
4692
4910
 
@@ -4807,5 +5025,3 @@ Init_zlib(void)
4807
5025
  * Raised when the data length recorded in the gzip file footer is not equivalent
4808
5026
  * to the length of the actual uncompressed data.
4809
5027
  */
4810
-
4811
-