Report abuse

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
static void
zstream_run(z, src, len, flush)
    struct zstream *z;
    Bytef *src;
    uInt len;
    int flush;
{
    uInt n;
    int err;
    volatile VALUE guard;

    if (NIL_P(z->input) && len == 0) {
	z->stream.next_in = "";
	z->stream.avail_in = 0;
    }
    else {
	zstream_append_input(z, src, len);
	z->stream.next_in = RSTRING(z->input)->ptr;
	z->stream.avail_in = RSTRING(z->input)->len;
	/* keep reference to `z->input' so as not to be garbage collected
	   after zstream_reset_input() and prevent `z->stream.next_in'
	   from dangling. */
	guard = z->input;
    }

    if (z->stream.avail_out == 0) {
	zstream_expand_buffer(z);
    }

    for (;;) {
	n = z->stream.avail_out;
	err = z->func->run(&z->stream, flush);
	z->buf_filled += n - z->stream.avail_out;
	rb_thread_schedule();

	if (err == Z_STREAM_END) {
	    z->flags &= ~ZSTREAM_FLAG_IN_STREAM;
	    z->flags |= ZSTREAM_FLAG_FINISHED;
	    break;
	}
	if (err != Z_OK) {
	    if (flush != Z_FINISH && err == Z_BUF_ERROR
		&& z->stream.avail_out > 0) {
		z->flags |= ZSTREAM_FLAG_IN_STREAM;
		break;
	    }
	    zstream_reset_input(z);
	    if (z->stream.avail_in > 0) {
		zstream_append_input(z, z->stream.next_in, z->stream.avail_in);
	    }
	    raise_zlib_error(err, z->stream.msg);
	}
	if (z->stream.avail_out > 0) {
	    z->flags |= ZSTREAM_FLAG_IN_STREAM;
	    break;
	}
	zstream_expand_buffer(z);
    }

    zstream_reset_input(z);
    if (z->stream.avail_in > 0) {
	zstream_append_input(z, z->stream.next_in, z->stream.avail_in);
        guard = Qnil; /* prevent tail call to make guard effective */
    }
}