Project

General

Profile

Feature #6440 » patch2.diff

Glass_saga (Masaki Matsushita), 06/11/2012 10:25 PM

View differences:

marshal.c
struct load_arg {
VALUE src;
char *buf;
long buflen;
long readable;
long offset;
st_table *symbols;
st_table *data;
......
static ID r_symbol(struct load_arg *arg);
static VALUE path2class(VALUE path);
NORETURN(static void too_short(void));
static void
too_short(void)
{
rb_raise(rb_eArgError, "marshal data too short");
}
static st_index_t
r_prepare(struct load_arg *arg)
{
......
return idx;
}
static unsigned char
r_byte1_buffered(struct load_arg *arg)
{
if (arg->buflen == 0) {
long readable = arg->readable < BUFSIZ ? arg->readable : BUFSIZ;
VALUE str, n = LONG2NUM(readable);
str = rb_funcall2(arg->src, s_read, 1, &n);
check_load_arg(arg, s_read);
if (NIL_P(str)) too_short();
StringValue(str);
arg->infection |= (int)FL_TEST(str, MARSHAL_INFECTION);
memcpy(arg->buf, RSTRING_PTR(str), RSTRING_LEN(str));
arg->offset = 0;
arg->buflen = RSTRING_LEN(str);
}
arg->buflen--;
return arg->buf[arg->offset++];
}
static int
r_byte(struct load_arg *arg)
{
......
c = (unsigned char)RSTRING_PTR(arg->src)[arg->offset++];
}
else {
rb_raise(rb_eArgError, "marshal data too short");
too_short();
}
}
else {
VALUE src = arg->src;
VALUE v = rb_funcall2(src, s_getbyte, 0, 0);
check_load_arg(arg, s_getbyte);
if (NIL_P(v)) rb_eof_error();
c = (unsigned char)NUM2CHR(v);
if (arg->readable >0 || arg->buflen > 0) {
c = r_byte1_buffered(arg);
}
else {
VALUE v = rb_funcall2(arg->src, s_getbyte, 0, 0);
check_load_arg(arg, s_getbyte);
if (NIL_P(v)) rb_eof_error();
c = (unsigned char)NUM2CHR(v);
}
}
return c;
}
......
return x;
}
static VALUE
r_bytes1(long len, struct load_arg *arg)
{
VALUE str, n = LONG2NUM(len);
str = rb_funcall2(arg->src, s_read, 1, &n);
check_load_arg(arg, s_read);
if (NIL_P(str)) too_short();
StringValue(str);
if (RSTRING_LEN(str) != len) too_short();
arg->infection |= (int)FL_TEST(str, MARSHAL_INFECTION);
return str;
}
static VALUE
r_bytes1_buffered(long len, struct load_arg *arg)
{
VALUE str;
if (len <= arg->buflen) {
str = rb_str_new(arg->buf+arg->offset, len);
arg->offset += len;
arg->buflen -= len;
}
else {
long buflen = arg->buflen;
long readable = arg->readable + 1;
long tmp_len, read_len, need_len = len - buflen;
VALUE tmp, n;
read_len = need_len > readable ? need_len : readable;
read_len = read_len < BUFSIZ ? read_len : BUFSIZ;
n = LONG2NUM(read_len);
tmp = rb_funcall2(arg->src, s_read, 1, &n);
check_load_arg(arg, s_read);
if (NIL_P(tmp)) too_short();
StringValue(tmp);
tmp_len = RSTRING_LEN(tmp);
if (tmp_len < need_len) too_short();
arg->infection |= (int)FL_TEST(tmp, MARSHAL_INFECTION);
str = rb_str_new(arg->buf+arg->offset, buflen);
rb_str_cat(str, RSTRING_PTR(tmp), need_len);
if (tmp_len > need_len) {
buflen = tmp_len - need_len;
memcpy(arg->buf, RSTRING_PTR(tmp)+need_len, buflen);
arg->buflen = buflen;
}
else {
arg->buflen = 0;
}
arg->offset = 0;
}
return str;
}
#define r_bytes(arg) r_bytes0(r_long(arg), (arg))
static VALUE
......
arg->offset += len;
}
else {
too_short:
rb_raise(rb_eArgError, "marshal data too short");
too_short();
}
}
else {
VALUE src = arg->src;
VALUE n = LONG2NUM(len);
str = rb_funcall2(src, s_read, 1, &n);
check_load_arg(arg, s_read);
if (NIL_P(str)) goto too_short;
StringValue(str);
if (RSTRING_LEN(str) != len) goto too_short;
arg->infection |= (int)FL_TEST(str, MARSHAL_INFECTION);
if (arg->readable > 0 || arg->buflen > 0) {
str = r_bytes1_buffered(len, arg);
}
else {
str = r_bytes1(len, arg);
}
}
return str;
}
......
v = rb_ary_new2(len);
v = r_entry(v, arg);
arg->readable += len - 1;
while (len--) {
rb_ary_push(v, r_object(arg));
arg->readable--;
}
v = r_leave(v, arg);
arg->readable++;
}
break;
......
v = rb_hash_new();
v = r_entry(v, arg);
arg->readable += (len - 1) * 2;
while (len--) {
VALUE key = r_object(arg);
VALUE value = r_object(arg);
rb_hash_aset(v, key, value);
arg->readable -= 2;
}
arg->readable += 2;
if (type == TYPE_HASH_DEF) {
RHASH_IFNONE(v) = r_object(arg);
}
......
rb_class2name(klass));
}
arg->readable += (len - 1) * 2;
v = r_entry0(v, idx, arg);
values = rb_ary_new2(len);
for (i=0; i<len; i++) {
......
rb_id2name(SYM2ID(RARRAY_PTR(mem)[i])));
}
rb_ary_push(values, r_object(arg));
arg->readable -= 2;
}
rb_struct_initialize(v, values);
v = r_leave(v, arg);
arg->readable += 2;
}
break;
......
static void
clear_load_arg(struct load_arg *arg)
{
if (arg->buf) {
xfree(arg->buf);
arg->buf = 0;
}
arg->buflen = 0;
arg->offset = 0;
arg->readable = 0;
if (!arg->symbols) return;
st_free_table(arg->symbols);
arg->symbols = 0;
......
arg->data = st_init_numtable();
arg->compat_tbl = st_init_numtable();
arg->proc = 0;
arg->readable = 0;
if (NIL_P(v))
arg->buf = xmalloc(BUFSIZ);
else
arg->buf = 0;
major = r_byte(arg);
minor = r_byte(arg);
(2-2/2)