Feature #14319 ยป 0001-zlib-reduce-garbage-on-Zlib-GzipReader-readpartial.patch
| ext/zlib/zlib.c | ||
|---|---|---|
|
static void gzfile_write_raw(struct gzfile*);
|
||
|
static VALUE gzfile_read_raw_partial(VALUE);
|
||
|
static VALUE gzfile_read_raw_rescue(VALUE);
|
||
|
static VALUE gzfile_read_raw(struct gzfile*);
|
||
|
static int gzfile_read_raw_ensure(struct gzfile*, long);
|
||
|
static VALUE gzfile_read_raw(struct gzfile*, VALUE outbuf);
|
||
|
static int gzfile_read_raw_ensure(struct gzfile*, long, VALUE outbuf);
|
||
|
static char *gzfile_read_raw_until_zero(struct gzfile*, long);
|
||
|
static unsigned int gzfile_get16(const unsigned char*);
|
||
|
static unsigned long gzfile_get32(const unsigned char*);
|
||
|
static void gzfile_set32(unsigned long n, unsigned char*);
|
||
|
static void gzfile_make_header(struct gzfile*);
|
||
|
static void gzfile_make_footer(struct gzfile*);
|
||
|
static void gzfile_read_header(struct gzfile*);
|
||
|
static void gzfile_check_footer(struct gzfile*);
|
||
|
static void gzfile_read_header(struct gzfile*, VALUE outbuf);
|
||
|
static void gzfile_check_footer(struct gzfile*, VALUE outbuf);
|
||
|
static void gzfile_write(struct gzfile*, Bytef*, long);
|
||
|
static long gzfile_read_more(struct gzfile*);
|
||
|
static long gzfile_read_more(struct gzfile*, VALUE outbuf);
|
||
|
static void gzfile_calc_crc(struct gzfile*, VALUE);
|
||
|
static VALUE gzfile_read(struct gzfile*, long);
|
||
|
static VALUE gzfile_read_all(struct gzfile*);
|
||
| ... | ... | |
|
#define GZFILE_READ_SIZE 2048
|
||
|
struct read_raw_arg {
|
||
|
VALUE io;
|
||
|
union {
|
||
|
const VALUE argv[2]; /* for rb_funcallv */
|
||
|
struct {
|
||
|
VALUE len;
|
||
|
VALUE buf;
|
||
|
} in;
|
||
|
} as;
|
||
|
};
|
||
|
static void
|
||
|
gzfile_mark(void *p)
|
||
| ... | ... | |
|
static VALUE
|
||
|
gzfile_read_raw_partial(VALUE arg)
|
||
|
{
|
||
|
struct gzfile *gz = (struct gzfile*)arg;
|
||
|
struct read_raw_arg *ra = (struct read_raw_arg *)arg;
|
||
|
VALUE str;
|
||
|
int argc = NIL_P(ra->as.argv[1]) ? 1 : 2;
|
||
|
str = rb_funcall(gz->io, id_readpartial, 1, INT2FIX(GZFILE_READ_SIZE));
|
||
|
str = rb_funcallv(ra->io, id_readpartial, argc, ra->as.argv);
|
||
|
Check_Type(str, T_STRING);
|
||
|
return str;
|
||
|
}
|
||
| ... | ... | |
|
static VALUE
|
||
|
gzfile_read_raw_rescue(VALUE arg)
|
||
|
{
|
||
|
struct gzfile *gz = (struct gzfile*)arg;
|
||
|
struct read_raw_arg *ra = (struct read_raw_arg *)arg;
|
||
|
VALUE str = Qnil;
|
||
|
if (rb_obj_is_kind_of(rb_errinfo(), rb_eNoMethodError)) {
|
||
|
str = rb_funcall(gz->io, id_read, 1, INT2FIX(GZFILE_READ_SIZE));
|
||
|
int argc = NIL_P(ra->as.argv[1]) ? 1 : 2;
|
||
|
str = rb_funcallv(ra->io, id_read, argc, ra->as.argv);
|
||
|
if (!NIL_P(str)) {
|
||
|
Check_Type(str, T_STRING);
|
||
|
}
|
||
| ... | ... | |
|
}
|
||
|
static VALUE
|
||
|
gzfile_read_raw(struct gzfile *gz)
|
||
|
gzfile_read_raw(struct gzfile *gz, VALUE outbuf)
|
||
|
{
|
||
|
return rb_rescue2(gzfile_read_raw_partial, (VALUE)gz,
|
||
|
gzfile_read_raw_rescue, (VALUE)gz,
|
||
|
struct read_raw_arg ra;
|
||
|
ra.io = gz->io;
|
||
|
ra.as.in.len = INT2FIX(GZFILE_READ_SIZE);
|
||
|
ra.as.in.buf = outbuf;
|
||
|
return rb_rescue2(gzfile_read_raw_partial, (VALUE)&ra,
|
||
|
gzfile_read_raw_rescue, (VALUE)&ra,
|
||
|
rb_eEOFError, rb_eNoMethodError, (VALUE)0);
|
||
|
}
|
||
|
static int
|
||
|
gzfile_read_raw_ensure(struct gzfile *gz, long size)
|
||
|
gzfile_read_raw_ensure(struct gzfile *gz, long size, VALUE outbuf)
|
||
|
{
|
||
|
VALUE str;
|
||
| ... | ... | |
|
rb_raise(cGzError, "unexpected end of string");
|
||
|
}
|
||
|
while (NIL_P(gz->z.input) || RSTRING_LEN(gz->z.input) < size) {
|
||
|
str = gzfile_read_raw(gz);
|
||
|
str = gzfile_read_raw(gz, outbuf);
|
||
|
if (NIL_P(str)) return 0;
|
||
|
zstream_append_input2(&gz->z, str);
|
||
|
}
|
||
| ... | ... | |
|
p = memchr(RSTRING_PTR(gz->z.input) + offset, '\0',
|
||
|
RSTRING_LEN(gz->z.input) - offset);
|
||
|
if (p) break;
|
||
|
str = gzfile_read_raw(gz);
|
||
|
str = gzfile_read_raw(gz, Qnil);
|
||
|
if (NIL_P(str)) {
|
||
|
rb_raise(cGzError, "unexpected end of file");
|
||
|
}
|
||
| ... | ... | |
|
}
|
||
|
static void
|
||
|
gzfile_read_header(struct gzfile *gz)
|
||
|
gzfile_read_header(struct gzfile *gz, VALUE outbuf)
|
||
|
{
|
||
|
const unsigned char *head;
|
||
|
long len;
|
||
|
char flags, *p;
|
||
|
if (!gzfile_read_raw_ensure(gz, 10)) { /* 10 is the size of gzip header */
|
||
|
/* 10 is the size of gzip header */
|
||
|
if (!gzfile_read_raw_ensure(gz, 10, outbuf)) {
|
||
|
gzfile_raise(gz, cGzError, "not in gzip format");
|
||
|
}
|
||
| ... | ... | |
|
zstream_discard_input(&gz->z, 10);
|
||
|
if (flags & GZ_FLAG_EXTRA) {
|
||
|
if (!gzfile_read_raw_ensure(gz, 2)) {
|
||
|
if (!gzfile_read_raw_ensure(gz, 2, outbuf)) {
|
||
|
rb_raise(cGzError, "unexpected end of file");
|
||
|
}
|
||
|
len = gzfile_get16((Bytef*)RSTRING_PTR(gz->z.input));
|
||
|
if (!gzfile_read_raw_ensure(gz, 2 + len)) {
|
||
|
if (!gzfile_read_raw_ensure(gz, 2 + len, outbuf)) {
|
||
|
rb_raise(cGzError, "unexpected end of file");
|
||
|
}
|
||
|
zstream_discard_input(&gz->z, 2 + len);
|
||
|
}
|
||
|
if (flags & GZ_FLAG_ORIG_NAME) {
|
||
|
if (!gzfile_read_raw_ensure(gz, 1)) {
|
||
|
if (!gzfile_read_raw_ensure(gz, 1, outbuf)) {
|
||
|
rb_raise(cGzError, "unexpected end of file");
|
||
|
}
|
||
|
p = gzfile_read_raw_until_zero(gz, 0);
|
||
| ... | ... | |
|
zstream_discard_input(&gz->z, len + 1);
|
||
|
}
|
||
|
if (flags & GZ_FLAG_COMMENT) {
|
||
|
if (!gzfile_read_raw_ensure(gz, 1)) {
|
||
|
if (!gzfile_read_raw_ensure(gz, 1, outbuf)) {
|
||
|
rb_raise(cGzError, "unexpected end of file");
|
||
|
}
|
||
|
p = gzfile_read_raw_until_zero(gz, 0);
|
||
| ... | ... | |
|
}
|
||
|
static void
|
||
|
gzfile_check_footer(struct gzfile *gz)
|
||
|
gzfile_check_footer(struct gzfile *gz, VALUE outbuf)
|
||
|
{
|
||
|
unsigned long crc, length;
|
||
|
gz->z.flags |= GZFILE_FLAG_FOOTER_FINISHED;
|
||
|
if (!gzfile_read_raw_ensure(gz, 8)) { /* 8 is the size of gzip footer */
|
||
|
/* 8 is the size of gzip footer */
|
||
|
if (!gzfile_read_raw_ensure(gz, 8, outbuf)) {
|
||
|
gzfile_raise(gz, cNoFooter, "footer is not found");
|
||
|
}
|
||
| ... | ... | |
|
}
|
||
|
static long
|
||
|
gzfile_read_more(struct gzfile *gz)
|
||
|
gzfile_read_more(struct gzfile *gz, VALUE outbuf)
|
||
|
{
|
||
|
VALUE str;
|
||
|
while (!ZSTREAM_IS_FINISHED(&gz->z)) {
|
||
|
str = gzfile_read_raw(gz);
|
||
|
str = gzfile_read_raw(gz, outbuf);
|
||
|
if (NIL_P(str)) {
|
||
|
if (!ZSTREAM_IS_FINISHED(&gz->z)) {
|
||
|
rb_raise(cGzError, "unexpected end of file");
|
||
| ... | ... | |
|
if (len == 0)
|
||
|
return 0;
|
||
|
while (!ZSTREAM_IS_FINISHED(&gz->z) && ZSTREAM_BUF_FILLED(&gz->z) < len) {
|
||
|
gzfile_read_more(gz);
|
||
|
gzfile_read_more(gz, Qnil);
|
||
|
}
|
||
|
if (GZFILE_IS_FINISHED(gz)) {
|
||
|
if (!(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) {
|
||
|
gzfile_check_footer(gz);
|
||
|
gzfile_check_footer(gz, Qnil);
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
| ... | ... | |
|
}
|
||
|
}
|
||
|
while (!ZSTREAM_IS_FINISHED(&gz->z) && ZSTREAM_BUF_FILLED(&gz->z) == 0) {
|
||
|
gzfile_read_more(gz);
|
||
|
gzfile_read_more(gz, outbuf);
|
||
|
}
|
||
|
if (GZFILE_IS_FINISHED(gz)) {
|
||
|
if (!(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) {
|
||
|
gzfile_check_footer(gz);
|
||
|
gzfile_check_footer(gz, outbuf);
|
||
|
}
|
||
|
if (!NIL_P(outbuf))
|
||
|
rb_str_resize(outbuf, 0);
|
||
| ... | ... | |
|
if (!NIL_P(outbuf)) {
|
||
|
rb_str_resize(outbuf, RSTRING_LEN(dst));
|
||
|
memcpy(RSTRING_PTR(outbuf), RSTRING_PTR(dst), RSTRING_LEN(dst));
|
||
|
RB_GC_GUARD(dst);
|
||
|
rb_str_resize(dst, 0);
|
||
|
rb_gc_force_recycle(dst);
|
||
|
dst = outbuf;
|
||
|
}
|
||
|
OBJ_TAINT(dst); /* for safe */
|
||
| ... | ... | |
|
VALUE dst;
|
||
|
while (!ZSTREAM_IS_FINISHED(&gz->z)) {
|
||
|
gzfile_read_more(gz);
|
||
|
gzfile_read_more(gz, Qnil);
|
||
|
}
|
||
|
if (GZFILE_IS_FINISHED(gz)) {
|
||
|
if (!(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) {
|
||
|
gzfile_check_footer(gz);
|
||
|
gzfile_check_footer(gz, Qnil);
|
||
|
}
|
||
|
return rb_str_new(0, 0);
|
||
|
}
|
||
| ... | ... | |
|
len = rb_enc_mbmaxlen(gz->enc);
|
||
|
while (!ZSTREAM_IS_FINISHED(&gz->z) && ZSTREAM_BUF_FILLED(&gz->z) < len) {
|
||
|
gzfile_read_more(gz);
|
||
|
gzfile_read_more(gz, Qnil);
|
||
|
}
|
||
|
if (GZFILE_IS_FINISHED(gz)) {
|
||
|
if (!(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) {
|
||
|
gzfile_check_footer(gz);
|
||
|
gzfile_check_footer(gz, Qnil);
|
||
|
}
|
||
|
return Qnil;
|
||
|
}
|
||
| ... | ... | |
|
if (GZFILE_IS_FINISHED(gz)
|
||
|
&& !(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) {
|
||
|
gzfile_check_footer(gz);
|
||
|
gzfile_check_footer(gz, Qnil);
|
||
|
}
|
||
|
return Qnil;
|
||
| ... | ... | |
|
if (!ZSTREAM_IS_READY(&gz->z)) return Qnil;
|
||
|
if (!GZFILE_IS_FINISHED(gz)) return Qnil;
|
||
|
if (!(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) {
|
||
|
gzfile_check_footer(gz);
|
||
|
gzfile_check_footer(gz, Qnil);
|
||
|
}
|
||
|
if (NIL_P(gz->z.input)) return Qnil;
|
||
| ... | ... | |
|
}
|
||
|
gz->io = io;
|
||
|
ZSTREAM_READY(&gz->z);
|
||
|
gzfile_read_header(gz);
|
||
|
gzfile_read_header(gz, Qnil);
|
||
|
rb_gzfile_ecopts(gz, opt);
|
||
|
if (rb_respond_to(io, id_path)) {
|
||
| ... | ... | |
|
while (ZSTREAM_BUF_FILLED(&gz->z) == 0) {
|
||
|
if (GZFILE_IS_FINISHED(gz)) return;
|
||
|
gzfile_read_more(gz);
|
||
|
gzfile_read_more(gz, Qnil);
|
||
|
}
|
||
|
n = 0;
|
||
|
p = RSTRING_PTR(gz->z.buf);
|
||
| ... | ... | |
|
gzfile_calc_crc(gz, str);
|
||
|
while (ZSTREAM_BUF_FILLED(&gz->z) == 0) {
|
||
|
if (GZFILE_IS_FINISHED(gz)) return;
|
||
|
gzfile_read_more(gz);
|
||
|
gzfile_read_more(gz, Qnil);
|
||
|
}
|
||
|
n = 0;
|
||
|
p = RSTRING_PTR(gz->z.buf);
|
||
| ... | ... | |
|
if (ZSTREAM_BUF_FILLED(&gz->z) > 0) gz->lineno++;
|
||
|
return gzfile_read(gz, rslen);
|
||
|
}
|
||
|
gzfile_read_more(gz);
|
||
|
gzfile_read_more(gz, Qnil);
|
||
|
}
|
||
|
p = RSTRING_PTR(gz->z.buf);
|
||
| ... | ... | |
|
long filled;
|
||
|
if (n > ZSTREAM_BUF_FILLED(&gz->z)) {
|
||
|
if (ZSTREAM_IS_FINISHED(&gz->z)) break;
|
||
|
gzfile_read_more(gz);
|
||
|
gzfile_read_more(gz, Qnil);
|
||
|
p = RSTRING_PTR(gz->z.buf) + n - rslen;
|
||
|
}
|
||
|
if (!rspara) rscheck(rsptr, rslen, rs);
|
||
| ... | ... | |
|
struct gzfile *gz = (struct gzfile *)arg;
|
||
|
VALUE dst;
|
||
|
gzfile_read_header(gz);
|
||
|
gzfile_read_header(gz, Qnil);
|
||
|
dst = zstream_detach_buffer(&gz->z);
|
||
|
gzfile_calc_crc(gz, dst);
|
||
|
if (!ZSTREAM_IS_FINISHED(&gz->z)) {
|
||
| ... | ... | |
|
if (NIL_P(gz->z.input)) {
|
||
|
rb_raise(cNoFooter, "footer is not found");
|
||
|
}
|
||
|
gzfile_check_footer(gz);
|
||
|
gzfile_check_footer(gz, Qnil);
|
||
|
return dst;
|
||
|
}
|
||
|
-
|
||