zlib 0.0.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
-