zlib 0.0.1 → 2.0.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.0.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
 
@@ -72,6 +79,7 @@ struct zstream_run_args;
72
79
  static void zstream_init(struct zstream*, const struct zstream_funcs*);
73
80
  static void zstream_expand_buffer(struct zstream*);
74
81
  static void zstream_expand_buffer_into(struct zstream*, unsigned long);
82
+ static int zstream_expand_buffer_non_stream(struct zstream *z);
75
83
  static void zstream_append_buffer(struct zstream*, const Bytef*, long);
76
84
  static VALUE zstream_detach_buffer(struct zstream*);
77
85
  static VALUE zstream_shift_buffer(struct zstream*, long);
@@ -84,6 +92,7 @@ static void zstream_passthrough_input(struct zstream*);
84
92
  static VALUE zstream_detach_input(struct zstream*);
85
93
  static void zstream_reset(struct zstream*);
86
94
  static VALUE zstream_end(struct zstream*);
95
+ static VALUE zstream_ensure_end(VALUE v);
87
96
  static void zstream_run(struct zstream*, Bytef*, long, int);
88
97
  static VALUE zstream_sync(struct zstream*, Bytef*, long);
89
98
  static void zstream_mark(void*);
@@ -124,7 +133,7 @@ static VALUE rb_inflate_s_allocate(VALUE);
124
133
  static VALUE rb_inflate_initialize(int, VALUE*, VALUE);
125
134
  static VALUE rb_inflate_s_inflate(VALUE, VALUE);
126
135
  static void do_inflate(struct zstream*, VALUE);
127
- static VALUE rb_inflate_inflate(VALUE, VALUE);
136
+ static VALUE rb_inflate_inflate(int, VALUE*, VALUE);
128
137
  static VALUE rb_inflate_addstr(VALUE, VALUE);
129
138
  static VALUE rb_inflate_sync(VALUE, VALUE);
130
139
  static VALUE rb_inflate_sync_point_p(VALUE);
@@ -139,19 +148,19 @@ static void gzfile_reset(struct gzfile*);
139
148
  static void gzfile_close(struct gzfile*, int);
140
149
  static void gzfile_write_raw(struct gzfile*);
141
150
  static VALUE gzfile_read_raw_partial(VALUE);
142
- static VALUE gzfile_read_raw_rescue(VALUE);
143
- static VALUE gzfile_read_raw(struct gzfile*);
144
- 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);
145
154
  static char *gzfile_read_raw_until_zero(struct gzfile*, long);
146
155
  static unsigned int gzfile_get16(const unsigned char*);
147
156
  static unsigned long gzfile_get32(const unsigned char*);
148
157
  static void gzfile_set32(unsigned long n, unsigned char*);
149
158
  static void gzfile_make_header(struct gzfile*);
150
159
  static void gzfile_make_footer(struct gzfile*);
151
- static void gzfile_read_header(struct gzfile*);
152
- 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);
153
162
  static void gzfile_write(struct gzfile*, Bytef*, long);
154
- static long gzfile_read_more(struct gzfile*);
163
+ static long gzfile_read_more(struct gzfile*, VALUE outbuf);
155
164
  static void gzfile_calc_crc(struct gzfile*, VALUE);
156
165
  static VALUE gzfile_read(struct gzfile*, long);
157
166
  static VALUE gzfile_read_all(struct gzfile*);
@@ -196,7 +205,7 @@ static VALUE rb_gzwriter_s_allocate(VALUE);
196
205
  static VALUE rb_gzwriter_s_open(int, VALUE*, VALUE);
197
206
  static VALUE rb_gzwriter_initialize(int, VALUE*, VALUE);
198
207
  static VALUE rb_gzwriter_flush(int, VALUE*, VALUE);
199
- static VALUE rb_gzwriter_write(VALUE, VALUE);
208
+ static VALUE rb_gzwriter_write(int, VALUE*, VALUE);
200
209
  static VALUE rb_gzwriter_putc(VALUE, VALUE);
201
210
 
202
211
  static VALUE rb_gzreader_s_allocate(VALUE);
@@ -359,11 +368,7 @@ finalizer_warn(const char *msg)
359
368
  static VALUE
360
369
  rb_zlib_version(VALUE klass)
361
370
  {
362
- VALUE str;
363
-
364
- str = rb_str_new2(zlibVersion());
365
- OBJ_TAINT(str); /* for safe */
366
- return str;
371
+ return rb_str_new2(zlibVersion());
367
372
  }
368
373
 
369
374
  #if SIZEOF_LONG > SIZEOF_INT
@@ -405,6 +410,15 @@ do_checksum(int argc, VALUE *argv, uLong (*func)(uLong, const Bytef*, uInt))
405
410
  if (NIL_P(str)) {
406
411
  sum = func(sum, Z_NULL, 0);
407
412
  }
413
+ else if (rb_obj_is_kind_of(str, rb_cIO)) {
414
+ VALUE buf;
415
+ VALUE buflen = INT2NUM(8192);
416
+
417
+ while (!NIL_P(buf = rb_funcall(str, id_read, 1, buflen))) {
418
+ StringValue(buf);
419
+ sum = checksum_long(func, sum, (Bytef*)RSTRING_PTR(buf), RSTRING_LEN(buf));
420
+ }
421
+ }
408
422
  else {
409
423
  StringValue(str);
410
424
  sum = checksum_long(func, sum, (Bytef*)RSTRING_PTR(str), RSTRING_LEN(str));
@@ -420,6 +434,8 @@ do_checksum(int argc, VALUE *argv, uLong (*func)(uLong, const Bytef*, uInt))
420
434
  * Calculates Adler-32 checksum for +string+, and returns updated value of
421
435
  * +adler+. If +string+ is omitted, it returns the Adler-32 initial value. If
422
436
  * +adler+ is omitted, it assumes that the initial value is given to +adler+.
437
+ * If +string+ is an IO instance, reads from the IO until the IO returns nil
438
+ * and returns Adler-32 of all read data.
423
439
  *
424
440
  * Example usage:
425
441
  *
@@ -450,7 +466,7 @@ rb_zlib_adler32(int argc, VALUE *argv, VALUE klass)
450
466
  static VALUE
451
467
  rb_zlib_adler32_combine(VALUE klass, VALUE adler1, VALUE adler2, VALUE len2)
452
468
  {
453
- return ULONG2NUM(
469
+ return ULONG2NUM(
454
470
  adler32_combine(NUM2ULONG(adler1), NUM2ULONG(adler2), NUM2LONG(len2)));
455
471
  }
456
472
  #else
@@ -464,7 +480,9 @@ rb_zlib_adler32_combine(VALUE klass, VALUE adler1, VALUE adler2, VALUE len2)
464
480
  *
465
481
  * Calculates CRC checksum for +string+, and returns updated value of +crc+. If
466
482
  * +string+ is omitted, it returns the CRC initial value. If +crc+ is omitted, it
467
- * assumes that the initial value is given to +crc+.
483
+ * assumes that the initial value is given to +crc+. If +string+ is an IO instance,
484
+ * reads from the IO until the IO returns nil and returns CRC checksum of all read
485
+ * data.
468
486
  *
469
487
  * FIXME: expression.
470
488
  */
@@ -488,7 +506,7 @@ rb_zlib_crc32(int argc, VALUE *argv, VALUE klass)
488
506
  static VALUE
489
507
  rb_zlib_crc32_combine(VALUE klass, VALUE crc1, VALUE crc2, VALUE len2)
490
508
  {
491
- return ULONG2NUM(
509
+ return ULONG2NUM(
492
510
  crc32_combine(NUM2ULONG(crc1), NUM2ULONG(crc2), NUM2LONG(len2)));
493
511
  }
494
512
  #else
@@ -527,7 +545,6 @@ rb_zlib_crc_table(VALUE obj)
527
545
  struct zstream {
528
546
  unsigned long flags;
529
547
  VALUE buf;
530
- long buf_filled;
531
548
  VALUE input;
532
549
  z_stream stream;
533
550
  const struct zstream_funcs {
@@ -543,13 +560,17 @@ struct zstream {
543
560
  #define ZSTREAM_FLAG_CLOSING 0x8
544
561
  #define ZSTREAM_FLAG_GZFILE 0x10 /* disallows yield from expand_buffer for
545
562
  gzip*/
546
- #define ZSTREAM_FLAG_UNUSED 0x20
563
+ #define ZSTREAM_REUSE_BUFFER 0x20
564
+ #define ZSTREAM_FLAG_UNUSED 0x40
547
565
 
548
566
  #define ZSTREAM_READY(z) ((z)->flags |= ZSTREAM_FLAG_READY)
549
567
  #define ZSTREAM_IS_READY(z) ((z)->flags & ZSTREAM_FLAG_READY)
550
568
  #define ZSTREAM_IS_FINISHED(z) ((z)->flags & ZSTREAM_FLAG_FINISHED)
551
569
  #define ZSTREAM_IS_CLOSING(z) ((z)->flags & ZSTREAM_FLAG_CLOSING)
552
570
  #define ZSTREAM_IS_GZFILE(z) ((z)->flags & ZSTREAM_FLAG_GZFILE)
571
+ #define ZSTREAM_BUF_FILLED(z) (NIL_P((z)->buf) ? 0 : RSTRING_LEN((z)->buf))
572
+
573
+ #define ZSTREAM_REUSE_BUFFER_P(z) ((z)->flags & ZSTREAM_REUSE_BUFFER)
553
574
 
554
575
  #define ZSTREAM_EXPAND_BUFFER_OK 0
555
576
 
@@ -599,7 +620,6 @@ zstream_init(struct zstream *z, const struct zstream_funcs *func)
599
620
  {
600
621
  z->flags = 0;
601
622
  z->buf = Qnil;
602
- z->buf_filled = 0;
603
623
  z->input = Qnil;
604
624
  z->stream.zalloc = zlib_mem_alloc;
605
625
  z->stream.zfree = zlib_mem_free;
@@ -624,17 +644,23 @@ zstream_expand_buffer(struct zstream *z)
624
644
  }
625
645
 
626
646
  if (!ZSTREAM_IS_GZFILE(z) && rb_block_given_p()) {
627
- if (z->buf_filled >= ZSTREAM_AVAIL_OUT_STEP_MAX) {
647
+ long buf_filled = ZSTREAM_BUF_FILLED(z);
648
+ if (buf_filled >= ZSTREAM_AVAIL_OUT_STEP_MAX) {
628
649
  int state = 0;
629
- VALUE self = (VALUE)z->stream.opaque;
630
650
 
631
- rb_str_resize(z->buf, z->buf_filled);
632
- rb_obj_reveal(z->buf, rb_cString);
633
- OBJ_INFECT(z->buf, self);
651
+ if (!ZSTREAM_REUSE_BUFFER_P(z)) {
652
+ rb_obj_reveal(z->buf, rb_cString);
653
+ }
634
654
 
635
655
  rb_protect(rb_yield, z->buf, &state);
636
656
 
637
- z->buf = Qnil;
657
+ if (ZSTREAM_REUSE_BUFFER_P(z)) {
658
+ rb_str_modify(z->buf);
659
+ rb_str_set_len(z->buf, 0);
660
+ }
661
+ else {
662
+ z->buf = Qnil;
663
+ }
638
664
  zstream_expand_buffer_into(z, ZSTREAM_AVAIL_OUT_STEP_MAX);
639
665
 
640
666
  if (state)
@@ -644,23 +670,11 @@ zstream_expand_buffer(struct zstream *z)
644
670
  }
645
671
  else {
646
672
  zstream_expand_buffer_into(z,
647
- ZSTREAM_AVAIL_OUT_STEP_MAX - z->buf_filled);
673
+ ZSTREAM_AVAIL_OUT_STEP_MAX - buf_filled);
648
674
  }
649
675
  }
650
676
  else {
651
- if (RSTRING_LEN(z->buf) - z->buf_filled >= ZSTREAM_AVAIL_OUT_STEP_MAX) {
652
- z->stream.avail_out = ZSTREAM_AVAIL_OUT_STEP_MAX;
653
- }
654
- else {
655
- long inc = z->buf_filled / 2;
656
- if (inc < ZSTREAM_AVAIL_OUT_STEP_MIN) {
657
- inc = ZSTREAM_AVAIL_OUT_STEP_MIN;
658
- }
659
- rb_str_resize(z->buf, z->buf_filled + inc);
660
- z->stream.avail_out = (inc < ZSTREAM_AVAIL_OUT_STEP_MAX) ?
661
- (int)inc : ZSTREAM_AVAIL_OUT_STEP_MAX;
662
- }
663
- z->stream.next_out = (Bytef*)RSTRING_PTR(z->buf) + z->buf_filled;
677
+ zstream_expand_buffer_non_stream(z);
664
678
  }
665
679
  }
666
680
 
@@ -670,15 +684,14 @@ zstream_expand_buffer_into(struct zstream *z, unsigned long size)
670
684
  if (NIL_P(z->buf)) {
671
685
  /* I uses rb_str_new here not rb_str_buf_new because
672
686
  rb_str_buf_new makes a zero-length string. */
673
- z->buf = rb_str_new(0, size);
674
- z->buf_filled = 0;
687
+ z->buf = rb_str_buf_new(size);
675
688
  z->stream.next_out = (Bytef*)RSTRING_PTR(z->buf);
676
689
  z->stream.avail_out = MAX_UINT(size);
677
690
  rb_obj_hide(z->buf);
678
691
  }
679
692
  else if (z->stream.avail_out != size) {
680
- rb_str_resize(z->buf, z->buf_filled + size);
681
- z->stream.next_out = (Bytef*)RSTRING_PTR(z->buf) + z->buf_filled;
693
+ rb_str_modify_expand(z->buf, size);
694
+ z->stream.next_out = (Bytef*)RSTRING_END(z->buf);
682
695
  z->stream.avail_out = MAX_UINT(size);
683
696
  }
684
697
  }
@@ -695,34 +708,24 @@ zstream_expand_buffer_protect(void *ptr)
695
708
  }
696
709
 
697
710
  static int
698
- zstream_expand_buffer_without_gvl(struct zstream *z)
711
+ zstream_expand_buffer_non_stream(struct zstream *z)
699
712
  {
700
- char * new_str;
701
- long inc, len;
713
+ long inc, len = ZSTREAM_BUF_FILLED(z);
702
714
 
703
- if (RSTRING_LEN(z->buf) - z->buf_filled >= ZSTREAM_AVAIL_OUT_STEP_MAX) {
715
+ if (rb_str_capacity(z->buf) - len >= ZSTREAM_AVAIL_OUT_STEP_MAX) {
704
716
  z->stream.avail_out = ZSTREAM_AVAIL_OUT_STEP_MAX;
705
717
  }
706
718
  else {
707
- inc = z->buf_filled / 2;
719
+ inc = len / 2;
708
720
  if (inc < ZSTREAM_AVAIL_OUT_STEP_MIN) {
709
721
  inc = ZSTREAM_AVAIL_OUT_STEP_MIN;
710
722
  }
711
723
 
712
- len = z->buf_filled + inc;
713
-
714
- new_str = ruby_xrealloc(RSTRING(z->buf)->as.heap.ptr, len + 1);
715
-
716
- /* from rb_str_resize */
717
- RSTRING(z->buf)->as.heap.ptr = new_str;
718
- RSTRING(z->buf)->as.heap.ptr[len] = '\0'; /* sentinel */
719
- RSTRING(z->buf)->as.heap.len =
720
- RSTRING(z->buf)->as.heap.aux.capa = len;
721
-
724
+ rb_str_modify_expand(z->buf, inc);
722
725
  z->stream.avail_out = (inc < ZSTREAM_AVAIL_OUT_STEP_MAX) ?
723
726
  (int)inc : ZSTREAM_AVAIL_OUT_STEP_MAX;
724
727
  }
725
- z->stream.next_out = (Bytef*)RSTRING_PTR(z->buf) + z->buf_filled;
728
+ z->stream.next_out = (Bytef*)RSTRING_END(z->buf);
726
729
 
727
730
  return ZSTREAM_EXPAND_BUFFER_OK;
728
731
  }
@@ -733,15 +736,14 @@ zstream_append_buffer(struct zstream *z, const Bytef *src, long len)
733
736
  if (NIL_P(z->buf)) {
734
737
  z->buf = rb_str_buf_new(len);
735
738
  rb_str_buf_cat(z->buf, (const char*)src, len);
736
- z->buf_filled = len;
737
739
  z->stream.next_out = (Bytef*)RSTRING_PTR(z->buf);
738
740
  z->stream.avail_out = 0;
739
741
  rb_obj_hide(z->buf);
740
742
  return;
741
743
  }
742
744
 
743
- if (RSTRING_LEN(z->buf) < z->buf_filled + len) {
744
- rb_str_resize(z->buf, z->buf_filled + len);
745
+ if ((long)rb_str_capacity(z->buf) < ZSTREAM_BUF_FILLED(z) + len) {
746
+ rb_str_modify_expand(z->buf, len);
745
747
  z->stream.avail_out = 0;
746
748
  }
747
749
  else {
@@ -752,9 +754,8 @@ zstream_append_buffer(struct zstream *z, const Bytef *src, long len)
752
754
  z->stream.avail_out = 0;
753
755
  }
754
756
  }
755
- memcpy(RSTRING_PTR(z->buf) + z->buf_filled, src, len);
756
- z->buf_filled += len;
757
- z->stream.next_out = (Bytef*)RSTRING_PTR(z->buf) + z->buf_filled;
757
+ rb_str_cat(z->buf, (const char *)src, len);
758
+ z->stream.next_out = (Bytef*)RSTRING_END(z->buf);
758
759
  }
759
760
 
760
761
  #define zstream_append_buffer2(z,v) \
@@ -763,7 +764,7 @@ zstream_append_buffer(struct zstream *z, const Bytef *src, long len)
763
764
  static VALUE
764
765
  zstream_detach_buffer(struct zstream *z)
765
766
  {
766
- VALUE dst, self = (VALUE)z->stream.opaque;
767
+ VALUE dst;
767
768
 
768
769
  if (!ZSTREAM_IS_FINISHED(z) && !ZSTREAM_IS_GZFILE(z) &&
769
770
  rb_block_given_p()) {
@@ -777,14 +778,12 @@ zstream_detach_buffer(struct zstream *z)
777
778
  }
778
779
  else {
779
780
  dst = z->buf;
780
- rb_str_resize(dst, z->buf_filled);
781
- rb_obj_reveal(dst, rb_cString);
781
+ if (!ZSTREAM_REUSE_BUFFER_P(z)) {
782
+ rb_obj_reveal(dst, rb_cString);
783
+ }
782
784
  }
783
785
 
784
- OBJ_INFECT(dst, self);
785
-
786
786
  z->buf = Qnil;
787
- z->buf_filled = 0;
788
787
  z->stream.next_out = 0;
789
788
  z->stream.avail_out = 0;
790
789
 
@@ -800,18 +799,20 @@ static VALUE
800
799
  zstream_shift_buffer(struct zstream *z, long len)
801
800
  {
802
801
  VALUE dst;
803
- long buflen;
802
+ char *bufptr;
803
+ long buflen = ZSTREAM_BUF_FILLED(z);
804
804
 
805
- if (z->buf_filled <= len) {
805
+ if (buflen <= len) {
806
806
  return zstream_detach_buffer(z);
807
807
  }
808
808
 
809
- dst = rb_str_new(RSTRING_PTR(z->buf), len);
810
- z->buf_filled -= len;
811
- memmove(RSTRING_PTR(z->buf), RSTRING_PTR(z->buf) + len,
812
- z->buf_filled);
813
- z->stream.next_out = (Bytef*)RSTRING_PTR(z->buf) + z->buf_filled;
814
- buflen = RSTRING_LEN(z->buf) - z->buf_filled;
809
+ bufptr = RSTRING_PTR(z->buf);
810
+ dst = rb_str_new(bufptr, len);
811
+ buflen -= len;
812
+ memmove(bufptr, bufptr + len, buflen);
813
+ rb_str_set_len(z->buf, buflen);
814
+ z->stream.next_out = (Bytef*)RSTRING_END(z->buf);
815
+ buflen = (long)rb_str_capacity(z->buf) - ZSTREAM_BUF_FILLED(z);
815
816
  if (buflen > ZSTREAM_AVAIL_OUT_STEP_MAX) {
816
817
  buflen = ZSTREAM_AVAIL_OUT_STEP_MAX;
817
818
  }
@@ -823,13 +824,17 @@ zstream_shift_buffer(struct zstream *z, long len)
823
824
  static void
824
825
  zstream_buffer_ungets(struct zstream *z, const Bytef *b, unsigned long len)
825
826
  {
826
- if (NIL_P(z->buf) || RSTRING_LEN(z->buf) - z->buf_filled == 0) {
827
+ char *bufptr;
828
+ long filled;
829
+
830
+ if (NIL_P(z->buf) || (long)rb_str_capacity(z->buf) <= ZSTREAM_BUF_FILLED(z)) {
827
831
  zstream_expand_buffer_into(z, len);
828
832
  }
829
833
 
830
- memmove(RSTRING_PTR(z->buf) + len, RSTRING_PTR(z->buf), z->buf_filled);
831
- memmove(RSTRING_PTR(z->buf), b, len);
832
- z->buf_filled+=len;
834
+ RSTRING_GETMEM(z->buf, bufptr, filled);
835
+ memmove(bufptr + len, bufptr, filled);
836
+ memmove(bufptr, b, len);
837
+ rb_str_set_len(z->buf, filled + len);
833
838
  if (z->stream.avail_out > 0) {
834
839
  if (len > z->stream.avail_out) len = z->stream.avail_out;
835
840
  z->stream.next_out+=len;
@@ -840,17 +845,8 @@ zstream_buffer_ungets(struct zstream *z, const Bytef *b, unsigned long len)
840
845
  static void
841
846
  zstream_buffer_ungetbyte(struct zstream *z, int c)
842
847
  {
843
- if (NIL_P(z->buf) || RSTRING_LEN(z->buf) - z->buf_filled == 0) {
844
- zstream_expand_buffer(z);
845
- }
846
-
847
- memmove(RSTRING_PTR(z->buf) + 1, RSTRING_PTR(z->buf), z->buf_filled);
848
- RSTRING_PTR(z->buf)[0] = (char)c;
849
- z->buf_filled++;
850
- if (z->stream.avail_out > 0) {
851
- z->stream.next_out++;
852
- z->stream.avail_out--;
853
- }
848
+ Bytef cc = (Bytef)c;
849
+ zstream_buffer_ungets(z, &cc, 1);
854
850
  }
855
851
 
856
852
  static void
@@ -875,19 +871,50 @@ zstream_append_input(struct zstream *z, const Bytef *src, long len)
875
871
  static void
876
872
  zstream_discard_input(struct zstream *z, long len)
877
873
  {
878
- if (NIL_P(z->input) || RSTRING_LEN(z->input) <= len) {
879
- z->input = Qnil;
874
+ if (NIL_P(z->input)) {
880
875
  }
881
- else {
882
- z->input = rb_str_substr(z->input, len,
883
- RSTRING_LEN(z->input) - len);
876
+ else if (RBASIC_CLASS(z->input) == 0) {
877
+ /* hidden, we created z->input and have complete control */
878
+ char *ptr;
879
+ long oldlen, newlen;
880
+
881
+ RSTRING_GETMEM(z->input, ptr, oldlen);
882
+ newlen = oldlen - len;
883
+ if (newlen > 0) {
884
+ memmove(ptr, ptr + len, newlen);
885
+ }
886
+ if (newlen < 0) {
887
+ newlen = 0;
888
+ }
889
+ rb_str_resize(z->input, newlen);
890
+ if (newlen == 0) {
891
+ rb_gc_force_recycle(z->input);
892
+ z->input = Qnil;
893
+ }
894
+ else {
895
+ rb_str_set_len(z->input, newlen);
896
+ }
897
+ }
898
+ else { /* do not mangle user-provided data */
899
+ if (RSTRING_LEN(z->input) <= len) {
900
+ z->input = Qnil;
901
+ }
902
+ else {
903
+ z->input = rb_str_substr(z->input, len,
904
+ RSTRING_LEN(z->input) - len);
905
+ }
884
906
  }
885
907
  }
886
908
 
887
909
  static void
888
910
  zstream_reset_input(struct zstream *z)
889
911
  {
890
- z->input = Qnil;
912
+ if (!NIL_P(z->input) && RBASIC_CLASS(z->input) == 0) {
913
+ rb_str_resize(z->input, 0);
914
+ }
915
+ else {
916
+ z->input = Qnil;
917
+ }
891
918
  }
892
919
 
893
920
  static void
@@ -912,7 +939,6 @@ zstream_detach_input(struct zstream *z)
912
939
  rb_obj_reveal(dst, rb_cString);
913
940
  }
914
941
  z->input = Qnil;
915
- rb_obj_reveal(dst, rb_cString);
916
942
  return dst;
917
943
  }
918
944
 
@@ -927,7 +953,6 @@ zstream_reset(struct zstream *z)
927
953
  }
928
954
  z->flags = ZSTREAM_FLAG_READY;
929
955
  z->buf = Qnil;
930
- z->buf_filled = 0;
931
956
  z->stream.next_out = 0;
932
957
  z->stream.avail_out = 0;
933
958
  zstream_reset_input(z);
@@ -956,6 +981,12 @@ zstream_end(struct zstream *z)
956
981
  return Qnil;
957
982
  }
958
983
 
984
+ static VALUE
985
+ zstream_ensure_end(VALUE v)
986
+ {
987
+ return zstream_end((struct zstream *)v);
988
+ }
989
+
959
990
  static void *
960
991
  zstream_run_func(void *ptr)
961
992
  {
@@ -968,7 +999,7 @@ zstream_run_func(void *ptr)
968
999
  while (!args->interrupt) {
969
1000
  n = z->stream.avail_out;
970
1001
  err = z->func->run(&z->stream, flush);
971
- z->buf_filled += n - z->stream.avail_out;
1002
+ rb_str_set_len(z->buf, ZSTREAM_BUF_FILLED(z) + (n - z->stream.avail_out));
972
1003
 
973
1004
  if (err == Z_STREAM_END) {
974
1005
  z->flags &= ~ZSTREAM_FLAG_IN_STREAM;
@@ -997,7 +1028,7 @@ zstream_run_func(void *ptr)
997
1028
  (void *)z);
998
1029
  }
999
1030
  else {
1000
- state = zstream_expand_buffer_without_gvl(z);
1031
+ state = zstream_expand_buffer_non_stream(z);
1001
1032
  }
1002
1033
 
1003
1034
  if (state) {
@@ -1012,6 +1043,7 @@ zstream_run_func(void *ptr)
1012
1043
 
1013
1044
  /*
1014
1045
  * There is no safe way to interrupt z->run->func().
1046
+ * async-signal-safe
1015
1047
  */
1016
1048
  static void
1017
1049
  zstream_unblock_func(void *ptr)
@@ -1026,7 +1058,7 @@ zstream_run(struct zstream *z, Bytef *src, long len, int flush)
1026
1058
  {
1027
1059
  struct zstream_run_args args;
1028
1060
  int err;
1029
- VALUE guard = Qnil;
1061
+ VALUE old_input = Qnil;
1030
1062
 
1031
1063
  args.z = z;
1032
1064
  args.flush = flush;
@@ -1040,12 +1072,13 @@ zstream_run(struct zstream *z, Bytef *src, long len, int flush)
1040
1072
  }
1041
1073
  else {
1042
1074
  zstream_append_input(z, src, len);
1043
- z->stream.next_in = (Bytef*)RSTRING_PTR(z->input);
1044
- z->stream.avail_in = MAX_UINT(RSTRING_LEN(z->input));
1045
1075
  /* keep reference to `z->input' so as not to be garbage collected
1046
1076
  after zstream_reset_input() and prevent `z->stream.next_in'
1047
1077
  from dangling. */
1048
- guard = z->input;
1078
+ old_input = zstream_detach_input(z);
1079
+ rb_obj_hide(old_input); /* for GVL release and later recycle */
1080
+ z->stream.next_in = (Bytef*)RSTRING_PTR(old_input);
1081
+ z->stream.avail_in = MAX_UINT(RSTRING_LEN(old_input));
1049
1082
  }
1050
1083
 
1051
1084
  if (z->stream.avail_out == 0) {
@@ -1053,8 +1086,14 @@ zstream_run(struct zstream *z, Bytef *src, long len, int flush)
1053
1086
  }
1054
1087
 
1055
1088
  loop:
1089
+ #ifndef RB_NOGVL_UBF_ASYNC_SAFE
1056
1090
  err = (int)(VALUE)rb_thread_call_without_gvl(zstream_run_func, (void *)&args,
1057
1091
  zstream_unblock_func, (void *)&args);
1092
+ #else
1093
+ err = (int)(VALUE)rb_nogvl(zstream_run_func, (void *)&args,
1094
+ zstream_unblock_func, (void *)&args,
1095
+ RB_NOGVL_UBF_ASYNC_SAFE);
1096
+ #endif
1058
1097
 
1059
1098
  if (flush != Z_FINISH && err == Z_BUF_ERROR
1060
1099
  && z->stream.avail_out > 0) {
@@ -1083,7 +1122,10 @@ loop:
1083
1122
 
1084
1123
  if (z->stream.avail_in > 0) {
1085
1124
  zstream_append_input(z, z->stream.next_in, z->stream.avail_in);
1086
- RB_GC_GUARD(guard); /* prevent tail call to make guard effective */
1125
+ }
1126
+ if (!NIL_P(old_input)) {
1127
+ rb_str_resize(old_input, 0);
1128
+ rb_gc_force_recycle(old_input);
1087
1129
  }
1088
1130
 
1089
1131
  if (args.jump_state)
@@ -1316,7 +1358,6 @@ rb_zstream_flush_next_in(VALUE obj)
1316
1358
 
1317
1359
  TypedData_Get_Struct(obj, struct zstream, &zstream_data_type, z);
1318
1360
  dst = zstream_detach_input(z);
1319
- OBJ_INFECT(dst, obj);
1320
1361
  return dst;
1321
1362
  }
1322
1363
 
@@ -1412,7 +1453,7 @@ rb_zstream_data_type(VALUE obj)
1412
1453
  static VALUE
1413
1454
  rb_zstream_adler(VALUE obj)
1414
1455
  {
1415
- return rb_uint2inum(get_zstream(obj)->stream.adler);
1456
+ return rb_uint2inum(get_zstream(obj)->stream.adler);
1416
1457
  }
1417
1458
 
1418
1459
  /*
@@ -1577,7 +1618,6 @@ rb_deflate_init_copy(VALUE self, VALUE orig)
1577
1618
  }
1578
1619
  z1->input = NIL_P(z2->input) ? Qnil : rb_str_dup(z2->input);
1579
1620
  z1->buf = NIL_P(z2->buf) ? Qnil : rb_str_dup(z2->buf);
1580
- z1->buf_filled = z2->buf_filled;
1581
1621
  z1->flags = z2->flags;
1582
1622
 
1583
1623
  return self;
@@ -1636,9 +1676,8 @@ rb_deflate_s_deflate(int argc, VALUE *argv, VALUE klass)
1636
1676
 
1637
1677
  args[0] = (VALUE)&z;
1638
1678
  args[1] = src;
1639
- dst = rb_ensure(deflate_run, (VALUE)args, zstream_end, (VALUE)&z);
1679
+ dst = rb_ensure(deflate_run, (VALUE)args, zstream_ensure_end, (VALUE)&z);
1640
1680
 
1641
- OBJ_INFECT(dst, src);
1642
1681
  return dst;
1643
1682
  }
1644
1683
 
@@ -1688,7 +1727,6 @@ rb_deflate_deflate(int argc, VALUE *argv, VALUE obj)
1688
1727
  VALUE src, flush;
1689
1728
 
1690
1729
  rb_scan_args(argc, argv, "11", &src, &flush);
1691
- OBJ_INFECT(obj, src);
1692
1730
  do_deflate(z, src, ARG_FLUSH(flush));
1693
1731
 
1694
1732
  return zstream_detach_buffer(z);
@@ -1706,7 +1744,6 @@ rb_deflate_deflate(int argc, VALUE *argv, VALUE obj)
1706
1744
  static VALUE
1707
1745
  rb_deflate_addstr(VALUE obj, VALUE src)
1708
1746
  {
1709
- OBJ_INFECT(obj, src);
1710
1747
  do_deflate(get_zstream(obj), src, Z_NO_FLUSH);
1711
1748
  return obj;
1712
1749
  }
@@ -1761,23 +1798,26 @@ rb_deflate_params(VALUE obj, VALUE v_level, VALUE v_strategy)
1761
1798
  int level, strategy;
1762
1799
  int err;
1763
1800
  uInt n;
1801
+ long filled;
1764
1802
 
1765
1803
  level = ARG_LEVEL(v_level);
1766
1804
  strategy = ARG_STRATEGY(v_strategy);
1767
1805
 
1768
1806
  n = z->stream.avail_out;
1769
1807
  err = deflateParams(&z->stream, level, strategy);
1770
- z->buf_filled += n - z->stream.avail_out;
1808
+ filled = n - z->stream.avail_out;
1771
1809
  while (err == Z_BUF_ERROR) {
1772
1810
  rb_warning("deflateParams() returned Z_BUF_ERROR");
1773
1811
  zstream_expand_buffer(z);
1812
+ rb_str_set_len(z->buf, RSTRING_LEN(z->buf) + filled);
1774
1813
  n = z->stream.avail_out;
1775
1814
  err = deflateParams(&z->stream, level, strategy);
1776
- z->buf_filled += n - z->stream.avail_out;
1815
+ filled = n - z->stream.avail_out;
1777
1816
  }
1778
1817
  if (err != Z_OK) {
1779
1818
  raise_zlib_error(err, z->stream.msg);
1780
1819
  }
1820
+ rb_str_set_len(z->buf, RSTRING_LEN(z->buf) + filled);
1781
1821
 
1782
1822
  return Qnil;
1783
1823
  }
@@ -1803,7 +1843,6 @@ rb_deflate_set_dictionary(VALUE obj, VALUE dic)
1803
1843
  VALUE src = dic;
1804
1844
  int err;
1805
1845
 
1806
- OBJ_INFECT(obj, dic);
1807
1846
  StringValue(src);
1808
1847
  err = deflateSetDictionary(&z->stream,
1809
1848
  (Bytef*)RSTRING_PTR(src), RSTRING_LENINT(src));
@@ -1948,9 +1987,8 @@ rb_inflate_s_inflate(VALUE obj, VALUE src)
1948
1987
 
1949
1988
  args[0] = (VALUE)&z;
1950
1989
  args[1] = src;
1951
- dst = rb_ensure(inflate_run, (VALUE)args, zstream_end, (VALUE)&z);
1990
+ dst = rb_ensure(inflate_run, (VALUE)args, zstream_ensure_end, (VALUE)&z);
1952
1991
 
1953
- OBJ_INFECT(dst, src);
1954
1992
  return dst;
1955
1993
  }
1956
1994
 
@@ -1991,8 +2029,8 @@ rb_inflate_add_dictionary(VALUE obj, VALUE dictionary)
1991
2029
  * Document-method: Zlib::Inflate#inflate
1992
2030
  *
1993
2031
  * call-seq:
1994
- * inflate(deflate_string) -> String
1995
- * inflate(deflate_string) { |chunk| ... } -> nil
2032
+ * inflate(deflate_string, buffer: nil) -> String
2033
+ * inflate(deflate_string, buffer: nil) { |chunk| ... } -> nil
1996
2034
  *
1997
2035
  * Inputs +deflate_string+ into the inflate stream and returns the output from
1998
2036
  * the stream. Calling this method, both the input and the output buffer of
@@ -2002,6 +2040,15 @@ rb_inflate_add_dictionary(VALUE obj, VALUE dictionary)
2002
2040
  * If a block is given consecutive inflated chunks from the +deflate_string+
2003
2041
  * are yielded to the block and +nil+ is returned.
2004
2042
  *
2043
+ * If a :buffer keyword argument is given and not nil:
2044
+ *
2045
+ * * The :buffer keyword should be a String, and will used as the output buffer.
2046
+ * Using this option can reuse the memory required during inflation.
2047
+ * * When not passing a block, the return value will be the same object as the
2048
+ * :buffer keyword argument.
2049
+ * * When passing a block, the yielded chunks will be the same value as the
2050
+ * :buffer keyword argument.
2051
+ *
2005
2052
  * Raises a Zlib::NeedDict exception if a preset dictionary is needed to
2006
2053
  * decompress. Set the dictionary by Zlib::Inflate#set_dictionary and then
2007
2054
  * call this method again with an empty string to flush the stream:
@@ -2025,12 +2072,37 @@ rb_inflate_add_dictionary(VALUE obj, VALUE dictionary)
2025
2072
  * See also Zlib::Inflate.new
2026
2073
  */
2027
2074
  static VALUE
2028
- rb_inflate_inflate(VALUE obj, VALUE src)
2075
+ rb_inflate_inflate(int argc, VALUE* argv, VALUE obj)
2029
2076
  {
2030
2077
  struct zstream *z = get_zstream(obj);
2031
- VALUE dst;
2078
+ VALUE dst, src, opts, buffer = Qnil;
2032
2079
 
2033
- OBJ_INFECT(obj, src);
2080
+ if (OPTHASH_GIVEN_P(opts)) {
2081
+ VALUE buf;
2082
+ rb_get_kwargs(opts, &id_buffer, 0, 1, &buf);
2083
+ if (buf != Qundef && buf != Qnil) {
2084
+ buffer = StringValue(buf);
2085
+ }
2086
+ }
2087
+ if (buffer != Qnil) {
2088
+ if (!(ZSTREAM_REUSE_BUFFER_P(z) && z->buf == buffer)) {
2089
+ long len = RSTRING_LEN(buffer);
2090
+ if (len >= ZSTREAM_AVAIL_OUT_STEP_MAX) {
2091
+ rb_str_modify(buffer);
2092
+ }
2093
+ else {
2094
+ len = ZSTREAM_AVAIL_OUT_STEP_MAX - len;
2095
+ rb_str_modify_expand(buffer, len);
2096
+ }
2097
+ rb_str_set_len(buffer, 0);
2098
+ z->flags |= ZSTREAM_REUSE_BUFFER;
2099
+ z->buf = buffer;
2100
+ }
2101
+ } else if (ZSTREAM_REUSE_BUFFER_P(z)) {
2102
+ z->flags &= ~ZSTREAM_REUSE_BUFFER;
2103
+ z->buf = Qnil;
2104
+ }
2105
+ rb_scan_args(argc, argv, "10", &src);
2034
2106
 
2035
2107
  if (ZSTREAM_IS_FINISHED(z)) {
2036
2108
  if (NIL_P(src)) {
@@ -2039,8 +2111,11 @@ rb_inflate_inflate(VALUE obj, VALUE src)
2039
2111
  else {
2040
2112
  StringValue(src);
2041
2113
  zstream_append_buffer2(z, src);
2042
- dst = rb_str_new(0, 0);
2043
- OBJ_INFECT(dst, obj);
2114
+ if (ZSTREAM_REUSE_BUFFER_P(z)) {
2115
+ dst = rb_str_resize(buffer, 0);
2116
+ } else {
2117
+ dst = rb_str_new(0, 0);
2118
+ }
2044
2119
  }
2045
2120
  }
2046
2121
  else {
@@ -2066,8 +2141,6 @@ rb_inflate_addstr(VALUE obj, VALUE src)
2066
2141
  {
2067
2142
  struct zstream *z = get_zstream(obj);
2068
2143
 
2069
- OBJ_INFECT(obj, src);
2070
-
2071
2144
  if (ZSTREAM_IS_FINISHED(z)) {
2072
2145
  if (!NIL_P(src)) {
2073
2146
  StringValue(src);
@@ -2097,7 +2170,6 @@ rb_inflate_sync(VALUE obj, VALUE src)
2097
2170
  {
2098
2171
  struct zstream *z = get_zstream(obj);
2099
2172
 
2100
- OBJ_INFECT(obj, src);
2101
2173
  StringValue(src);
2102
2174
  return zstream_sync(z, (Bytef*)RSTRING_PTR(src), RSTRING_LEN(src));
2103
2175
  }
@@ -2139,7 +2211,6 @@ rb_inflate_set_dictionary(VALUE obj, VALUE dic)
2139
2211
  VALUE src = dic;
2140
2212
  int err;
2141
2213
 
2142
- OBJ_INFECT(obj, dic);
2143
2214
  StringValue(src);
2144
2215
  err = inflateSetDictionary(&z->stream,
2145
2216
  (Bytef*)RSTRING_PTR(src), RSTRING_LENINT(src));
@@ -2196,7 +2267,7 @@ rb_inflate_set_dictionary(VALUE obj, VALUE dic)
2196
2267
  #define OS_CODE OS_UNIX
2197
2268
  #endif
2198
2269
 
2199
- static ID id_write, id_read, id_readpartial, id_flush, id_seek, id_close, id_path, id_input;
2270
+ static ID id_write, id_readpartial, id_flush, id_seek, id_close, id_path, id_input;
2200
2271
  static VALUE cGzError, cNoFooter, cCRCError, cLengthError;
2201
2272
 
2202
2273
 
@@ -2220,7 +2291,6 @@ struct gzfile {
2220
2291
  rb_encoding *enc2;
2221
2292
  rb_econv_t *ec;
2222
2293
  VALUE ecopts;
2223
- char *cbuf;
2224
2294
  VALUE path;
2225
2295
  };
2226
2296
  #define GZFILE_CBUF_CAPA 10
@@ -2228,12 +2298,23 @@ struct gzfile {
2228
2298
  #define GZFILE_FLAG_SYNC ZSTREAM_FLAG_UNUSED
2229
2299
  #define GZFILE_FLAG_HEADER_FINISHED (ZSTREAM_FLAG_UNUSED << 1)
2230
2300
  #define GZFILE_FLAG_FOOTER_FINISHED (ZSTREAM_FLAG_UNUSED << 2)
2301
+ #define GZFILE_FLAG_MTIME_IS_SET (ZSTREAM_FLAG_UNUSED << 3)
2231
2302
 
2232
2303
  #define GZFILE_IS_FINISHED(gz) \
2233
- (ZSTREAM_IS_FINISHED(&(gz)->z) && (gz)->z.buf_filled == 0)
2304
+ (ZSTREAM_IS_FINISHED(&(gz)->z) && ZSTREAM_BUF_FILLED(&(gz)->z) == 0)
2234
2305
 
2235
2306
  #define GZFILE_READ_SIZE 2048
2236
2307
 
2308
+ struct read_raw_arg {
2309
+ VALUE io;
2310
+ union {
2311
+ const VALUE argv[2]; /* for rb_funcallv */
2312
+ struct {
2313
+ VALUE len;
2314
+ VALUE buf;
2315
+ } in;
2316
+ } as;
2317
+ };
2237
2318
 
2238
2319
  static void
2239
2320
  gzfile_mark(void *p)
@@ -2260,22 +2341,13 @@ gzfile_free(void *p)
2260
2341
  }
2261
2342
  zstream_finalize(z);
2262
2343
  }
2263
- if (gz->cbuf) {
2264
- xfree(gz->cbuf);
2265
- }
2266
2344
  xfree(gz);
2267
2345
  }
2268
2346
 
2269
2347
  static size_t
2270
2348
  gzfile_memsize(const void *p)
2271
2349
  {
2272
- const struct gzfile *gz = p;
2273
- size_t size = sizeof(struct gzfile);
2274
-
2275
- if (gz->cbuf)
2276
- size += GZFILE_CBUF_CAPA;
2277
-
2278
- return size;
2350
+ return sizeof(struct gzfile);
2279
2351
  }
2280
2352
 
2281
2353
  static const rb_data_type_t gzfile_data_type = {
@@ -2304,7 +2376,6 @@ gzfile_init(struct gzfile *gz, const struct zstream_funcs *funcs, void (*endfunc
2304
2376
  gz->ec = NULL;
2305
2377
  gz->ecflags = 0;
2306
2378
  gz->ecopts = Qnil;
2307
- gz->cbuf = 0;
2308
2379
  gz->path = Qnil;
2309
2380
  }
2310
2381
 
@@ -2356,9 +2427,8 @@ gzfile_write_raw(struct gzfile *gz)
2356
2427
  {
2357
2428
  VALUE str;
2358
2429
 
2359
- if (gz->z.buf_filled > 0) {
2430
+ if (ZSTREAM_BUF_FILLED(&gz->z) > 0) {
2360
2431
  str = zstream_detach_buffer(&gz->z);
2361
- OBJ_TAINT(str); /* for safe */
2362
2432
  rb_funcall(gz->io, id_write, 1, str);
2363
2433
  if ((gz->z.flags & GZFILE_FLAG_SYNC)
2364
2434
  && rb_respond_to(gz->io, id_flush))
@@ -2369,21 +2439,23 @@ gzfile_write_raw(struct gzfile *gz)
2369
2439
  static VALUE
2370
2440
  gzfile_read_raw_partial(VALUE arg)
2371
2441
  {
2372
- struct gzfile *gz = (struct gzfile*)arg;
2442
+ struct read_raw_arg *ra = (struct read_raw_arg *)arg;
2373
2443
  VALUE str;
2444
+ int argc = NIL_P(ra->as.argv[1]) ? 1 : 2;
2374
2445
 
2375
- str = rb_funcall(gz->io, id_readpartial, 1, INT2FIX(GZFILE_READ_SIZE));
2446
+ str = rb_funcallv(ra->io, id_readpartial, argc, ra->as.argv);
2376
2447
  Check_Type(str, T_STRING);
2377
2448
  return str;
2378
2449
  }
2379
2450
 
2380
2451
  static VALUE
2381
- gzfile_read_raw_rescue(VALUE arg)
2452
+ gzfile_read_raw_rescue(VALUE arg, VALUE _)
2382
2453
  {
2383
- struct gzfile *gz = (struct gzfile*)arg;
2454
+ struct read_raw_arg *ra = (struct read_raw_arg *)arg;
2384
2455
  VALUE str = Qnil;
2385
2456
  if (rb_obj_is_kind_of(rb_errinfo(), rb_eNoMethodError)) {
2386
- str = rb_funcall(gz->io, id_read, 1, INT2FIX(GZFILE_READ_SIZE));
2457
+ int argc = NIL_P(ra->as.argv[1]) ? 1 : 2;
2458
+ str = rb_funcallv(ra->io, id_read, argc, ra->as.argv);
2387
2459
  if (!NIL_P(str)) {
2388
2460
  Check_Type(str, T_STRING);
2389
2461
  }
@@ -2392,15 +2464,21 @@ gzfile_read_raw_rescue(VALUE arg)
2392
2464
  }
2393
2465
 
2394
2466
  static VALUE
2395
- gzfile_read_raw(struct gzfile *gz)
2467
+ gzfile_read_raw(struct gzfile *gz, VALUE outbuf)
2396
2468
  {
2397
- return rb_rescue2(gzfile_read_raw_partial, (VALUE)gz,
2398
- gzfile_read_raw_rescue, (VALUE)gz,
2469
+ struct read_raw_arg ra;
2470
+
2471
+ ra.io = gz->io;
2472
+ ra.as.in.len = INT2FIX(GZFILE_READ_SIZE);
2473
+ ra.as.in.buf = outbuf;
2474
+
2475
+ return rb_rescue2(gzfile_read_raw_partial, (VALUE)&ra,
2476
+ gzfile_read_raw_rescue, (VALUE)&ra,
2399
2477
  rb_eEOFError, rb_eNoMethodError, (VALUE)0);
2400
2478
  }
2401
2479
 
2402
2480
  static int
2403
- gzfile_read_raw_ensure(struct gzfile *gz, long size)
2481
+ gzfile_read_raw_ensure(struct gzfile *gz, long size, VALUE outbuf)
2404
2482
  {
2405
2483
  VALUE str;
2406
2484
 
@@ -2409,7 +2487,7 @@ gzfile_read_raw_ensure(struct gzfile *gz, long size)
2409
2487
  rb_raise(cGzError, "unexpected end of string");
2410
2488
  }
2411
2489
  while (NIL_P(gz->z.input) || RSTRING_LEN(gz->z.input) < size) {
2412
- str = gzfile_read_raw(gz);
2490
+ str = gzfile_read_raw(gz, outbuf);
2413
2491
  if (NIL_P(str)) return 0;
2414
2492
  zstream_append_input2(&gz->z, str);
2415
2493
  }
@@ -2426,7 +2504,7 @@ gzfile_read_raw_until_zero(struct gzfile *gz, long offset)
2426
2504
  p = memchr(RSTRING_PTR(gz->z.input) + offset, '\0',
2427
2505
  RSTRING_LEN(gz->z.input) - offset);
2428
2506
  if (p) break;
2429
- str = gzfile_read_raw(gz);
2507
+ str = gzfile_read_raw(gz, Qnil);
2430
2508
  if (NIL_P(str)) {
2431
2509
  rb_raise(cGzError, "unexpected end of file");
2432
2510
  }
@@ -2507,7 +2585,7 @@ gzfile_make_header(struct gzfile *gz)
2507
2585
  if (!NIL_P(gz->comment)) {
2508
2586
  flags |= GZ_FLAG_COMMENT;
2509
2587
  }
2510
- if (gz->mtime == 0) {
2588
+ if (!(gz->z.flags & GZFILE_FLAG_MTIME_IS_SET)) {
2511
2589
  gz->mtime = time(0);
2512
2590
  }
2513
2591
 
@@ -2551,13 +2629,14 @@ gzfile_make_footer(struct gzfile *gz)
2551
2629
  }
2552
2630
 
2553
2631
  static void
2554
- gzfile_read_header(struct gzfile *gz)
2632
+ gzfile_read_header(struct gzfile *gz, VALUE outbuf)
2555
2633
  {
2556
2634
  const unsigned char *head;
2557
2635
  long len;
2558
2636
  char flags, *p;
2559
2637
 
2560
- if (!gzfile_read_raw_ensure(gz, 10)) { /* 10 is the size of gzip header */
2638
+ /* 10 is the size of gzip header */
2639
+ if (!gzfile_read_raw_ensure(gz, 10, outbuf)) {
2561
2640
  gzfile_raise(gz, cGzError, "not in gzip format");
2562
2641
  }
2563
2642
 
@@ -2596,33 +2675,31 @@ gzfile_read_header(struct gzfile *gz)
2596
2675
  zstream_discard_input(&gz->z, 10);
2597
2676
 
2598
2677
  if (flags & GZ_FLAG_EXTRA) {
2599
- if (!gzfile_read_raw_ensure(gz, 2)) {
2678
+ if (!gzfile_read_raw_ensure(gz, 2, outbuf)) {
2600
2679
  rb_raise(cGzError, "unexpected end of file");
2601
2680
  }
2602
2681
  len = gzfile_get16((Bytef*)RSTRING_PTR(gz->z.input));
2603
- if (!gzfile_read_raw_ensure(gz, 2 + len)) {
2682
+ if (!gzfile_read_raw_ensure(gz, 2 + len, outbuf)) {
2604
2683
  rb_raise(cGzError, "unexpected end of file");
2605
2684
  }
2606
2685
  zstream_discard_input(&gz->z, 2 + len);
2607
2686
  }
2608
2687
  if (flags & GZ_FLAG_ORIG_NAME) {
2609
- if (!gzfile_read_raw_ensure(gz, 1)) {
2688
+ if (!gzfile_read_raw_ensure(gz, 1, outbuf)) {
2610
2689
  rb_raise(cGzError, "unexpected end of file");
2611
2690
  }
2612
2691
  p = gzfile_read_raw_until_zero(gz, 0);
2613
2692
  len = p - RSTRING_PTR(gz->z.input);
2614
2693
  gz->orig_name = rb_str_new(RSTRING_PTR(gz->z.input), len);
2615
- OBJ_TAINT(gz->orig_name); /* for safe */
2616
2694
  zstream_discard_input(&gz->z, len + 1);
2617
2695
  }
2618
2696
  if (flags & GZ_FLAG_COMMENT) {
2619
- if (!gzfile_read_raw_ensure(gz, 1)) {
2697
+ if (!gzfile_read_raw_ensure(gz, 1, outbuf)) {
2620
2698
  rb_raise(cGzError, "unexpected end of file");
2621
2699
  }
2622
2700
  p = gzfile_read_raw_until_zero(gz, 0);
2623
2701
  len = p - RSTRING_PTR(gz->z.input);
2624
2702
  gz->comment = rb_str_new(RSTRING_PTR(gz->z.input), len);
2625
- OBJ_TAINT(gz->comment); /* for safe */
2626
2703
  zstream_discard_input(&gz->z, len + 1);
2627
2704
  }
2628
2705
 
@@ -2632,13 +2709,14 @@ gzfile_read_header(struct gzfile *gz)
2632
2709
  }
2633
2710
 
2634
2711
  static void
2635
- gzfile_check_footer(struct gzfile *gz)
2712
+ gzfile_check_footer(struct gzfile *gz, VALUE outbuf)
2636
2713
  {
2637
2714
  unsigned long crc, length;
2638
2715
 
2639
2716
  gz->z.flags |= GZFILE_FLAG_FOOTER_FINISHED;
2640
2717
 
2641
- if (!gzfile_read_raw_ensure(gz, 8)) { /* 8 is the size of gzip footer */
2718
+ /* 8 is the size of gzip footer */
2719
+ if (!gzfile_read_raw_ensure(gz, 8, outbuf)) {
2642
2720
  gzfile_raise(gz, cNoFooter, "footer is not found");
2643
2721
  }
2644
2722
 
@@ -2672,12 +2750,12 @@ gzfile_write(struct gzfile *gz, Bytef *str, long len)
2672
2750
  }
2673
2751
 
2674
2752
  static long
2675
- gzfile_read_more(struct gzfile *gz)
2753
+ gzfile_read_more(struct gzfile *gz, VALUE outbuf)
2676
2754
  {
2677
2755
  VALUE str;
2678
2756
 
2679
2757
  while (!ZSTREAM_IS_FINISHED(&gz->z)) {
2680
- str = gzfile_read_raw(gz);
2758
+ str = gzfile_read_raw(gz, outbuf);
2681
2759
  if (NIL_P(str)) {
2682
2760
  if (!ZSTREAM_IS_FINISHED(&gz->z)) {
2683
2761
  rb_raise(cGzError, "unexpected end of file");
@@ -2689,9 +2767,9 @@ gzfile_read_more(struct gzfile *gz)
2689
2767
  Z_SYNC_FLUSH);
2690
2768
  RB_GC_GUARD(str);
2691
2769
  }
2692
- if (gz->z.buf_filled > 0) break;
2770
+ if (ZSTREAM_BUF_FILLED(&gz->z) > 0) break;
2693
2771
  }
2694
- return gz->z.buf_filled;
2772
+ return ZSTREAM_BUF_FILLED(&gz->z);
2695
2773
  }
2696
2774
 
2697
2775
  static void
@@ -2702,7 +2780,7 @@ gzfile_calc_crc(struct gzfile *gz, VALUE str)
2702
2780
  }
2703
2781
  else {
2704
2782
  gz->crc = checksum_long(crc32, gz->crc, (Bytef*)RSTRING_PTR(str) + gz->ungetc,
2705
- RSTRING_LEN(str) - gz->ungetc);
2783
+ RSTRING_LEN(str) - gz->ungetc);
2706
2784
  gz->ungetc = 0;
2707
2785
  }
2708
2786
  }
@@ -2712,13 +2790,11 @@ gzfile_newstr(struct gzfile *gz, VALUE str)
2712
2790
  {
2713
2791
  if (!gz->enc2) {
2714
2792
  rb_enc_associate(str, gz->enc);
2715
- OBJ_TAINT(str); /* for safe */
2716
2793
  return str;
2717
2794
  }
2718
2795
  if (gz->ec && rb_enc_dummy_p(gz->enc2)) {
2719
2796
  str = rb_econv_str_convert(gz->ec, str, ECONV_PARTIAL_INPUT);
2720
2797
  rb_enc_associate(str, gz->enc);
2721
- OBJ_TAINT(str);
2722
2798
  return str;
2723
2799
  }
2724
2800
  return rb_str_conv_enc_opts(str, gz->enc2, gz->enc,
@@ -2732,16 +2808,16 @@ gzfile_fill(struct gzfile *gz, long len)
2732
2808
  rb_raise(rb_eArgError, "negative length %ld given", len);
2733
2809
  if (len == 0)
2734
2810
  return 0;
2735
- while (!ZSTREAM_IS_FINISHED(&gz->z) && gz->z.buf_filled < len) {
2736
- gzfile_read_more(gz);
2811
+ while (!ZSTREAM_IS_FINISHED(&gz->z) && ZSTREAM_BUF_FILLED(&gz->z) < len) {
2812
+ gzfile_read_more(gz, Qnil);
2737
2813
  }
2738
2814
  if (GZFILE_IS_FINISHED(gz)) {
2739
2815
  if (!(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) {
2740
- gzfile_check_footer(gz);
2816
+ gzfile_check_footer(gz, Qnil);
2741
2817
  }
2742
2818
  return -1;
2743
2819
  }
2744
- return len < gz->z.buf_filled ? len : gz->z.buf_filled;
2820
+ return len < ZSTREAM_BUF_FILLED(&gz->z) ? len : ZSTREAM_BUF_FILLED(&gz->z);
2745
2821
  }
2746
2822
 
2747
2823
  static VALUE
@@ -2765,9 +2841,6 @@ gzfile_readpartial(struct gzfile *gz, long len, VALUE outbuf)
2765
2841
  if (len < 0)
2766
2842
  rb_raise(rb_eArgError, "negative length %ld given", len);
2767
2843
 
2768
- if (!NIL_P(outbuf))
2769
- OBJ_TAINT(outbuf);
2770
-
2771
2844
  if (len == 0) {
2772
2845
  if (NIL_P(outbuf))
2773
2846
  return rb_str_new(0, 0);
@@ -2776,12 +2849,12 @@ gzfile_readpartial(struct gzfile *gz, long len, VALUE outbuf)
2776
2849
  return outbuf;
2777
2850
  }
2778
2851
  }
2779
- while (!ZSTREAM_IS_FINISHED(&gz->z) && gz->z.buf_filled == 0) {
2780
- gzfile_read_more(gz);
2852
+ while (!ZSTREAM_IS_FINISHED(&gz->z) && ZSTREAM_BUF_FILLED(&gz->z) == 0) {
2853
+ gzfile_read_more(gz, outbuf);
2781
2854
  }
2782
2855
  if (GZFILE_IS_FINISHED(gz)) {
2783
2856
  if (!(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) {
2784
- gzfile_check_footer(gz);
2857
+ gzfile_check_footer(gz, outbuf);
2785
2858
  }
2786
2859
  if (!NIL_P(outbuf))
2787
2860
  rb_str_resize(outbuf, 0);
@@ -2794,10 +2867,10 @@ gzfile_readpartial(struct gzfile *gz, long len, VALUE outbuf)
2794
2867
  if (!NIL_P(outbuf)) {
2795
2868
  rb_str_resize(outbuf, RSTRING_LEN(dst));
2796
2869
  memcpy(RSTRING_PTR(outbuf), RSTRING_PTR(dst), RSTRING_LEN(dst));
2797
- RB_GC_GUARD(dst);
2870
+ rb_str_resize(dst, 0);
2871
+ rb_gc_force_recycle(dst);
2798
2872
  dst = outbuf;
2799
2873
  }
2800
- OBJ_TAINT(dst); /* for safe */
2801
2874
  return dst;
2802
2875
  }
2803
2876
 
@@ -2807,11 +2880,11 @@ gzfile_read_all(struct gzfile *gz)
2807
2880
  VALUE dst;
2808
2881
 
2809
2882
  while (!ZSTREAM_IS_FINISHED(&gz->z)) {
2810
- gzfile_read_more(gz);
2883
+ gzfile_read_more(gz, Qnil);
2811
2884
  }
2812
2885
  if (GZFILE_IS_FINISHED(gz)) {
2813
2886
  if (!(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) {
2814
- gzfile_check_footer(gz);
2887
+ gzfile_check_footer(gz, Qnil);
2815
2888
  }
2816
2889
  return rb_str_new(0, 0);
2817
2890
  }
@@ -2819,7 +2892,6 @@ gzfile_read_all(struct gzfile *gz)
2819
2892
  dst = zstream_detach_buffer(&gz->z);
2820
2893
  if (NIL_P(dst)) return dst;
2821
2894
  gzfile_calc_crc(gz, dst);
2822
- OBJ_TAINT(dst);
2823
2895
  return gzfile_newstr(gz, dst);
2824
2896
  }
2825
2897
 
@@ -2830,12 +2902,12 @@ gzfile_getc(struct gzfile *gz)
2830
2902
  int len;
2831
2903
 
2832
2904
  len = rb_enc_mbmaxlen(gz->enc);
2833
- while (!ZSTREAM_IS_FINISHED(&gz->z) && gz->z.buf_filled < len) {
2834
- gzfile_read_more(gz);
2905
+ while (!ZSTREAM_IS_FINISHED(&gz->z) && ZSTREAM_BUF_FILLED(&gz->z) < len) {
2906
+ gzfile_read_more(gz, Qnil);
2835
2907
  }
2836
2908
  if (GZFILE_IS_FINISHED(gz)) {
2837
2909
  if (!(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) {
2838
- gzfile_check_footer(gz);
2910
+ gzfile_check_footer(gz, Qnil);
2839
2911
  }
2840
2912
  return Qnil;
2841
2913
  }
@@ -2843,22 +2915,18 @@ gzfile_getc(struct gzfile *gz)
2843
2915
  if (gz->ec && rb_enc_dummy_p(gz->enc2)) {
2844
2916
  const unsigned char *ss, *sp, *se;
2845
2917
  unsigned char *ds, *dp, *de;
2918
+ VALUE cbuf = rb_enc_str_new(0, GZFILE_CBUF_CAPA, gz->enc);
2846
2919
 
2847
- if (!gz->cbuf) {
2848
- gz->cbuf = ALLOC_N(char, GZFILE_CBUF_CAPA);
2849
- }
2850
2920
  ss = sp = (const unsigned char*)RSTRING_PTR(gz->z.buf);
2851
- se = sp + gz->z.buf_filled;
2852
- ds = dp = (unsigned char *)gz->cbuf;
2921
+ se = sp + ZSTREAM_BUF_FILLED(&gz->z);
2922
+ ds = dp = (unsigned char *)RSTRING_PTR(cbuf);
2853
2923
  de = (unsigned char *)ds + GZFILE_CBUF_CAPA;
2854
2924
  (void)rb_econv_convert(gz->ec, &sp, se, &dp, de, ECONV_PARTIAL_INPUT|ECONV_AFTER_OUTPUT);
2855
2925
  rb_econv_check_error(gz->ec);
2856
2926
  dst = zstream_shift_buffer(&gz->z, sp - ss);
2857
2927
  gzfile_calc_crc(gz, dst);
2858
- dst = rb_str_new(gz->cbuf, dp - ds);
2859
- rb_enc_associate(dst, gz->enc);
2860
- OBJ_TAINT(dst);
2861
- return dst;
2928
+ rb_str_resize(cbuf, dp - ds);
2929
+ return cbuf;
2862
2930
  }
2863
2931
  else {
2864
2932
  buf = gz->z.buf;
@@ -2905,7 +2973,7 @@ gzfile_writer_end(struct gzfile *gz)
2905
2973
  if (ZSTREAM_IS_CLOSING(&gz->z)) return;
2906
2974
  gz->z.flags |= ZSTREAM_FLAG_CLOSING;
2907
2975
 
2908
- rb_ensure(gzfile_writer_end_run, (VALUE)gz, zstream_end, (VALUE)&gz->z);
2976
+ rb_ensure(gzfile_writer_end_run, (VALUE)gz, zstream_ensure_end, (VALUE)&gz->z);
2909
2977
  }
2910
2978
 
2911
2979
  static VALUE
@@ -2915,7 +2983,7 @@ gzfile_reader_end_run(VALUE arg)
2915
2983
 
2916
2984
  if (GZFILE_IS_FINISHED(gz)
2917
2985
  && !(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) {
2918
- gzfile_check_footer(gz);
2986
+ gzfile_check_footer(gz, Qnil);
2919
2987
  }
2920
2988
 
2921
2989
  return Qnil;
@@ -2927,7 +2995,7 @@ gzfile_reader_end(struct gzfile *gz)
2927
2995
  if (ZSTREAM_IS_CLOSING(&gz->z)) return;
2928
2996
  gz->z.flags |= ZSTREAM_FLAG_CLOSING;
2929
2997
 
2930
- rb_ensure(gzfile_reader_end_run, (VALUE)gz, zstream_end, (VALUE)&gz->z);
2998
+ rb_ensure(gzfile_reader_end_run, (VALUE)gz, zstream_ensure_end, (VALUE)&gz->z);
2931
2999
  }
2932
3000
 
2933
3001
  static void
@@ -2952,12 +3020,11 @@ gzfile_reader_get_unused(struct gzfile *gz)
2952
3020
  if (!ZSTREAM_IS_READY(&gz->z)) return Qnil;
2953
3021
  if (!GZFILE_IS_FINISHED(gz)) return Qnil;
2954
3022
  if (!(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) {
2955
- gzfile_check_footer(gz);
3023
+ gzfile_check_footer(gz, Qnil);
2956
3024
  }
2957
3025
  if (NIL_P(gz->z.input)) return Qnil;
2958
3026
 
2959
3027
  str = rb_str_resurrect(gz->z.input);
2960
- OBJ_TAINT(str); /* for safe */
2961
3028
  return str;
2962
3029
  }
2963
3030
 
@@ -3024,7 +3091,7 @@ static VALUE
3024
3091
  new_wrap(VALUE tmp)
3025
3092
  {
3026
3093
  new_wrap_arg_t *arg = (new_wrap_arg_t *)tmp;
3027
- return rb_class_new_instance(arg->argc, arg->argv, arg->klass);
3094
+ return rb_class_new_instance_kw(arg->argc, arg->argv, arg->klass, RB_PASS_CALLED_KEYWORDS);
3028
3095
  }
3029
3096
 
3030
3097
  static VALUE
@@ -3057,7 +3124,7 @@ gzfile_wrap(int argc, VALUE *argv, VALUE klass, int close_io_on_error)
3057
3124
  }
3058
3125
  }
3059
3126
  else {
3060
- obj = rb_class_new_instance(argc, argv, klass);
3127
+ obj = rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
3061
3128
  }
3062
3129
 
3063
3130
  if (rb_block_given_p()) {
@@ -3174,7 +3241,6 @@ rb_gzfile_orig_name(VALUE obj)
3174
3241
  if (!NIL_P(str)) {
3175
3242
  str = rb_str_dup(str);
3176
3243
  }
3177
- OBJ_TAINT(str); /* for safe */
3178
3244
  return str;
3179
3245
  }
3180
3246
 
@@ -3191,7 +3257,6 @@ rb_gzfile_comment(VALUE obj)
3191
3257
  if (!NIL_P(str)) {
3192
3258
  str = rb_str_dup(str);
3193
3259
  }
3194
- OBJ_TAINT(str); /* for safe */
3195
3260
  return str;
3196
3261
  }
3197
3262
 
@@ -3250,6 +3315,7 @@ rb_gzfile_set_mtime(VALUE obj, VALUE mtime)
3250
3315
 
3251
3316
  val = rb_Integer(mtime);
3252
3317
  gz->mtime = NUM2UINT(val);
3318
+ gz->z.flags |= GZFILE_FLAG_MTIME_IS_SET;
3253
3319
 
3254
3320
  return mtime;
3255
3321
  }
@@ -3422,7 +3488,14 @@ static VALUE
3422
3488
  rb_gzfile_total_out(VALUE obj)
3423
3489
  {
3424
3490
  struct gzfile *gz = get_gzfile(obj);
3425
- return rb_uint2inum(gz->z.stream.total_out - gz->z.buf_filled);
3491
+ uLong total_out = gz->z.stream.total_out;
3492
+ long buf_filled = ZSTREAM_BUF_FILLED(&gz->z);
3493
+
3494
+ if (total_out >= (uLong)buf_filled) {
3495
+ return rb_uint2inum(total_out - buf_filled);
3496
+ } else {
3497
+ return LONG2FIX(-(buf_filled - (long)total_out));
3498
+ }
3426
3499
  }
3427
3500
 
3428
3501
  /*
@@ -3588,18 +3661,23 @@ rb_gzwriter_flush(int argc, VALUE *argv, VALUE obj)
3588
3661
  * Same as IO.
3589
3662
  */
3590
3663
  static VALUE
3591
- rb_gzwriter_write(VALUE obj, VALUE str)
3664
+ rb_gzwriter_write(int argc, VALUE *argv, VALUE obj)
3592
3665
  {
3593
3666
  struct gzfile *gz = get_gzfile(obj);
3594
-
3595
- if (!RB_TYPE_P(str, T_STRING))
3596
- str = rb_obj_as_string(str);
3597
- if (gz->enc2 && gz->enc2 != rb_ascii8bit_encoding()) {
3598
- str = rb_str_conv_enc(str, rb_enc_get(str), gz->enc2);
3667
+ size_t total = 0;
3668
+
3669
+ while (argc-- > 0) {
3670
+ VALUE str = *argv++;
3671
+ if (!RB_TYPE_P(str, T_STRING))
3672
+ str = rb_obj_as_string(str);
3673
+ if (gz->enc2 && gz->enc2 != rb_ascii8bit_encoding()) {
3674
+ str = rb_str_conv_enc(str, rb_enc_get(str), gz->enc2);
3675
+ }
3676
+ gzfile_write(gz, (Bytef*)RSTRING_PTR(str), RSTRING_LEN(str));
3677
+ total += RSTRING_LEN(str);
3678
+ RB_GC_GUARD(str);
3599
3679
  }
3600
- gzfile_write(gz, (Bytef*)RSTRING_PTR(str), RSTRING_LEN(str));
3601
- RB_GC_GUARD(str);
3602
- return INT2FIX(RSTRING_LEN(str));
3680
+ return SIZET2NUM(total);
3603
3681
  }
3604
3682
 
3605
3683
  /*
@@ -3714,6 +3792,60 @@ rb_gzreader_s_open(int argc, VALUE *argv, VALUE klass)
3714
3792
  return gzfile_s_open(argc, argv, klass, "rb");
3715
3793
  }
3716
3794
 
3795
+ /*
3796
+ * Document-method: Zlib::GzipReader.zcat
3797
+ *
3798
+ * call-seq:
3799
+ * Zlib::GzipReader.zcat(io, options = {}, &block) => nil
3800
+ * Zlib::GzipReader.zcat(io, options = {}) => string
3801
+ *
3802
+ * Decompresses all gzip data in the +io+, handling multiple gzip
3803
+ * streams until the end of the +io+. There should not be any non-gzip
3804
+ * data after the gzip streams.
3805
+ *
3806
+ * If a block is given, it is yielded strings of uncompressed data,
3807
+ * and the method returns +nil+.
3808
+ * If a block is not given, the method returns the concatenation of
3809
+ * all uncompressed data in all gzip streams.
3810
+ */
3811
+ static VALUE
3812
+ rb_gzreader_s_zcat(int argc, VALUE *argv, VALUE klass)
3813
+ {
3814
+ VALUE io, unused, obj, buf=0, tmpbuf;
3815
+ long pos;
3816
+
3817
+ rb_check_arity(argc, 1, 2);
3818
+ io = argv[0];
3819
+
3820
+ do {
3821
+ obj = rb_funcallv(klass, rb_intern("new"), argc, argv);
3822
+ if (rb_block_given_p()) {
3823
+ rb_gzreader_each(0, 0, obj);
3824
+ }
3825
+ else {
3826
+ if (!buf) {
3827
+ buf = rb_str_new(0, 0);
3828
+ }
3829
+ tmpbuf = gzfile_read_all(get_gzfile(obj));
3830
+ rb_str_cat(buf, RSTRING_PTR(tmpbuf), RSTRING_LEN(tmpbuf));
3831
+ }
3832
+
3833
+ rb_gzreader_read(0, 0, obj);
3834
+ pos = NUM2LONG(rb_funcall(io, rb_intern("pos"), 0));
3835
+ unused = rb_gzreader_unused(obj);
3836
+ rb_gzfile_finish(obj);
3837
+ if (!NIL_P(unused)) {
3838
+ pos -= NUM2LONG(rb_funcall(unused, rb_intern("length"), 0));
3839
+ rb_funcall(io, rb_intern("pos="), 1, LONG2NUM(pos));
3840
+ }
3841
+ } while (pos < NUM2LONG(rb_funcall(io, rb_intern("size"), 0)));
3842
+
3843
+ if (rb_block_given_p()) {
3844
+ return Qnil;
3845
+ }
3846
+ return buf;
3847
+ }
3848
+
3717
3849
  /*
3718
3850
  * Document-method: Zlib::GzipReader.new
3719
3851
  *
@@ -3748,7 +3880,7 @@ rb_gzreader_initialize(int argc, VALUE *argv, VALUE obj)
3748
3880
  }
3749
3881
  gz->io = io;
3750
3882
  ZSTREAM_READY(&gz->z);
3751
- gzfile_read_header(gz);
3883
+ gzfile_read_header(gz, Qnil);
3752
3884
  rb_gzfile_ecopts(gz, opt);
3753
3885
 
3754
3886
  if (rb_respond_to(io, id_path)) {
@@ -3940,20 +4072,6 @@ rb_gzreader_each_byte(VALUE obj)
3940
4072
  return Qnil;
3941
4073
  }
3942
4074
 
3943
- /*
3944
- * Document-method: Zlib::GzipReader#bytes
3945
- *
3946
- * This is a deprecated alias for <code>each_byte</code>.
3947
- */
3948
- static VALUE
3949
- rb_gzreader_bytes(VALUE obj)
3950
- {
3951
- rb_warn("Zlib::GzipReader#bytes is deprecated; use #each_byte instead");
3952
- if (!rb_block_given_p())
3953
- return rb_enumeratorize(obj, ID2SYM(rb_intern("each_byte")), 0, 0);
3954
- return rb_gzreader_each_byte(obj);
3955
- }
3956
-
3957
4075
  /*
3958
4076
  * Document-method: Zlib::GzipReader#ungetc
3959
4077
  *
@@ -3996,20 +4114,20 @@ gzreader_skip_linebreaks(struct gzfile *gz)
3996
4114
  char *p;
3997
4115
  int n;
3998
4116
 
3999
- while (gz->z.buf_filled == 0) {
4117
+ while (ZSTREAM_BUF_FILLED(&gz->z) == 0) {
4000
4118
  if (GZFILE_IS_FINISHED(gz)) return;
4001
- gzfile_read_more(gz);
4119
+ gzfile_read_more(gz, Qnil);
4002
4120
  }
4003
4121
  n = 0;
4004
4122
  p = RSTRING_PTR(gz->z.buf);
4005
4123
 
4006
4124
  while (n++, *(p++) == '\n') {
4007
- if (n >= gz->z.buf_filled) {
4125
+ if (n >= ZSTREAM_BUF_FILLED(&gz->z)) {
4008
4126
  str = zstream_detach_buffer(&gz->z);
4009
4127
  gzfile_calc_crc(gz, str);
4010
- while (gz->z.buf_filled == 0) {
4128
+ while (ZSTREAM_BUF_FILLED(&gz->z) == 0) {
4011
4129
  if (GZFILE_IS_FINISHED(gz)) return;
4012
- gzfile_read_more(gz);
4130
+ gzfile_read_more(gz, Qnil);
4013
4131
  }
4014
4132
  n = 0;
4015
4133
  p = RSTRING_PTR(gz->z.buf);
@@ -4031,7 +4149,7 @@ static long
4031
4149
  gzreader_charboundary(struct gzfile *gz, long n)
4032
4150
  {
4033
4151
  char *s = RSTRING_PTR(gz->z.buf);
4034
- char *e = s + gz->z.buf_filled;
4152
+ char *e = s + ZSTREAM_BUF_FILLED(&gz->z);
4035
4153
  char *p = rb_enc_left_char_head(s, s + n, e, gz->enc);
4036
4154
  long l = p - s;
4037
4155
  if (l < n) {
@@ -4126,25 +4244,25 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj)
4126
4244
  gzreader_skip_linebreaks(gz);
4127
4245
  }
4128
4246
 
4129
- while (gz->z.buf_filled < rslen) {
4247
+ while (ZSTREAM_BUF_FILLED(&gz->z) < rslen) {
4130
4248
  if (ZSTREAM_IS_FINISHED(&gz->z)) {
4131
- if (gz->z.buf_filled > 0) gz->lineno++;
4249
+ if (ZSTREAM_BUF_FILLED(&gz->z) > 0) gz->lineno++;
4132
4250
  return gzfile_read(gz, rslen);
4133
4251
  }
4134
- gzfile_read_more(gz);
4252
+ gzfile_read_more(gz, Qnil);
4135
4253
  }
4136
4254
 
4137
4255
  p = RSTRING_PTR(gz->z.buf);
4138
4256
  n = rslen;
4139
4257
  for (;;) {
4140
4258
  long filled;
4141
- if (n > gz->z.buf_filled) {
4259
+ if (n > ZSTREAM_BUF_FILLED(&gz->z)) {
4142
4260
  if (ZSTREAM_IS_FINISHED(&gz->z)) break;
4143
- gzfile_read_more(gz);
4261
+ gzfile_read_more(gz, Qnil);
4144
4262
  p = RSTRING_PTR(gz->z.buf) + n - rslen;
4145
4263
  }
4146
4264
  if (!rspara) rscheck(rsptr, rslen, rs);
4147
- filled = gz->z.buf_filled;
4265
+ filled = ZSTREAM_BUF_FILLED(&gz->z);
4148
4266
  if (limit > 0 && filled >= limit) {
4149
4267
  filled = limit;
4150
4268
  }
@@ -4161,7 +4279,7 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj)
4161
4279
  p++, n++;
4162
4280
  }
4163
4281
  }
4164
- if (maxlen > 1 && n == limit && (gz->z.buf_filled > n || !ZSTREAM_IS_FINISHED(&gz->z))) {
4282
+ if (maxlen > 1 && n == limit && (ZSTREAM_BUF_FILLED(&gz->z) > n || !ZSTREAM_IS_FINISHED(&gz->z))) {
4165
4283
  n = gzreader_charboundary(gz, n);
4166
4284
  }
4167
4285
 
@@ -4180,6 +4298,8 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj)
4180
4298
  * Document-method: Zlib::GzipReader#gets
4181
4299
  *
4182
4300
  * See Zlib::GzipReader documentation for a description.
4301
+ * However, note that this method can return +nil+ even if
4302
+ * #eof? returns false, unlike the behavior of File#gets.
4183
4303
  */
4184
4304
  static VALUE
4185
4305
  rb_gzreader_gets(int argc, VALUE *argv, VALUE obj)
@@ -4226,20 +4346,6 @@ rb_gzreader_each(int argc, VALUE *argv, VALUE obj)
4226
4346
  return obj;
4227
4347
  }
4228
4348
 
4229
- /*
4230
- * Document-method: Zlib::GzipReader#lines
4231
- *
4232
- * This is a deprecated alias for <code>each_line</code>.
4233
- */
4234
- static VALUE
4235
- rb_gzreader_lines(int argc, VALUE *argv, VALUE obj)
4236
- {
4237
- rb_warn("Zlib::GzipReader#lines is deprecated; use #each_line instead");
4238
- if (!rb_block_given_p())
4239
- return rb_enumeratorize(obj, ID2SYM(rb_intern("each_line")), argc, argv);
4240
- return rb_gzreader_each(argc, argv, obj);
4241
- }
4242
-
4243
4349
  /*
4244
4350
  * Document-method: Zlib::GzipReader#readlines
4245
4351
  *
@@ -4267,6 +4373,20 @@ rb_gzreader_external_encoding(VALUE self)
4267
4373
  return rb_enc_from_encoding(get_gzfile(self)->enc);
4268
4374
  }
4269
4375
 
4376
+ static VALUE
4377
+ zlib_gzip_end_rescue(VALUE arg)
4378
+ {
4379
+ struct gzfile *gz = (struct gzfile *)arg;
4380
+ gz->end(gz);
4381
+ return Qnil;
4382
+ }
4383
+
4384
+ static VALUE
4385
+ zlib_gzip_ensure(VALUE arg)
4386
+ {
4387
+ return rb_rescue(zlib_gzip_end_rescue, arg, NULL, Qnil);
4388
+ }
4389
+
4270
4390
  static void
4271
4391
  zlib_gzip_end(struct gzfile *gz)
4272
4392
  {
@@ -4276,9 +4396,8 @@ zlib_gzip_end(struct gzfile *gz)
4276
4396
  zstream_end(&gz->z);
4277
4397
  }
4278
4398
 
4279
- #define OPTHASH_GIVEN_P(opts) \
4280
- (argc > 0 && !NIL_P((opts) = rb_check_hash_type(argv[argc-1])) && (--argc, 1))
4281
4399
  static ID id_level, id_strategy;
4400
+ static VALUE zlib_gzip_run(VALUE arg);
4282
4401
 
4283
4402
  /*
4284
4403
  * call-seq:
@@ -4307,9 +4426,8 @@ zlib_s_gzip(int argc, VALUE *argv, VALUE klass)
4307
4426
  {
4308
4427
  struct gzfile gz0;
4309
4428
  struct gzfile *gz = &gz0;
4310
- long len;
4311
4429
  int err;
4312
- VALUE src, opts, level=Qnil, strategy=Qnil;
4430
+ VALUE src, opts, level=Qnil, strategy=Qnil, args[2];
4313
4431
 
4314
4432
  if (OPTHASH_GIVEN_P(opts)) {
4315
4433
  ID keyword_ids[2];
@@ -4331,9 +4449,23 @@ zlib_s_gzip(int argc, VALUE *argv, VALUE klass)
4331
4449
  err = deflateInit2(&gz->z.stream, gz->level, Z_DEFLATED,
4332
4450
  -MAX_WBITS, DEF_MEM_LEVEL, ARG_STRATEGY(strategy));
4333
4451
  if (err != Z_OK) {
4452
+ zlib_gzip_end(gz);
4334
4453
  raise_zlib_error(err, gz->z.stream.msg);
4335
4454
  }
4336
4455
  ZSTREAM_READY(&gz->z);
4456
+ args[0] = (VALUE)gz;
4457
+ args[1] = src;
4458
+ return rb_ensure(zlib_gzip_run, (VALUE)args, zlib_gzip_ensure, (VALUE)gz);
4459
+ }
4460
+
4461
+ static VALUE
4462
+ zlib_gzip_run(VALUE arg)
4463
+ {
4464
+ VALUE *args = (VALUE *)arg;
4465
+ struct gzfile *gz = (struct gzfile *)args[0];
4466
+ VALUE src = args[1];
4467
+ long len;
4468
+
4337
4469
  gzfile_make_header(gz);
4338
4470
  len = RSTRING_LEN(src);
4339
4471
  if (len > 0) {
@@ -4349,10 +4481,11 @@ static void
4349
4481
  zlib_gunzip_end(struct gzfile *gz)
4350
4482
  {
4351
4483
  gz->z.flags |= ZSTREAM_FLAG_CLOSING;
4352
- gzfile_check_footer(gz);
4353
4484
  zstream_end(&gz->z);
4354
4485
  }
4355
4486
 
4487
+ static VALUE zlib_gunzip_run(VALUE arg);
4488
+
4356
4489
  /*
4357
4490
  * call-seq:
4358
4491
  * Zlib.gunzip(src) -> String
@@ -4377,7 +4510,6 @@ zlib_gunzip(VALUE klass, VALUE src)
4377
4510
  struct gzfile gz0;
4378
4511
  struct gzfile *gz = &gz0;
4379
4512
  int err;
4380
- VALUE dst;
4381
4513
 
4382
4514
  StringValue(src);
4383
4515
 
@@ -4389,15 +4521,25 @@ zlib_gunzip(VALUE klass, VALUE src)
4389
4521
  gz->io = Qundef;
4390
4522
  gz->z.input = src;
4391
4523
  ZSTREAM_READY(&gz->z);
4392
- gzfile_read_header(gz);
4524
+ return rb_ensure(zlib_gunzip_run, (VALUE)gz, zlib_gzip_ensure, (VALUE)gz);
4525
+ }
4526
+
4527
+ static VALUE
4528
+ zlib_gunzip_run(VALUE arg)
4529
+ {
4530
+ struct gzfile *gz = (struct gzfile *)arg;
4531
+ VALUE dst;
4532
+
4533
+ gzfile_read_header(gz, Qnil);
4393
4534
  dst = zstream_detach_buffer(&gz->z);
4394
4535
  gzfile_calc_crc(gz, dst);
4395
- if (!ZSTREAM_IS_FINISHED(&gz->z)) {
4396
- rb_raise(cGzError, "unexpected end of file");
4397
- }
4398
- if (NIL_P(gz->z.input))
4536
+ if (!ZSTREAM_IS_FINISHED(&gz->z)) {
4537
+ rb_raise(cGzError, "unexpected end of file");
4538
+ }
4539
+ if (NIL_P(gz->z.input)) {
4399
4540
  rb_raise(cNoFooter, "footer is not found");
4400
- gzfile_check_footer(gz);
4541
+ }
4542
+ gzfile_check_footer(gz, Qnil);
4401
4543
  return dst;
4402
4544
  }
4403
4545
 
@@ -4406,6 +4548,11 @@ zlib_gunzip(VALUE klass, VALUE src)
4406
4548
  void
4407
4549
  Init_zlib(void)
4408
4550
  {
4551
+ #if HAVE_RB_EXT_RACTOR_SAFE
4552
+ rb_ext_ractor_safe(true);
4553
+ #endif
4554
+
4555
+ #undef rb_intern
4409
4556
  VALUE mZlib, cZStream, cDeflate, cInflate;
4410
4557
  #if GZIP_SUPPORT
4411
4558
  VALUE cGzipFile, cGzipWriter, cGzipReader;
@@ -4499,7 +4646,7 @@ Init_zlib(void)
4499
4646
  rb_define_alloc_func(cInflate, rb_inflate_s_allocate);
4500
4647
  rb_define_method(cInflate, "initialize", rb_inflate_initialize, -1);
4501
4648
  rb_define_method(cInflate, "add_dictionary", rb_inflate_add_dictionary, 1);
4502
- rb_define_method(cInflate, "inflate", rb_inflate_inflate, 1);
4649
+ rb_define_method(cInflate, "inflate", rb_inflate_inflate, -1);
4503
4650
  rb_define_method(cInflate, "<<", rb_inflate_addstr, 1);
4504
4651
  rb_define_method(cInflate, "sync", rb_inflate_sync, 1);
4505
4652
  rb_define_method(cInflate, "sync_point?", rb_inflate_sync_point_p, 0);
@@ -4640,7 +4787,7 @@ Init_zlib(void)
4640
4787
  rb_define_alloc_func(cGzipWriter, rb_gzwriter_s_allocate);
4641
4788
  rb_define_method(cGzipWriter, "initialize", rb_gzwriter_initialize,-1);
4642
4789
  rb_define_method(cGzipWriter, "flush", rb_gzwriter_flush, -1);
4643
- rb_define_method(cGzipWriter, "write", rb_gzwriter_write, 1);
4790
+ rb_define_method(cGzipWriter, "write", rb_gzwriter_write, -1);
4644
4791
  rb_define_method(cGzipWriter, "putc", rb_gzwriter_putc, 1);
4645
4792
  rb_define_method(cGzipWriter, "<<", rb_gzwriter_addstr, 1);
4646
4793
  rb_define_method(cGzipWriter, "printf", rb_gzwriter_printf, -1);
@@ -4648,6 +4795,7 @@ Init_zlib(void)
4648
4795
  rb_define_method(cGzipWriter, "puts", rb_gzwriter_puts, -1);
4649
4796
 
4650
4797
  rb_define_singleton_method(cGzipReader, "open", rb_gzreader_s_open,-1);
4798
+ rb_define_singleton_method(cGzipReader, "zcat", rb_gzreader_s_zcat, -1);
4651
4799
  rb_define_alloc_func(cGzipReader, rb_gzreader_s_allocate);
4652
4800
  rb_define_method(cGzipReader, "initialize", rb_gzreader_initialize, -1);
4653
4801
  rb_define_method(cGzipReader, "rewind", rb_gzreader_rewind, 0);
@@ -4660,14 +4808,12 @@ Init_zlib(void)
4660
4808
  rb_define_method(cGzipReader, "readbyte", rb_gzreader_readbyte, 0);
4661
4809
  rb_define_method(cGzipReader, "each_byte", rb_gzreader_each_byte, 0);
4662
4810
  rb_define_method(cGzipReader, "each_char", rb_gzreader_each_char, 0);
4663
- rb_define_method(cGzipReader, "bytes", rb_gzreader_bytes, 0);
4664
4811
  rb_define_method(cGzipReader, "ungetc", rb_gzreader_ungetc, 1);
4665
4812
  rb_define_method(cGzipReader, "ungetbyte", rb_gzreader_ungetbyte, 1);
4666
4813
  rb_define_method(cGzipReader, "gets", rb_gzreader_gets, -1);
4667
4814
  rb_define_method(cGzipReader, "readline", rb_gzreader_readline, -1);
4668
4815
  rb_define_method(cGzipReader, "each", rb_gzreader_each, -1);
4669
4816
  rb_define_method(cGzipReader, "each_line", rb_gzreader_each, -1);
4670
- rb_define_method(cGzipReader, "lines", rb_gzreader_lines, -1);
4671
4817
  rb_define_method(cGzipReader, "readlines", rb_gzreader_readlines, -1);
4672
4818
  rb_define_method(cGzipReader, "external_encoding", rb_gzreader_external_encoding, 0);
4673
4819
 
@@ -4709,6 +4855,7 @@ Init_zlib(void)
4709
4855
 
4710
4856
  id_level = rb_intern("level");
4711
4857
  id_strategy = rb_intern("strategy");
4858
+ id_buffer = rb_intern("buffer");
4712
4859
  #endif /* GZIP_SUPPORT */
4713
4860
  }
4714
4861
 
@@ -4829,5 +4976,3 @@ Init_zlib(void)
4829
4976
  * Raised when the data length recorded in the gzip file footer is not equivalent
4830
4977
  * to the length of the actual uncompressed data.
4831
4978
  */
4832
-
4833
-