@@ -56,7 +56,10 @@ max_uint(long n)
56
56
#define MAX_UINT (n ) (uInt)(n)
57
57
#endif
58
58
59
- static ID id_dictionaries , id_read ;
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 ;
60
63
61
64
/*--------- Prototypes --------*/
62
65
@@ -130,7 +133,7 @@ static VALUE rb_inflate_s_allocate(VALUE);
130
133
static VALUE rb_inflate_initialize (int , VALUE * , VALUE );
131
134
static VALUE rb_inflate_s_inflate (VALUE , VALUE );
132
135
static void do_inflate (struct zstream * , VALUE );
133
- static VALUE rb_inflate_inflate (VALUE , VALUE );
136
+ static VALUE rb_inflate_inflate (int , VALUE * , VALUE );
134
137
static VALUE rb_inflate_addstr (VALUE , VALUE );
135
138
static VALUE rb_inflate_sync (VALUE , VALUE );
136
139
static VALUE rb_inflate_sync_point_p (VALUE );
@@ -557,7 +560,8 @@ struct zstream {
557
560
#define ZSTREAM_FLAG_CLOSING 0x8
558
561
#define ZSTREAM_FLAG_GZFILE 0x10 /* disallows yield from expand_buffer for
559
562
gzip*/
560
- #define ZSTREAM_FLAG_UNUSED 0x20
563
+ #define ZSTREAM_REUSE_BUFFER 0x20
564
+ #define ZSTREAM_FLAG_UNUSED 0x40
561
565
562
566
#define ZSTREAM_READY (z ) ((z)->flags |= ZSTREAM_FLAG_READY)
563
567
#define ZSTREAM_IS_READY (z ) ((z)->flags & ZSTREAM_FLAG_READY)
@@ -566,6 +570,8 @@ struct zstream {
566
570
#define ZSTREAM_IS_GZFILE (z ) ((z)->flags & ZSTREAM_FLAG_GZFILE)
567
571
#define ZSTREAM_BUF_FILLED (z ) (NIL_P((z)->buf) ? 0 : RSTRING_LEN((z)->buf))
568
572
573
+ #define ZSTREAM_REUSE_BUFFER_P (z ) ((z)->flags & ZSTREAM_REUSE_BUFFER)
574
+
569
575
#define ZSTREAM_EXPAND_BUFFER_OK 0
570
576
571
577
/* I think that more better value should be found,
@@ -642,11 +648,19 @@ zstream_expand_buffer(struct zstream *z)
642
648
if (buf_filled >= ZSTREAM_AVAIL_OUT_STEP_MAX ) {
643
649
int state = 0 ;
644
650
645
- rb_obj_reveal (z -> buf , rb_cString );
651
+ if (!ZSTREAM_REUSE_BUFFER_P (z )) {
652
+ rb_obj_reveal (z -> buf , rb_cString );
653
+ }
646
654
647
655
rb_protect (rb_yield , z -> buf , & state );
648
656
649
- 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
+ }
650
664
zstream_expand_buffer_into (z , ZSTREAM_AVAIL_OUT_STEP_MAX );
651
665
652
666
if (state )
@@ -764,7 +778,9 @@ zstream_detach_buffer(struct zstream *z)
764
778
}
765
779
else {
766
780
dst = z -> buf ;
767
- rb_obj_reveal (dst , rb_cString );
781
+ if (!ZSTREAM_REUSE_BUFFER_P (z )) {
782
+ rb_obj_reveal (dst , rb_cString );
783
+ }
768
784
}
769
785
770
786
z -> buf = Qnil ;
@@ -2013,8 +2029,8 @@ rb_inflate_add_dictionary(VALUE obj, VALUE dictionary)
2013
2029
* Document-method: Zlib::Inflate#inflate
2014
2030
*
2015
2031
* call-seq:
2016
- * inflate(deflate_string) -> String
2017
- * inflate(deflate_string) { |chunk| ... } -> nil
2032
+ * inflate(deflate_string, buffer: nil ) -> String
2033
+ * inflate(deflate_string, buffer: nil ) { |chunk| ... } -> nil
2018
2034
*
2019
2035
* Inputs +deflate_string+ into the inflate stream and returns the output from
2020
2036
* the stream. Calling this method, both the input and the output buffer of
@@ -2024,6 +2040,15 @@ rb_inflate_add_dictionary(VALUE obj, VALUE dictionary)
2024
2040
* If a block is given consecutive inflated chunks from the +deflate_string+
2025
2041
* are yielded to the block and +nil+ is returned.
2026
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
+ *
2027
2052
* Raises a Zlib::NeedDict exception if a preset dictionary is needed to
2028
2053
* decompress. Set the dictionary by Zlib::Inflate#set_dictionary and then
2029
2054
* call this method again with an empty string to flush the stream:
@@ -2047,10 +2072,37 @@ rb_inflate_add_dictionary(VALUE obj, VALUE dictionary)
2047
2072
* See also Zlib::Inflate.new
2048
2073
*/
2049
2074
static VALUE
2050
- rb_inflate_inflate (VALUE obj , VALUE src )
2075
+ rb_inflate_inflate (int argc , VALUE * argv , VALUE obj )
2051
2076
{
2052
2077
struct zstream * z = get_zstream (obj );
2053
- VALUE dst ;
2078
+ VALUE dst , src , opts , buffer = Qnil ;
2079
+
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 );
2054
2106
2055
2107
if (ZSTREAM_IS_FINISHED (z )) {
2056
2108
if (NIL_P (src )) {
@@ -2059,7 +2111,11 @@ rb_inflate_inflate(VALUE obj, VALUE src)
2059
2111
else {
2060
2112
StringValue (src );
2061
2113
zstream_append_buffer2 (z , src );
2062
- dst = rb_str_new (0 , 0 );
2114
+ if (ZSTREAM_REUSE_BUFFER_P (z )) {
2115
+ dst = rb_str_resize (buffer , 0 );
2116
+ } else {
2117
+ dst = rb_str_new (0 , 0 );
2118
+ }
2063
2119
}
2064
2120
}
2065
2121
else {
@@ -4368,8 +4424,6 @@ zlib_gzip_end(struct gzfile *gz)
4368
4424
zstream_end (& gz -> z );
4369
4425
}
4370
4426
4371
- #define OPTHASH_GIVEN_P (opts ) \
4372
- (argc > 0 && !NIL_P((opts) = rb_check_hash_type(argv[argc-1])) && (--argc, 1))
4373
4427
static ID id_level , id_strategy ;
4374
4428
static VALUE zlib_gzip_run (VALUE arg );
4375
4429
@@ -4616,7 +4670,7 @@ Init_zlib(void)
4616
4670
rb_define_alloc_func (cInflate , rb_inflate_s_allocate );
4617
4671
rb_define_method (cInflate , "initialize" , rb_inflate_initialize , -1 );
4618
4672
rb_define_method (cInflate , "add_dictionary" , rb_inflate_add_dictionary , 1 );
4619
- rb_define_method (cInflate , "inflate" , rb_inflate_inflate , 1 );
4673
+ rb_define_method (cInflate , "inflate" , rb_inflate_inflate , - 1 );
4620
4674
rb_define_method (cInflate , "<<" , rb_inflate_addstr , 1 );
4621
4675
rb_define_method (cInflate , "sync" , rb_inflate_sync , 1 );
4622
4676
rb_define_method (cInflate , "sync_point?" , rb_inflate_sync_point_p , 0 );
@@ -4827,6 +4881,7 @@ Init_zlib(void)
4827
4881
4828
4882
id_level = rb_intern ("level" );
4829
4883
id_strategy = rb_intern ("strategy" );
4884
+ id_buffer = rb_intern ("buffer" );
4830
4885
#endif /* GZIP_SUPPORT */
4831
4886
}
4832
4887
0 commit comments