Project

General

Profile

Feature #6612 ยป zlib.inflate_deflate_chunked.patch

Fixed patch - drbrain (Eric Hodel), 06/20/2012 03:43 PM

View differences:

ext/zlib/zlib.c (working copy)
543 543
#define ZSTREAM_FLAG_IN_STREAM  0x2
544 544
#define ZSTREAM_FLAG_FINISHED   0x4
545 545
#define ZSTREAM_FLAG_CLOSING    0x8
546
#define ZSTREAM_FLAG_UNUSED     0x10
546
#define ZSTREAM_FLAG_GZFILE     0x10
547
#define ZSTREAM_FLAG_UNUSED     0x20
547 548

  
548 549
#define ZSTREAM_READY(z)       ((z)->flags |= ZSTREAM_FLAG_READY)
549 550
#define ZSTREAM_IS_READY(z)    ((z)->flags & ZSTREAM_FLAG_READY)
550 551
#define ZSTREAM_IS_FINISHED(z) ((z)->flags & ZSTREAM_FLAG_FINISHED)
551 552
#define ZSTREAM_IS_CLOSING(z)  ((z)->flags & ZSTREAM_FLAG_CLOSING)
553
#define ZSTREAM_IS_GZFILE(z)   ((z)->flags & ZSTREAM_FLAG_GZFILE)
552 554

  
553 555
/* I think that more better value should be found,
554 556
   but I gave up finding it. B) */
......
607 609
static void
608 610
zstream_expand_buffer(struct zstream *z)
609 611
{
610
    long inc;
611

  
612 612
    if (NIL_P(z->buf)) {
613
	    /* I uses rb_str_new here not rb_str_buf_new because
614
	       rb_str_buf_new makes a zero-length string. */
615
	z->buf = rb_str_new(0, ZSTREAM_INITIAL_BUFSIZE);
616
	z->buf_filled = 0;
617
	z->stream.next_out = (Bytef*)RSTRING_PTR(z->buf);
618
	z->stream.avail_out = ZSTREAM_INITIAL_BUFSIZE;
619
	RBASIC(z->buf)->klass = 0;
613
	zstream_expand_buffer_into(z, ZSTREAM_INITIAL_BUFSIZE);
620 614
	return;
621 615
    }
622 616

  
623
    if (RSTRING_LEN(z->buf) - z->buf_filled >= ZSTREAM_AVAIL_OUT_STEP_MAX) {
624
	/* to keep other threads from freezing */
625
	z->stream.avail_out = ZSTREAM_AVAIL_OUT_STEP_MAX;
617
    if (!ZSTREAM_IS_GZFILE(z) && rb_block_given_p()) {
618
	if (z->buf_filled >= ZSTREAM_AVAIL_OUT_STEP_MAX) {
619
	    int state = 0;
620
	    VALUE self = (VALUE)z->stream.opaque;
621

  
622
	    rb_str_resize(z->buf, z->buf_filled);
623
	    RBASIC(z->buf)->klass = rb_cString;
624
	    OBJ_INFECT(z->buf, self);
625

  
626
	    rb_protect(rb_yield, z->buf, &state);
627

  
628
	    z->buf = Qnil;
629
	    zstream_expand_buffer_into(z, ZSTREAM_AVAIL_OUT_STEP_MAX);
630

  
631
	    if (state)
632
		rb_jump_tag(state);
633

  
634
	    return;
635
	}
636
	else {
637
	    zstream_expand_buffer_into(z,
638
		    ZSTREAM_AVAIL_OUT_STEP_MAX - z->buf_filled);
639
	}
626 640
    }
627 641
    else {
628
	inc = z->buf_filled / 2;
629
	if (inc < ZSTREAM_AVAIL_OUT_STEP_MIN) {
630
	    inc = ZSTREAM_AVAIL_OUT_STEP_MIN;
631
	}
632
	rb_str_resize(z->buf, z->buf_filled + inc);
633
	z->stream.avail_out = (inc < ZSTREAM_AVAIL_OUT_STEP_MAX) ?
634
	    (int)inc : ZSTREAM_AVAIL_OUT_STEP_MAX;
642
	if (RSTRING_LEN(z->buf) - z->buf_filled >= ZSTREAM_AVAIL_OUT_STEP_MAX) {
643
	    /* to keep other threads from freezing */
644
	    z->stream.avail_out = ZSTREAM_AVAIL_OUT_STEP_MAX;
645
	}
646
	else {
647
	    long inc = z->buf_filled / 2;
648
	    if (inc < ZSTREAM_AVAIL_OUT_STEP_MIN) {
649
		inc = ZSTREAM_AVAIL_OUT_STEP_MIN;
650
	    }
651
	    rb_str_resize(z->buf, z->buf_filled + inc);
652
	    z->stream.avail_out = (inc < ZSTREAM_AVAIL_OUT_STEP_MAX) ?
653
		(int)inc : ZSTREAM_AVAIL_OUT_STEP_MAX;
654
	}
655
	z->stream.next_out = (Bytef*)RSTRING_PTR(z->buf) + z->buf_filled;
635 656
    }
636
    z->stream.next_out = (Bytef*)RSTRING_PTR(z->buf) + z->buf_filled;
637 657
}
638 658

  
639 659
static void
......
691 711
static VALUE
692 712
zstream_detach_buffer(struct zstream *z)
693 713
{
694
    VALUE dst;
714
    VALUE dst, self = (VALUE)z->stream.opaque;
695 715

  
696 716
    if (NIL_P(z->buf)) {
697 717
	dst = rb_str_new(0, 0);
......
702 722
	RBASIC(dst)->klass = rb_cString;
703 723
    }
704 724

  
725
    OBJ_INFECT(dst, self);
726

  
705 727
    z->buf = Qnil;
706 728
    z->buf_filled = 0;
707 729
    z->stream.next_out = 0;
708 730
    z->stream.avail_out = 0;
731

  
732
    if (!ZSTREAM_IS_GZFILE(z) && rb_block_given_p()) {
733
	rb_yield(dst);
734
	dst = Qnil;
735
    }
736

  
709 737
    return dst;
710 738
}
711 739

  
......
871 899
    return Qnil;
872 900
}
873 901

  
874
static void
875
zstream_run(struct zstream *z, Bytef *src, long len, int flush)
876
{
902
static VALUE
903
zstream_run_loop(VALUE loop_args) {
904
    struct zstream *z;
877 905
    uInt n;
878
    int err;
879
    volatile VALUE guard = Qnil;
880

  
881
    if (NIL_P(z->input) && len == 0) {
882
	z->stream.next_in = (Bytef*)"";
883
	z->stream.avail_in = 0;
884
    }
885
    else {
886
	zstream_append_input(z, src, len);
887
	z->stream.next_in = (Bytef*)RSTRING_PTR(z->input);
888
	z->stream.avail_in = MAX_UINT(RSTRING_LEN(z->input));
889
	/* keep reference to `z->input' so as not to be garbage collected
890
	   after zstream_reset_input() and prevent `z->stream.next_in'
891
	   from dangling. */
892
	guard = z->input;
893
    }
906
    int err, flush;
894 907

  
895
    if (z->stream.avail_out == 0) {
896
	zstream_expand_buffer(z);
897
    }
908
    z = (struct zstream *)((VALUE *)loop_args)[0];
909
    flush = (int)((VALUE*)loop_args)[1];
898 910

  
899 911
    for (;;) {
900
	/* VC allocates err and guard to same address.  accessing err and guard
901
	   in same scope prevents it. */
902
	RB_GC_GUARD(guard);
903 912
	n = z->stream.avail_out;
904 913
	err = z->func->run(&z->stream, flush);
905 914
	z->buf_filled += n - z->stream.avail_out;
......
929 938
		    continue;
930 939
		}
931 940
	    }
932
	    raise_zlib_error(err, z->stream.msg);
941

  
942
	    /* Z_BUF_ERROR with Z_FINISH is normal, continue expanding output
943
	     * buffer */
944
	    if (flush != Z_FINISH && err != Z_BUF_ERROR)
945
		raise_zlib_error(err, z->stream.msg);
933 946
	}
934 947
	if (z->stream.avail_out > 0) {
935 948
	    z->flags |= ZSTREAM_FLAG_IN_STREAM;
......
938 951
	zstream_expand_buffer(z);
939 952
    }
940 953

  
954
    return Qnil;
955
}
956

  
957
static void
958
zstream_run(struct zstream *z, Bytef *src, long len, int flush)
959
{
960
    int state;
961
    VALUE loop_args[2];
962
    volatile VALUE guard = Qnil;
963

  
964
    if (NIL_P(z->input) && len == 0) {
965
	z->stream.next_in = (Bytef*)"";
966
	z->stream.avail_in = 0;
967
    }
968
    else {
969
	zstream_append_input(z, src, len);
970
	z->stream.next_in = (Bytef*)RSTRING_PTR(z->input);
971
	z->stream.avail_in = MAX_UINT(RSTRING_LEN(z->input));
972
	/* keep reference to `z->input' so as not to be garbage collected
973
	   after zstream_reset_input() and prevent `z->stream.next_in'
974
	   from dangling. */
975
	guard = z->input;
976
    }
977

  
978
    if (z->stream.avail_out == 0) {
979
	zstream_expand_buffer(z);
980
    }
981

  
982
    loop_args[0] = (VALUE)z;
983
    loop_args[1] = (VALUE)flush;
984

  
985
    rb_protect(zstream_run_loop, (VALUE)loop_args, &state);
986

  
941 987
    zstream_reset_input(z);
942 988
    if (z->stream.avail_in > 0) {
943 989
	zstream_append_input(z, z->stream.next_in, z->stream.avail_in);
944
        guard = Qnil; /* prevent tail call to make guard effective */
990
	guard = Qnil; /* prevent tail call to make guard effective */
945 991
    }
992

  
993
    if (state)
994
	rb_jump_tag(state);
946 995
}
947 996

  
948 997
static VALUE
......
1125 1174
}
1126 1175

  
1127 1176
/*
1128
 * Finishes the stream and flushes output buffer. See Zlib::Deflate#finish and
1129
 * Zlib::Inflate#finish for details of this behavior.
1177
 * call-seq:
1178
 *   finish                 -> String
1179
 *   finish { |chunk| ... } -> nil
1180
 *
1181
 * Finishes the stream and flushes output buffer.  If a block is given each
1182
 * chunk is yielded to the block until the input buffer has been flushed to
1183
 * the output buffer.
1130 1184
 */
1131 1185
static VALUE
1132 1186
rb_zstream_finish(VALUE obj)
1133 1187
{
1134 1188
    struct zstream *z = get_zstream(obj);
1135
    VALUE dst;
1136 1189

  
1137 1190
    zstream_run(z, (Bytef*)"", 0, Z_FINISH);
1138
    dst = zstream_detach_buffer(z);
1139 1191

  
1140
    OBJ_INFECT(dst, obj);
1141
    return dst;
1192
    return zstream_detach_buffer(z);
1142 1193
}
1143 1194

  
1144 1195
/*
......
1157 1208
}
1158 1209

  
1159 1210
/*
1160
 * Flushes output buffer and returns all data in that buffer.
1211
 * call-seq:
1212
 *   flush_next_out                 -> String
1213
 *   flush_next_out { |chunk| ... } -> nil
1214
 *
1215
 * Flushes output buffer and returns all data in that buffer.  If a block is
1216
 * given each chunk is yielded to the block until the current output buffer
1217
 * has been flushed.
1161 1218
 */
1162 1219
static VALUE
1163 1220
rb_zstream_flush_next_out(VALUE obj)
1164 1221
{
1165 1222
    struct zstream *z;
1166
    VALUE dst;
1167 1223

  
1168 1224
    Data_Get_Struct(obj, struct zstream, z);
1169
    dst = zstream_detach_buffer(z);
1170
    OBJ_INFECT(dst, obj);
1171
    return dst;
1225

  
1226
    return zstream_detach_buffer(z);
1172 1227
}
1173 1228

  
1174 1229
/*
......
1426 1481
/*
1427 1482
 * Document-method: Zlib::Deflate.deflate
1428 1483
 *
1429
 * call-seq: Zlib.deflate(string[, level])
1430
 *           Zlib::Deflate.deflate(string[, level])
1484
 * call-seq:
1485
 *   Zlib.deflate(string[, level])
1486
 *   Zlib::Deflate.deflate(string[, level])
1431 1487
 *
1432 1488
 * Compresses the given +string+. Valid values of level are
1433
 * <tt>NO_COMPRESSION</tt>, <tt>BEST_SPEED</tt>,
1434
 * <tt>BEST_COMPRESSION</tt>, <tt>DEFAULT_COMPRESSION</tt>, and an
1435
 * integer from 0 to 9 (the default is 6).
1489
 * Zlib::NO_COMPRESSION, Zlib::BEST_SPEED, * Zlib::BEST_COMPRESSION,
1490
 * Zlib::DEFAULT_COMPRESSION, or an integer from 0 to 9 (the default is 6).
1436 1491
 *
1437 1492
 * This method is almost equivalent to the following code:
1438 1493
 *
......
1486 1541
}
1487 1542

  
1488 1543
/*
1489
 * Document-method: Zlib#deflate
1544
 * Document-method: Zlib::Deflate#deflate
1490 1545
 *
1491 1546
 * call-seq:
1492
 *   deflate(string, flush = Zlib::NO_FLUSH)
1547
 *   z.deflate(string, flush = Zlib::NO_FLUSH)                 -> String
1548
 *   z.deflate(string, flush = Zlib::NO_FLUSH) { |chunk| ... } -> nil
1493 1549
 *
1494 1550
 * Inputs +string+ into the deflate stream and returns the output from the
1495 1551
 * stream.  On calling this method, both the input and the output buffers of
1496
 * the stream are flushed.
1552
 * the stream are flushed.  If +string+ is nil, this method finishes the
1553
 * stream, just like Zlib::ZStream#finish.
1497 1554
 *
1498
 * If +string+ is nil, this method finishes the stream, just like
1499
 * Zlib::ZStream#finish.
1555
 * If a block is given consecutive deflated chunks from the +string+ are
1556
 * yielded to the block and +nil+ is returned.
1500 1557
 *
1501 1558
 * The +flush+ parameter specifies the flush mode.  The following constants
1502 1559
 * may be used:
......
1513 1570
rb_deflate_deflate(int argc, VALUE *argv, VALUE obj)
1514 1571
{
1515 1572
    struct zstream *z = get_zstream(obj);
1516
    VALUE src, flush, dst;
1573
    VALUE src, flush;
1517 1574

  
1518 1575
    rb_scan_args(argc, argv, "11", &src, &flush);
1519 1576
    OBJ_INFECT(obj, src);
1520 1577
    do_deflate(z, src, ARG_FLUSH(flush));
1521
    dst = zstream_detach_buffer(z);
1522 1578

  
1523
    OBJ_INFECT(dst, obj);
1524
    return dst;
1579
    return zstream_detach_buffer(z);
1525 1580
}
1526 1581

  
1527 1582
/*
......
1545 1600
 * Document-method: Zlib::Deflate#flush
1546 1601
 *
1547 1602
 * call-seq:
1548
 *   flush(flush = Zlib::SYNC_FLUSH)
1603
 *   flush(flush = Zlib::SYNC_FLUSH)                 -> String
1604
 *   flush(flush = Zlib::SYNC_FLUSH) { |chunk| ... } -> nil
1549 1605
 *
1550 1606
 * This method is equivalent to <tt>deflate('', flush)</tt>. This method is
1551
 * just provided to improve the readability of your Ruby program.
1607
 * just provided to improve the readability of your Ruby program.  If a block
1608
 * is given chunks of deflate output are yielded to the block until the buffer
1609
 * is flushed.
1552 1610
 *
1553 1611
 * See Zlib::Deflate#deflate for detail on the +flush+ constants NO_FLUSH,
1554 1612
 * SYNC_FLUSH, FULL_FLUSH and FINISH.
......
1557 1615
rb_deflate_flush(int argc, VALUE *argv, VALUE obj)
1558 1616
{
1559 1617
    struct zstream *z = get_zstream(obj);
1560
    VALUE v_flush, dst;
1618
    VALUE v_flush;
1561 1619
    int flush;
1562 1620

  
1563 1621
    rb_scan_args(argc, argv, "01", &v_flush);
......
1565 1623
    if (flush != Z_NO_FLUSH) {  /* prevent Z_BUF_ERROR */
1566 1624
	zstream_run(z, (Bytef*)"", 0, flush);
1567 1625
    }
1568
    dst = zstream_detach_buffer(z);
1569

  
1570
    OBJ_INFECT(dst, obj);
1571
    return dst;
1626
    return zstream_detach_buffer(z);
1572 1627
}
1573 1628

  
1574 1629
/*
......
1738 1793
}
1739 1794

  
1740 1795
/*
1741
 * Document-method: Zlib::Inflate.inflate
1796
 * Document-method: Zlib::inflate
1742 1797
 *
1743
 * call-seq: Zlib::Inflate.inflate(string)
1798
 * call-seq:
1799
 *   Zlib.inflate(string)
1800
 *   Zlib::Inflate.inflate(string)
1744 1801
 *
1745 1802
 * Decompresses +string+. Raises a Zlib::NeedDict exception if a preset
1746 1803
 * dictionary is needed for decompression.
......
1816 1873
/*
1817 1874
 * Document-method: Zlib::Inflate#inflate
1818 1875
 *
1819
 * call-seq: inflate(string)
1876
 * call-seq:
1877
 *   inflate(deflate_string)                 -> String
1878
 *   inflate(deflate_string) { |chunk| ... } -> nil
1879
 *
1880
 * Inputs +deflate_string+ into the inflate stream and returns the output from
1881
 * the stream.  Calling this method, both the input and the output buffer of
1882
 * the stream are flushed.  If string is +nil+, this method finishes the
1883
 * stream, just like Zlib::ZStream#finish.
1820 1884
 *
1821
 * Inputs +string+ into the inflate stream and returns the output from the
1822
 * stream.  Calling this method, both the input and the output buffer of the
1823
 * stream are flushed.  If string is +nil+, this method finishes the stream,
1824
 * just like Zlib::ZStream#finish.
1885
 * If a block is given consecutive inflated chunks from the +deflate_string+
1886
 * are yielded to the block and +nil+ is returned.
1825 1887
 *
1826 1888
 * Raises a Zlib::NeedDict exception if a preset dictionary is needed to
1827 1889
 * decompress.  Set the dictionary by Zlib::Inflate#set_dictionary and then
......
1858 1920
	    dst = zstream_detach_buffer(z);
1859 1921
	}
1860 1922
	else {
1923
	    VALUE self = (VALUE)z->stream.opaque;
1861 1924
	    StringValue(src);
1862 1925
	    zstream_append_buffer2(z, src);
1863 1926
	    dst = rb_str_new(0, 0);
1927
	    OBJ_INFECT(dst, self);
1864 1928
	}
1865 1929
    }
1866 1930
    else {
......
1871 1935
	}
1872 1936
    }
1873 1937

  
1874
    OBJ_INFECT(dst, obj);
1875 1938
    return dst;
1876 1939
}
1877 1940

  
......
2095 2158

  
2096 2159
    obj = Data_Make_Struct(klass, struct gzfile, gzfile_mark, gzfile_free, gz);
2097 2160
    zstream_init(&gz->z, funcs);
2161
    gz->z.flags |= ZSTREAM_FLAG_GZFILE;
2098 2162
    gz->io = Qnil;
2099 2163
    gz->level = 0;
2100 2164
    gz->mtime = 0;
test/zlib/test_zlib.rb (working copy)
39 39
      assert_raise(Zlib::StreamError) { Zlib::Deflate.deflate("foo", 10000) }
40 40
    end
41 41

  
42
    def test_deflate_chunked
43
      original = ''
44
      chunks = []
45
      r = Random.new 0
46

  
47
      z = Zlib::Deflate.new
48

  
49
      2.times do
50
        input = r.bytes(16384)
51
        original << input
52
        z.deflate(input) do |chunk|
53
          chunks << chunk
54
        end
55
      end
56

  
57
      assert_equal [2, 16384, 10],
58
                   chunks.map { |chunk| chunk.length }
59

  
60
      final = z.finish
61

  
62
      assert_equal 16388, final.length
63

  
64
      all = chunks.join
65
      all << final
66

  
67
      inflated = Zlib.inflate all
68

  
69
      assert_equal original, inflated
70
    end
71

  
72
    def test_deflate_chunked_break
73
      chunks = []
74
      r = Random.new 0
75

  
76
      z = Zlib::Deflate.new
77

  
78
      input = r.bytes(16384)
79
      z.deflate(input) do |chunk|
80
        chunks << chunk
81
        break
82
      end
83

  
84
      assert_equal [2], chunks.map { |chunk| chunk.length }
85

  
86
      final = z.finish
87

  
88
      assert_equal 16393, final.length
89

  
90
      all = chunks.join
91
      all << final
92

  
93
      original = Zlib.inflate all
94

  
95
      assert_equal input, original
96
    end
97

  
42 98
    def test_addstr
43 99
      z = Zlib::Deflate.new
44 100
      z << "foo"
......
202 258
      assert_equal "foofoofoo", out
203 259
    end
204 260

  
261
    def test_finish_chunked
262
      # zeros = Zlib::Deflate.deflate("0" * 100_000)
263
      zeros = "x\234\355\3011\001\000\000\000\302\240J\353\237\316\032\036@" \
264
              "\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000" \
265
              "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" \
266
              "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" \
267
              "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" \
268
              "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" \
269
              "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" \
270
              "\000\000\000\000\000\000\000\257\006\351\247BH"
271

  
272
      chunks = []
273

  
274
      z = Zlib::Inflate.new
275

  
276
      z.inflate(zeros) do |chunk|
277
        chunks << chunk
278
        break
279
      end
280

  
281
      z.finish do |chunk|
282
        chunks << chunk
283
      end
284

  
285
      assert_equal [16384, 16384, 16384, 16384, 16384, 16384, 1696],
286
                   chunks.map { |chunk| chunk.size }
287

  
288
      assert chunks.all? { |chunk|
289
        chunk =~ /\A0+\z/
290
      }
291
    end
292

  
205 293
    def test_inflate
206 294
      s = Zlib::Deflate.deflate("foo")
207 295
      z = Zlib::Inflate.new
......
212 300
      z << "foo" # ???
213 301
    end
214 302

  
303
    def test_inflate_chunked
304
      # s = Zlib::Deflate.deflate("0" * 100_000)
305
      zeros = "x\234\355\3011\001\000\000\000\302\240J\353\237\316\032\036@" \
306
              "\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000" \
307
              "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" \
308
              "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" \
309
              "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" \
310
              "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" \
311
              "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" \
312
              "\000\000\000\000\000\000\000\257\006\351\247BH"
313

  
314
      chunks = []
315

  
316
      z = Zlib::Inflate.new
317

  
318
      z.inflate(zeros) do |chunk|
319
        chunks << chunk
320
      end
321

  
322
      assert_equal [16384, 16384, 16384, 16384, 16384, 16384, 1696],
323
                   chunks.map { |chunk| chunk.size }
324

  
325
      assert chunks.all? { |chunk|
326
        chunk =~ /\A0+\z/
327
      }
328
    end
329

  
330
    def test_inflate_chunked_break
331
      # zeros = Zlib::Deflate.deflate("0" * 100_000)
332
      zeros = "x\234\355\3011\001\000\000\000\302\240J\353\237\316\032\036@" \
333
              "\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000" \
334
              "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" \
335
              "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" \
336
              "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" \
337
              "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" \
338
              "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" \
339
              "\000\000\000\000\000\000\000\257\006\351\247BH"
340

  
341
      chunks = []
342

  
343
      z = Zlib::Inflate.new
344

  
345
      z.inflate(zeros) do |chunk|
346
        chunks << chunk
347
        break
348
      end
349

  
350
      out = z.inflate nil
351

  
352
      assert_equal 100_000 - chunks.first.length, out.length
353
    end
354

  
215 355
    def test_inflate_dictionary
216 356
      dictionary = "foo"
217 357