2000-05-01 05:42:38 -04:00
|
|
|
/**********************************************************************
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
marshal.c -
|
|
|
|
|
|
|
|
$Author$
|
|
|
|
$Date$
|
|
|
|
created at: Thu Apr 27 16:30:01 JST 1995
|
|
|
|
|
2003-01-16 02:34:03 -05:00
|
|
|
Copyright (C) 1993-2003 Yukihiro Matsumoto
|
2000-05-01 05:42:38 -04:00
|
|
|
|
|
|
|
**********************************************************************/
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
#include "ruby.h"
|
1999-01-19 23:59:39 -05:00
|
|
|
#include "rubyio.h"
|
1998-01-16 07:19:09 -05:00
|
|
|
#include "st.h"
|
2002-05-14 02:22:31 -04:00
|
|
|
#include "util.h"
|
1999-08-13 01:45:20 -04:00
|
|
|
|
2003-01-15 01:29:05 -05:00
|
|
|
#include <math.h>
|
2003-04-20 11:11:20 -04:00
|
|
|
#ifdef HAVE_FLOAT_H
|
|
|
|
#include <float.h>
|
|
|
|
#endif
|
2003-01-15 01:29:05 -05:00
|
|
|
|
2001-08-29 02:28:51 -04:00
|
|
|
#define BITSPERSHORT (2*CHAR_BIT)
|
2000-10-31 03:37:47 -05:00
|
|
|
#define SHORTMASK ((1<<BITSPERSHORT)-1)
|
|
|
|
#define SHORTDN(x) RSHIFT(x,BITSPERSHORT)
|
|
|
|
|
|
|
|
#if SIZEOF_SHORT == SIZEOF_BDIGITS
|
|
|
|
#define SHORTLEN(x) (x)
|
|
|
|
#else
|
|
|
|
static int
|
|
|
|
shortlen(len, ds)
|
|
|
|
long len;
|
|
|
|
BDIGIT *ds;
|
|
|
|
{
|
|
|
|
BDIGIT num;
|
|
|
|
int offset = 0;
|
|
|
|
|
|
|
|
num = ds[len-1];
|
|
|
|
while (num) {
|
|
|
|
num = SHORTDN(num);
|
|
|
|
offset++;
|
|
|
|
}
|
2001-08-29 02:28:51 -04:00
|
|
|
return (len - 1)*sizeof(BDIGIT)/2 + offset;
|
2000-10-31 03:37:47 -05:00
|
|
|
}
|
|
|
|
#define SHORTLEN(x) shortlen((x),d)
|
|
|
|
#endif
|
|
|
|
|
1998-01-16 07:19:09 -05:00
|
|
|
#define MARSHAL_MAJOR 4
|
2002-09-17 05:36:05 -04:00
|
|
|
#define MARSHAL_MINOR 8
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
#define TYPE_NIL '0'
|
|
|
|
#define TYPE_TRUE 'T'
|
|
|
|
#define TYPE_FALSE 'F'
|
|
|
|
#define TYPE_FIXNUM 'i'
|
|
|
|
|
2002-09-05 05:42:56 -04:00
|
|
|
#define TYPE_EXTENDED 'e'
|
1998-01-16 07:19:09 -05:00
|
|
|
#define TYPE_UCLASS 'C'
|
|
|
|
#define TYPE_OBJECT 'o'
|
2002-09-05 05:42:56 -04:00
|
|
|
#define TYPE_DATA 'd'
|
1998-01-16 07:19:09 -05:00
|
|
|
#define TYPE_USERDEF 'u'
|
2003-04-20 11:11:20 -04:00
|
|
|
#define TYPE_USRMARSHAL 'U'
|
1998-01-16 07:19:09 -05:00
|
|
|
#define TYPE_FLOAT 'f'
|
|
|
|
#define TYPE_BIGNUM 'l'
|
|
|
|
#define TYPE_STRING '"'
|
|
|
|
#define TYPE_REGEXP '/'
|
|
|
|
#define TYPE_ARRAY '['
|
|
|
|
#define TYPE_HASH '{'
|
1999-12-01 04:24:48 -05:00
|
|
|
#define TYPE_HASH_DEF '}'
|
1998-01-16 07:19:09 -05:00
|
|
|
#define TYPE_STRUCT 'S'
|
1999-12-01 04:24:48 -05:00
|
|
|
#define TYPE_MODULE_OLD 'M'
|
|
|
|
#define TYPE_CLASS 'c'
|
|
|
|
#define TYPE_MODULE 'm'
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
#define TYPE_SYMBOL ':'
|
|
|
|
#define TYPE_SYMLINK ';'
|
|
|
|
|
2000-01-04 23:41:21 -05:00
|
|
|
#define TYPE_IVAR 'I'
|
1998-01-16 07:19:09 -05:00
|
|
|
#define TYPE_LINK '@'
|
|
|
|
|
2003-07-29 14:26:55 -04:00
|
|
|
static ID s_dump, s_load, s_mdump, s_mload;
|
2002-04-24 00:54:16 -04:00
|
|
|
static ID s_dump_data, s_load_data, s_alloc;
|
2003-03-03 02:20:17 -05:00
|
|
|
static ID s_getc, s_read, s_write, s_binmode;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
struct dump_arg {
|
|
|
|
VALUE obj;
|
2002-10-17 06:20:52 -04:00
|
|
|
VALUE str, dest;
|
2003-08-06 17:50:06 -04:00
|
|
|
st_table *symbols;
|
1998-01-16 07:19:09 -05:00
|
|
|
st_table *data;
|
2000-07-21 04:45:34 -04:00
|
|
|
int taint;
|
1998-01-16 07:19:09 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
struct dump_call_arg {
|
|
|
|
VALUE obj;
|
|
|
|
struct dump_arg *arg;
|
|
|
|
int limit;
|
2003-10-04 13:51:11 -04:00
|
|
|
int weak;
|
1998-01-16 07:19:09 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
static void w_long _((long, struct dump_arg*));
|
|
|
|
|
2002-10-17 06:20:52 -04:00
|
|
|
static void
|
2003-03-03 02:20:17 -05:00
|
|
|
w_nbyte(s, n, arg)
|
2002-10-17 06:20:52 -04:00
|
|
|
char *s;
|
|
|
|
int n;
|
|
|
|
struct dump_arg *arg;
|
|
|
|
{
|
2003-03-03 02:20:17 -05:00
|
|
|
VALUE buf = arg->str;
|
|
|
|
rb_str_buf_cat(buf, s, n);
|
|
|
|
if (arg->dest && RSTRING(buf)->len >= BUFSIZ) {
|
|
|
|
if (arg->taint) OBJ_TAINT(buf);
|
|
|
|
rb_io_write(arg->dest, buf);
|
|
|
|
rb_str_resize(buf, 0);
|
2002-10-17 06:20:52 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-01-16 07:19:09 -05:00
|
|
|
static void
|
|
|
|
w_byte(c, arg)
|
|
|
|
char c;
|
|
|
|
struct dump_arg *arg;
|
|
|
|
{
|
2003-03-03 02:20:17 -05:00
|
|
|
w_nbyte(&c, 1, arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
w_bytes(s, n, arg)
|
|
|
|
char *s;
|
|
|
|
int n;
|
|
|
|
struct dump_arg *arg;
|
|
|
|
{
|
|
|
|
w_long(n, arg);
|
2003-03-03 02:20:17 -05:00
|
|
|
w_nbyte(s, n, arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
w_short(x, arg)
|
|
|
|
int x;
|
|
|
|
struct dump_arg *arg;
|
|
|
|
{
|
2001-08-29 02:28:51 -04:00
|
|
|
w_byte((x >> 0) & 0xff, arg);
|
|
|
|
w_byte((x >> 8) & 0xff, arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
w_long(x, arg)
|
|
|
|
long x;
|
|
|
|
struct dump_arg *arg;
|
|
|
|
{
|
|
|
|
char buf[sizeof(long)+1];
|
|
|
|
int i, len = 0;
|
|
|
|
|
2000-12-05 04:36:54 -05:00
|
|
|
#if SIZEOF_LONG > 4
|
2001-08-29 02:28:51 -04:00
|
|
|
if (!(RSHIFT(x, 31) == 0 || RSHIFT(x, 31) == -1)) {
|
2000-12-05 04:36:54 -05:00
|
|
|
/* big long does not fit in 4 bytes */
|
|
|
|
rb_raise(rb_eTypeError, "long too big to dump");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1998-01-16 07:19:09 -05:00
|
|
|
if (x == 0) {
|
|
|
|
w_byte(0, arg);
|
|
|
|
return;
|
|
|
|
}
|
2000-12-05 04:36:54 -05:00
|
|
|
if (0 < x && x < 123) {
|
|
|
|
w_byte(x + 5, arg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (-124 < x && x < 0) {
|
|
|
|
w_byte((x - 5)&0xff, arg);
|
|
|
|
return;
|
|
|
|
}
|
1998-01-16 07:19:09 -05:00
|
|
|
for (i=1;i<sizeof(long)+1;i++) {
|
|
|
|
buf[i] = x & 0xff;
|
|
|
|
x = RSHIFT(x,8);
|
|
|
|
if (x == 0) {
|
|
|
|
buf[0] = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (x == -1) {
|
|
|
|
buf[0] = -i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
len = i;
|
|
|
|
for (i=0;i<=len;i++) {
|
|
|
|
w_byte(buf[i], arg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-04-20 11:11:20 -04:00
|
|
|
#ifdef DBL_MANT_DIG
|
2003-04-22 06:08:57 -04:00
|
|
|
#define DECIMAL_MANT (53-16) /* from IEEE754 double precision */
|
|
|
|
|
|
|
|
#if DBL_MANT_DIG > 32
|
|
|
|
#define MANT_BITS 32
|
|
|
|
#elif DBL_MANT_DIG > 24
|
|
|
|
#define MANT_BITS 24
|
|
|
|
#elif DBL_MANT_DIG > 16
|
|
|
|
#define MANT_BITS 16
|
|
|
|
#else
|
|
|
|
#define MANT_BITS 8
|
|
|
|
#endif
|
|
|
|
|
2003-04-20 11:11:20 -04:00
|
|
|
static int
|
|
|
|
save_mantissa(d, buf)
|
|
|
|
double d;
|
|
|
|
char *buf;
|
|
|
|
{
|
2003-04-22 06:08:57 -04:00
|
|
|
int e, i = 0;
|
|
|
|
unsigned long m;
|
|
|
|
double n;
|
|
|
|
|
|
|
|
d = modf(ldexp(frexp(fabs(d), &e), DECIMAL_MANT), &d);
|
|
|
|
if (d > 0) {
|
|
|
|
buf[i++] = 0;
|
|
|
|
do {
|
|
|
|
d = modf(ldexp(d, MANT_BITS), &n);
|
|
|
|
m = (unsigned long)n;
|
|
|
|
#if MANT_BITS > 24
|
|
|
|
buf[i++] = m >> 24;
|
|
|
|
#endif
|
|
|
|
#if MANT_BITS > 16
|
|
|
|
buf[i++] = m >> 16;
|
|
|
|
#endif
|
|
|
|
#if MANT_BITS > 8
|
|
|
|
buf[i++] = m >> 8;
|
|
|
|
#endif
|
|
|
|
buf[i++] = m;
|
|
|
|
} while (d > 0);
|
|
|
|
while (!buf[i - 1]) --i;
|
|
|
|
}
|
|
|
|
return i;
|
2003-04-20 11:11:20 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static double
|
|
|
|
load_mantissa(d, buf, len)
|
|
|
|
double d;
|
|
|
|
const char *buf;
|
|
|
|
int len;
|
|
|
|
{
|
2003-04-22 06:08:57 -04:00
|
|
|
if (--len > 0 && !*buf++) { /* binary mantissa mark */
|
|
|
|
int e, s = d < 0, dig = 0;
|
|
|
|
unsigned long m;
|
|
|
|
|
|
|
|
modf(ldexp(frexp(fabs(d), &e), DECIMAL_MANT), &d);
|
|
|
|
do {
|
|
|
|
m = 0;
|
|
|
|
switch (len) {
|
|
|
|
default: m = *buf++ & 0xff;
|
|
|
|
#if MANT_BITS > 24
|
|
|
|
case 3: m = (m << 8) | (*buf++ & 0xff);
|
|
|
|
#endif
|
|
|
|
#if MANT_BITS > 16
|
|
|
|
case 2: m = (m << 8) | (*buf++ & 0xff);
|
|
|
|
#endif
|
|
|
|
#if MANT_BITS > 8
|
|
|
|
case 1: m = (m << 8) | (*buf++ & 0xff);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
dig -= len < MANT_BITS / 8 ? 8 * (unsigned)len : MANT_BITS;
|
|
|
|
d += ldexp((double)m, dig);
|
|
|
|
} while ((len -= MANT_BITS / 8) > 0);
|
|
|
|
d = ldexp(d, e - DECIMAL_MANT);
|
2003-04-20 11:11:20 -04:00
|
|
|
if (s) d = -d;
|
|
|
|
}
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#define load_mantissa(d, buf, len) (d)
|
|
|
|
#define save_mantissa(d, buf) 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef DBL_DIG
|
2003-04-21 09:02:08 -04:00
|
|
|
#define FLOAT_DIG (DBL_DIG+2)
|
2003-04-20 11:11:20 -04:00
|
|
|
#else
|
|
|
|
#define FLOAT_DIG 17
|
|
|
|
#endif
|
|
|
|
|
1998-01-16 07:19:09 -05:00
|
|
|
static void
|
|
|
|
w_float(d, arg)
|
|
|
|
double d;
|
|
|
|
struct dump_arg *arg;
|
|
|
|
{
|
|
|
|
char buf[100];
|
|
|
|
|
2001-11-19 00:03:03 -05:00
|
|
|
if (isinf(d)) {
|
|
|
|
if (d < 0) strcpy(buf, "-inf");
|
|
|
|
else strcpy(buf, "inf");
|
|
|
|
}
|
|
|
|
else if (isnan(d)) {
|
|
|
|
strcpy(buf, "nan");
|
|
|
|
}
|
2001-11-27 05:00:35 -05:00
|
|
|
else if (d == 0.0) {
|
|
|
|
if (1.0/d < 0) strcpy(buf, "-0");
|
|
|
|
else strcpy(buf, "0");
|
|
|
|
}
|
2001-11-19 00:03:03 -05:00
|
|
|
else {
|
2003-04-20 11:11:20 -04:00
|
|
|
int len;
|
|
|
|
|
2001-11-19 00:03:03 -05:00
|
|
|
/* xxx: should not use system's sprintf(3) */
|
2003-04-20 11:11:20 -04:00
|
|
|
sprintf(buf, "%.*g", FLOAT_DIG, d);
|
|
|
|
len = strlen(buf);
|
|
|
|
w_bytes(buf, len + save_mantissa(d, buf + len), arg);
|
|
|
|
return;
|
2001-11-19 00:03:03 -05:00
|
|
|
}
|
1998-01-16 07:19:09 -05:00
|
|
|
w_bytes(buf, strlen(buf), arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
w_symbol(id, arg)
|
|
|
|
ID id;
|
|
|
|
struct dump_arg *arg;
|
|
|
|
{
|
|
|
|
char *sym = rb_id2name(id);
|
2003-08-16 10:58:34 -04:00
|
|
|
st_data_t num;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
2003-08-06 17:50:06 -04:00
|
|
|
if (st_lookup(arg->symbols, id, &num)) {
|
1998-01-16 07:19:09 -05:00
|
|
|
w_byte(TYPE_SYMLINK, arg);
|
2003-08-16 10:58:34 -04:00
|
|
|
w_long((long)num, arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
w_byte(TYPE_SYMBOL, arg);
|
|
|
|
w_bytes(sym, strlen(sym), arg);
|
2003-08-06 17:50:06 -04:00
|
|
|
st_add_direct(arg->symbols, id, arg->symbols->num_entries);
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
w_unique(s, arg)
|
|
|
|
char *s;
|
|
|
|
struct dump_arg *arg;
|
|
|
|
{
|
2001-10-05 02:30:42 -04:00
|
|
|
if (s[0] == '#') {
|
2003-05-22 04:30:58 -04:00
|
|
|
rb_raise(rb_eTypeError, "can't dump anonymous class %s", s);
|
2001-10-05 02:30:42 -04:00
|
|
|
}
|
1998-01-16 07:19:09 -05:00
|
|
|
w_symbol(rb_intern(s), arg);
|
|
|
|
}
|
|
|
|
|
2003-10-04 13:51:11 -04:00
|
|
|
static void w_object _((VALUE,struct dump_arg*,int,int));
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
static int
|
1999-08-13 01:45:20 -04:00
|
|
|
hash_each(key, value, arg)
|
1998-01-16 07:19:09 -05:00
|
|
|
VALUE key, value;
|
|
|
|
struct dump_call_arg *arg;
|
|
|
|
{
|
2003-10-04 13:51:11 -04:00
|
|
|
w_object(key, arg->arg, arg->limit, arg->weak);
|
|
|
|
w_object(value, arg->arg, arg->limit, arg->weak);
|
1998-01-16 07:19:09 -05:00
|
|
|
return ST_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2002-09-05 05:42:56 -04:00
|
|
|
w_extended(klass, arg)
|
|
|
|
VALUE klass;
|
1998-01-16 07:19:09 -05:00
|
|
|
struct dump_arg *arg;
|
|
|
|
{
|
2002-08-27 04:31:08 -04:00
|
|
|
char *path;
|
|
|
|
|
2002-09-05 05:42:56 -04:00
|
|
|
if (FL_TEST(klass, FL_SINGLETON)) {
|
|
|
|
if (RCLASS(klass)->m_tbl->num_entries ||
|
|
|
|
(RCLASS(klass)->iv_tbl && RCLASS(klass)->iv_tbl->num_entries > 1)) {
|
2002-08-27 04:31:08 -04:00
|
|
|
rb_raise(rb_eTypeError, "singleton can't be dumped");
|
|
|
|
}
|
2002-09-05 05:42:56 -04:00
|
|
|
klass = RCLASS(klass)->super;
|
2002-08-27 04:31:08 -04:00
|
|
|
}
|
2002-09-05 05:42:56 -04:00
|
|
|
while (BUILTIN_TYPE(klass) == T_ICLASS) {
|
|
|
|
path = rb_class2name(RBASIC(klass)->klass);
|
|
|
|
w_byte(TYPE_EXTENDED, arg);
|
|
|
|
w_unique(path, arg);
|
|
|
|
klass = RCLASS(klass)->super;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
w_class(type, obj, arg)
|
|
|
|
int type;
|
|
|
|
VALUE obj;
|
|
|
|
struct dump_arg *arg;
|
|
|
|
{
|
|
|
|
char *path;
|
|
|
|
|
|
|
|
VALUE klass = CLASS_OF(obj);
|
|
|
|
w_extended(klass, arg);
|
|
|
|
w_byte(type, arg);
|
2002-08-27 04:31:08 -04:00
|
|
|
path = rb_class2name(klass);
|
|
|
|
w_unique(path, arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
w_uclass(obj, base_klass, arg)
|
|
|
|
VALUE obj, base_klass;
|
|
|
|
struct dump_arg *arg;
|
|
|
|
{
|
|
|
|
VALUE klass = CLASS_OF(obj);
|
|
|
|
|
2002-09-05 05:42:56 -04:00
|
|
|
w_extended(klass, arg);
|
2003-08-06 17:50:06 -04:00
|
|
|
klass = rb_class_real(klass);
|
2002-08-27 04:31:08 -04:00
|
|
|
if (klass != base_klass) {
|
1998-01-16 07:19:09 -05:00
|
|
|
w_byte(TYPE_UCLASS, arg);
|
2003-08-06 17:50:06 -04:00
|
|
|
w_unique(rb_class2name(klass), arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-10-04 13:51:11 -04:00
|
|
|
static int
|
|
|
|
w_obj_each(id, value, arg)
|
|
|
|
ID id;
|
|
|
|
VALUE value;
|
|
|
|
struct dump_call_arg *arg;
|
|
|
|
{
|
|
|
|
w_symbol(id, arg->arg);
|
|
|
|
w_object(value, arg->arg, arg->limit, arg->weak);
|
|
|
|
return ST_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2000-01-04 23:41:21 -05:00
|
|
|
static void
|
|
|
|
w_ivar(tbl, arg)
|
|
|
|
st_table *tbl;
|
|
|
|
struct dump_call_arg *arg;
|
|
|
|
{
|
|
|
|
if (tbl) {
|
|
|
|
w_long(tbl->num_entries, arg->arg);
|
2003-10-04 13:51:11 -04:00
|
|
|
st_foreach(tbl, w_obj_each, (st_data_t)arg);
|
2000-01-04 23:41:21 -05:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
w_long(0, arg->arg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-01-16 07:19:09 -05:00
|
|
|
static void
|
2003-10-04 13:51:11 -04:00
|
|
|
w_object(obj, arg, limit, weak)
|
1998-01-16 07:19:09 -05:00
|
|
|
VALUE obj;
|
|
|
|
struct dump_arg *arg;
|
|
|
|
int limit;
|
2003-10-04 13:51:11 -04:00
|
|
|
int weak;
|
1998-01-16 07:19:09 -05:00
|
|
|
{
|
|
|
|
struct dump_call_arg c_arg;
|
2000-01-17 03:37:53 -05:00
|
|
|
st_table *ivtbl = 0;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
if (limit == 0) {
|
2000-01-31 22:12:21 -05:00
|
|
|
rb_raise(rb_eArgError, "exceed depth limit");
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
2003-08-06 17:50:06 -04:00
|
|
|
|
2003-08-07 23:48:33 -04:00
|
|
|
limit--;
|
|
|
|
c_arg.limit = limit;
|
|
|
|
c_arg.arg = arg;
|
2003-10-05 21:50:41 -04:00
|
|
|
c_arg.weak = weak;
|
2003-08-07 23:48:33 -04:00
|
|
|
|
2003-08-06 17:50:06 -04:00
|
|
|
if (ivtbl = rb_generic_ivar_table(obj)) {
|
|
|
|
w_byte(TYPE_IVAR, arg);
|
|
|
|
}
|
1998-01-16 07:19:09 -05:00
|
|
|
if (obj == Qnil) {
|
|
|
|
w_byte(TYPE_NIL, arg);
|
|
|
|
}
|
1999-01-19 23:59:39 -05:00
|
|
|
else if (obj == Qtrue) {
|
1998-01-16 07:19:09 -05:00
|
|
|
w_byte(TYPE_TRUE, arg);
|
|
|
|
}
|
1999-01-19 23:59:39 -05:00
|
|
|
else if (obj == Qfalse) {
|
1998-01-16 07:19:09 -05:00
|
|
|
w_byte(TYPE_FALSE, arg);
|
|
|
|
}
|
|
|
|
else if (FIXNUM_P(obj)) {
|
|
|
|
#if SIZEOF_LONG <= 4
|
|
|
|
w_byte(TYPE_FIXNUM, arg);
|
|
|
|
w_long(FIX2INT(obj), arg);
|
|
|
|
#else
|
2001-08-23 02:02:15 -04:00
|
|
|
if (RSHIFT((long)obj, 31) == 0 || RSHIFT((long)obj, 31) == -1) {
|
1998-01-16 07:19:09 -05:00
|
|
|
w_byte(TYPE_FIXNUM, arg);
|
1999-01-19 23:59:39 -05:00
|
|
|
w_long(FIX2LONG(obj), arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
else {
|
2003-10-04 13:51:11 -04:00
|
|
|
w_object(rb_int2big(FIX2LONG(obj)), arg, limit, weak);
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
2000-03-07 03:37:59 -05:00
|
|
|
else if (SYMBOL_P(obj)) {
|
2000-04-10 01:48:43 -04:00
|
|
|
w_symbol(SYM2ID(obj), arg);
|
2000-03-07 03:37:59 -05:00
|
|
|
}
|
1998-01-16 07:19:09 -05:00
|
|
|
else {
|
2003-08-16 10:58:34 -04:00
|
|
|
st_data_t num;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
if (st_lookup(arg->data, obj, &num)) {
|
|
|
|
w_byte(TYPE_LINK, arg);
|
2003-08-16 10:58:34 -04:00
|
|
|
w_long((long)num, arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2000-07-21 04:45:34 -04:00
|
|
|
if (OBJ_TAINTED(obj)) arg->taint = Qtrue;
|
|
|
|
|
1999-01-19 23:59:39 -05:00
|
|
|
st_add_direct(arg->data, obj, arg->data->num_entries);
|
2003-07-29 14:26:55 -04:00
|
|
|
if (rb_respond_to(obj, s_mdump)) {
|
|
|
|
VALUE v;
|
|
|
|
|
2003-10-02 04:25:00 -04:00
|
|
|
if (TYPE(obj) == T_OBJECT) {
|
|
|
|
w_byte(TYPE_IVAR, arg);
|
|
|
|
ivtbl = ROBJECT(obj)->iv_tbl;
|
|
|
|
}
|
2003-07-30 03:24:11 -04:00
|
|
|
v = rb_funcall(obj, s_mdump, 0, 0);
|
2003-08-04 01:28:50 -04:00
|
|
|
w_byte(TYPE_USRMARSHAL, arg);
|
|
|
|
w_unique(rb_class2name(CLASS_OF(obj)), arg);
|
2003-10-04 13:51:11 -04:00
|
|
|
w_object(v, arg, limit, Qtrue);
|
|
|
|
c_arg.weak = Qtrue;
|
2003-10-02 04:25:00 -04:00
|
|
|
if (ivtbl) w_ivar(ivtbl, &c_arg);
|
2003-07-29 14:26:55 -04:00
|
|
|
return;
|
|
|
|
}
|
1998-01-16 07:19:09 -05:00
|
|
|
if (rb_respond_to(obj, s_dump)) {
|
|
|
|
VALUE v;
|
|
|
|
|
1999-08-13 01:45:20 -04:00
|
|
|
v = rb_funcall(obj, s_dump, 1, INT2NUM(limit));
|
2003-07-31 04:42:44 -04:00
|
|
|
if (TYPE(v) != T_STRING) {
|
|
|
|
rb_raise(rb_eTypeError, "_dump() must return string");
|
|
|
|
}
|
2003-07-29 14:26:55 -04:00
|
|
|
w_class(TYPE_USERDEF, obj, arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
w_bytes(RSTRING(v)->ptr, RSTRING(v)->len, arg);
|
2003-10-04 13:51:11 -04:00
|
|
|
c_arg.weak = Qtrue;
|
2003-10-02 04:25:00 -04:00
|
|
|
if (ivtbl) w_ivar(ivtbl, &c_arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (BUILTIN_TYPE(obj)) {
|
|
|
|
case T_CLASS:
|
2001-05-11 01:24:59 -04:00
|
|
|
if (FL_TEST(obj, FL_SINGLETON)) {
|
|
|
|
rb_raise(rb_eTypeError, "singleton class can't be dumped");
|
|
|
|
}
|
1999-12-01 04:24:48 -05:00
|
|
|
w_byte(TYPE_CLASS, arg);
|
|
|
|
{
|
|
|
|
VALUE path = rb_class_path(obj);
|
2001-06-05 03:19:39 -04:00
|
|
|
if (RSTRING(path)->ptr[0] == '#') {
|
2003-05-22 04:30:58 -04:00
|
|
|
rb_raise(rb_eTypeError, "can't dump anonymous class %s",
|
2001-06-05 03:19:39 -04:00
|
|
|
RSTRING(path)->ptr);
|
|
|
|
}
|
1999-12-01 04:24:48 -05:00
|
|
|
w_bytes(RSTRING(path)->ptr, RSTRING(path)->len, arg);
|
|
|
|
}
|
2000-01-04 23:41:21 -05:00
|
|
|
break;
|
1999-12-01 04:24:48 -05:00
|
|
|
|
|
|
|
case T_MODULE:
|
1998-01-16 07:19:09 -05:00
|
|
|
w_byte(TYPE_MODULE, arg);
|
|
|
|
{
|
|
|
|
VALUE path = rb_class_path(obj);
|
2001-06-05 03:19:39 -04:00
|
|
|
if (RSTRING(path)->ptr[0] == '#') {
|
2003-05-22 04:30:58 -04:00
|
|
|
rb_raise(rb_eTypeError, "can't dump anonymous module %s",
|
2001-06-05 03:19:39 -04:00
|
|
|
RSTRING(path)->ptr);
|
|
|
|
}
|
1998-01-16 07:19:09 -05:00
|
|
|
w_bytes(RSTRING(path)->ptr, RSTRING(path)->len, arg);
|
|
|
|
}
|
2000-01-04 23:41:21 -05:00
|
|
|
break;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
case T_FLOAT:
|
|
|
|
w_byte(TYPE_FLOAT, arg);
|
|
|
|
w_float(RFLOAT(obj)->value, arg);
|
2000-01-04 23:41:21 -05:00
|
|
|
break;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
case T_BIGNUM:
|
|
|
|
w_byte(TYPE_BIGNUM, arg);
|
|
|
|
{
|
2002-01-23 02:30:43 -05:00
|
|
|
char sign = RBIGNUM(obj)->sign ? '+' : '-';
|
2000-11-20 02:31:55 -05:00
|
|
|
long len = RBIGNUM(obj)->len;
|
2000-10-31 03:37:47 -05:00
|
|
|
BDIGIT *d = RBIGNUM(obj)->digits;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
w_byte(sign, arg);
|
2000-11-20 02:31:55 -05:00
|
|
|
w_long(SHORTLEN(len), arg); /* w_short? */
|
1998-01-16 07:19:09 -05:00
|
|
|
while (len--) {
|
2000-10-31 03:37:47 -05:00
|
|
|
#if SIZEOF_BDIGITS > SIZEOF_SHORT
|
|
|
|
BDIGIT num = *d;
|
|
|
|
int i;
|
|
|
|
|
2001-03-26 03:57:16 -05:00
|
|
|
for (i=0; i<SIZEOF_BDIGITS; i+=SIZEOF_SHORT) {
|
2000-10-31 03:37:47 -05:00
|
|
|
w_short(num & SHORTMASK, arg);
|
|
|
|
num = SHORTDN(num);
|
2001-03-26 03:57:16 -05:00
|
|
|
if (len == 0 && num == 0) break;
|
2000-10-31 03:37:47 -05:00
|
|
|
}
|
|
|
|
#else
|
1998-01-16 07:19:09 -05:00
|
|
|
w_short(*d, arg);
|
2000-10-31 03:37:47 -05:00
|
|
|
#endif
|
1998-01-16 07:19:09 -05:00
|
|
|
d++;
|
|
|
|
}
|
|
|
|
}
|
2000-01-04 23:41:21 -05:00
|
|
|
break;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
case T_STRING:
|
1999-01-19 23:59:39 -05:00
|
|
|
w_uclass(obj, rb_cString, arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
w_byte(TYPE_STRING, arg);
|
|
|
|
w_bytes(RSTRING(obj)->ptr, RSTRING(obj)->len, arg);
|
2000-01-04 23:41:21 -05:00
|
|
|
break;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
case T_REGEXP:
|
1999-01-19 23:59:39 -05:00
|
|
|
w_uclass(obj, rb_cRegexp, arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
w_byte(TYPE_REGEXP, arg);
|
|
|
|
w_bytes(RREGEXP(obj)->str, RREGEXP(obj)->len, arg);
|
1999-01-19 23:59:39 -05:00
|
|
|
w_byte(rb_reg_options(obj), arg);
|
2000-01-04 23:41:21 -05:00
|
|
|
break;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
case T_ARRAY:
|
1999-01-19 23:59:39 -05:00
|
|
|
w_uclass(obj, rb_cArray, arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
w_byte(TYPE_ARRAY, arg);
|
|
|
|
{
|
2000-11-20 02:31:55 -05:00
|
|
|
long len = RARRAY(obj)->len;
|
1998-01-16 07:19:09 -05:00
|
|
|
VALUE *ptr = RARRAY(obj)->ptr;
|
|
|
|
|
|
|
|
w_long(len, arg);
|
|
|
|
while (len--) {
|
2003-10-04 13:51:11 -04:00
|
|
|
w_object(*ptr, arg, limit, weak);
|
1998-01-16 07:19:09 -05:00
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case T_HASH:
|
1999-01-19 23:59:39 -05:00
|
|
|
w_uclass(obj, rb_cHash, arg);
|
2002-08-29 05:08:18 -04:00
|
|
|
if (NIL_P(RHASH(obj)->ifnone)) {
|
|
|
|
w_byte(TYPE_HASH, arg);
|
|
|
|
}
|
|
|
|
else if (FL_TEST(obj, FL_USER2)) {
|
|
|
|
/* FL_USER2 means HASH_PROC_DEFAULT (see hash.c) */
|
2003-05-22 04:30:58 -04:00
|
|
|
rb_raise(rb_eTypeError, "cannot dump hash with default proc");
|
1999-12-01 04:24:48 -05:00
|
|
|
}
|
|
|
|
else {
|
2002-08-29 05:08:18 -04:00
|
|
|
w_byte(TYPE_HASH_DEF, arg);
|
1999-12-01 04:24:48 -05:00
|
|
|
}
|
1998-01-16 07:19:09 -05:00
|
|
|
w_long(RHASH(obj)->tbl->num_entries, arg);
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 10:55:43 -05:00
|
|
|
st_foreach(RHASH(obj)->tbl, hash_each, (st_data_t)&c_arg);
|
1999-12-01 04:24:48 -05:00
|
|
|
if (!NIL_P(RHASH(obj)->ifnone)) {
|
2003-10-04 13:51:11 -04:00
|
|
|
w_object(RHASH(obj)->ifnone, arg, limit, weak);
|
1999-12-01 04:24:48 -05:00
|
|
|
}
|
1998-01-16 07:19:09 -05:00
|
|
|
break;
|
|
|
|
|
|
|
|
case T_STRUCT:
|
2003-04-09 01:08:25 -04:00
|
|
|
w_class(TYPE_STRUCT, obj, arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
{
|
2000-11-20 02:31:55 -05:00
|
|
|
long len = RSTRUCT(obj)->len;
|
1998-01-16 07:19:09 -05:00
|
|
|
VALUE mem;
|
2000-11-20 02:31:55 -05:00
|
|
|
long i;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
w_long(len, arg);
|
2001-08-29 02:28:51 -04:00
|
|
|
mem = rb_struct_iv_get(rb_obj_class(obj), "__member__");
|
1998-01-16 07:19:09 -05:00
|
|
|
if (mem == Qnil) {
|
2000-05-24 00:34:26 -04:00
|
|
|
rb_raise(rb_eTypeError, "uninitialized struct");
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
for (i=0; i<len; i++) {
|
2000-06-14 01:30:29 -04:00
|
|
|
w_symbol(SYM2ID(RARRAY(mem)->ptr[i]), arg);
|
2003-10-04 13:51:11 -04:00
|
|
|
w_object(RSTRUCT(obj)->ptr[i], arg, limit, weak);
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case T_OBJECT:
|
2002-09-05 05:42:56 -04:00
|
|
|
w_class(TYPE_OBJECT, obj, arg);
|
2002-08-27 04:31:08 -04:00
|
|
|
w_ivar(ROBJECT(obj)->iv_tbl, &c_arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
break;
|
|
|
|
|
2003-04-09 01:08:25 -04:00
|
|
|
case T_DATA:
|
|
|
|
{
|
|
|
|
VALUE v;
|
|
|
|
|
|
|
|
w_class(TYPE_DATA, obj, arg);
|
|
|
|
if (!rb_respond_to(obj, s_dump_data)) {
|
|
|
|
rb_raise(rb_eTypeError,
|
2003-10-06 03:23:40 -04:00
|
|
|
"class %s needs to have instance method `_dump_data'",
|
2003-04-09 01:08:25 -04:00
|
|
|
rb_obj_classname(obj));
|
|
|
|
}
|
|
|
|
v = rb_funcall(obj, s_dump_data, 0);
|
2003-10-04 13:51:11 -04:00
|
|
|
w_object(v, arg, limit, weak);
|
2003-04-09 01:08:25 -04:00
|
|
|
}
|
|
|
|
break;
|
2002-04-24 00:54:16 -04:00
|
|
|
|
1998-01-16 07:19:09 -05:00
|
|
|
default:
|
2003-10-04 13:51:11 -04:00
|
|
|
if (weak) {
|
|
|
|
w_byte(TYPE_NIL, arg);
|
|
|
|
return;
|
|
|
|
}
|
1999-01-19 23:59:39 -05:00
|
|
|
rb_raise(rb_eTypeError, "can't dump %s",
|
2003-01-30 23:00:17 -05:00
|
|
|
rb_obj_classname(obj));
|
1998-01-16 07:19:09 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2000-01-04 23:41:21 -05:00
|
|
|
if (ivtbl) {
|
|
|
|
w_ivar(ivtbl, &c_arg);
|
|
|
|
}
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
dump(arg)
|
|
|
|
struct dump_call_arg *arg;
|
|
|
|
{
|
2003-10-04 13:51:11 -04:00
|
|
|
w_object(arg->obj, arg->arg, arg->limit, arg->weak);
|
2002-10-17 06:20:52 -04:00
|
|
|
if (arg->arg->dest) {
|
|
|
|
rb_io_write(arg->arg->dest, arg->arg->str);
|
|
|
|
rb_str_resize(arg->arg->str, 0);
|
|
|
|
}
|
1999-01-19 23:59:39 -05:00
|
|
|
return 0;
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
dump_ensure(arg)
|
|
|
|
struct dump_arg *arg;
|
|
|
|
{
|
2003-08-06 17:50:06 -04:00
|
|
|
st_free_table(arg->symbols);
|
1998-01-16 07:19:09 -05:00
|
|
|
st_free_table(arg->data);
|
2003-03-03 02:20:17 -05:00
|
|
|
if (arg->taint) {
|
2000-07-21 04:45:34 -04:00
|
|
|
OBJ_TAINT(arg->str);
|
|
|
|
}
|
1999-01-19 23:59:39 -05:00
|
|
|
return 0;
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
marshal_dump(argc, argv)
|
|
|
|
int argc;
|
|
|
|
VALUE* argv;
|
|
|
|
{
|
|
|
|
VALUE obj, port, a1, a2;
|
|
|
|
int limit = -1;
|
|
|
|
struct dump_arg arg;
|
|
|
|
struct dump_call_arg c_arg;
|
|
|
|
|
2003-04-08 01:40:29 -04:00
|
|
|
port = Qnil;
|
1998-01-16 07:19:09 -05:00
|
|
|
rb_scan_args(argc, argv, "12", &obj, &a1, &a2);
|
|
|
|
if (argc == 3) {
|
2000-04-12 01:06:23 -04:00
|
|
|
if (!NIL_P(a2)) limit = NUM2INT(a2);
|
2003-04-08 01:40:29 -04:00
|
|
|
if (NIL_P(a1)) goto type_error;
|
1998-01-16 07:19:09 -05:00
|
|
|
port = a1;
|
|
|
|
}
|
|
|
|
else if (argc == 2) {
|
|
|
|
if (FIXNUM_P(a1)) limit = FIX2INT(a1);
|
2003-04-08 01:40:29 -04:00
|
|
|
else if (NIL_P(a1)) goto type_error;
|
1998-01-16 07:19:09 -05:00
|
|
|
else port = a1;
|
|
|
|
}
|
2002-10-17 06:20:52 -04:00
|
|
|
arg.dest = 0;
|
2003-04-08 01:40:29 -04:00
|
|
|
if (!NIL_P(port)) {
|
2003-03-03 02:20:17 -05:00
|
|
|
if (!rb_respond_to(port, s_write)) {
|
2003-04-08 01:40:29 -04:00
|
|
|
type_error:
|
1999-01-19 23:59:39 -05:00
|
|
|
rb_raise(rb_eTypeError, "instance of IO needed");
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
2003-03-03 02:20:17 -05:00
|
|
|
arg.str = rb_str_buf_new(0);
|
|
|
|
arg.dest = port;
|
|
|
|
if (rb_respond_to(port, s_binmode)) {
|
|
|
|
rb_funcall2(port, s_binmode, 0, 0);
|
|
|
|
}
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
else {
|
2001-05-30 05:12:34 -04:00
|
|
|
port = rb_str_buf_new(0);
|
1998-01-16 07:19:09 -05:00
|
|
|
arg.str = port;
|
|
|
|
}
|
|
|
|
|
2003-08-06 17:50:06 -04:00
|
|
|
arg.symbols = st_init_numtable();
|
|
|
|
arg.data = st_init_numtable();
|
|
|
|
arg.taint = Qfalse;
|
|
|
|
c_arg.obj = obj;
|
|
|
|
c_arg.arg = &arg;
|
1998-01-16 07:19:09 -05:00
|
|
|
c_arg.limit = limit;
|
|
|
|
|
|
|
|
w_byte(MARSHAL_MAJOR, &arg);
|
|
|
|
w_byte(MARSHAL_MINOR, &arg);
|
|
|
|
|
1999-01-19 23:59:39 -05:00
|
|
|
rb_ensure(dump, (VALUE)&c_arg, dump_ensure, (VALUE)&arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
return port;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct load_arg {
|
1999-01-19 23:59:39 -05:00
|
|
|
char *ptr, *end;
|
2003-08-06 17:50:06 -04:00
|
|
|
st_table *symbols;
|
1999-10-20 03:10:23 -04:00
|
|
|
VALUE data;
|
1998-01-16 07:19:09 -05:00
|
|
|
VALUE proc;
|
2000-07-21 04:45:34 -04:00
|
|
|
int taint;
|
1998-01-16 07:19:09 -05:00
|
|
|
};
|
|
|
|
|
2000-01-04 23:41:21 -05:00
|
|
|
static VALUE r_object _((struct load_arg *arg));
|
|
|
|
|
1998-01-16 07:19:09 -05:00
|
|
|
static int
|
|
|
|
r_byte(arg)
|
|
|
|
struct load_arg *arg;
|
|
|
|
{
|
1999-08-13 01:45:20 -04:00
|
|
|
int c;
|
|
|
|
|
2003-03-03 02:20:17 -05:00
|
|
|
if (!arg->end) {
|
2002-10-17 06:20:52 -04:00
|
|
|
VALUE src = (VALUE)arg->ptr;
|
|
|
|
VALUE v = rb_funcall2(src, s_getc, 0, 0);
|
|
|
|
if (NIL_P(v)) rb_eof_error();
|
|
|
|
c = (unsigned char)FIX2INT(v);
|
|
|
|
}
|
1999-08-13 01:45:20 -04:00
|
|
|
else if (arg->ptr < arg->end) {
|
|
|
|
c = *(unsigned char*)arg->ptr++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rb_raise(rb_eArgError, "marshal data too short");
|
|
|
|
}
|
|
|
|
return c;
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
long_toobig(size)
|
|
|
|
int size;
|
|
|
|
{
|
1999-01-19 23:59:39 -05:00
|
|
|
rb_raise(rb_eTypeError, "long too big for this architecture (size %d, given %d)",
|
|
|
|
sizeof(long), size);
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
|
2001-08-29 02:28:51 -04:00
|
|
|
#undef SIGN_EXTEND_CHAR
|
|
|
|
#if __STDC__
|
|
|
|
# define SIGN_EXTEND_CHAR(c) ((signed char)(c))
|
|
|
|
#else /* not __STDC__ */
|
|
|
|
/* As in Harbison and Steele. */
|
|
|
|
# define SIGN_EXTEND_CHAR(c) ((((unsigned char)(c)) ^ 128) - 128)
|
|
|
|
#endif
|
|
|
|
|
1998-01-16 07:19:09 -05:00
|
|
|
static long
|
|
|
|
r_long(arg)
|
|
|
|
struct load_arg *arg;
|
|
|
|
{
|
|
|
|
register long x;
|
2001-08-29 02:28:51 -04:00
|
|
|
int c = SIGN_EXTEND_CHAR(r_byte(arg));
|
|
|
|
long i;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
if (c == 0) return 0;
|
|
|
|
if (c > 0) {
|
2000-12-05 04:36:54 -05:00
|
|
|
if (4 < c && c < 128) {
|
|
|
|
return c - 5;
|
|
|
|
}
|
2000-11-20 02:31:55 -05:00
|
|
|
if (c > sizeof(long)) long_toobig(c);
|
1998-01-16 07:19:09 -05:00
|
|
|
x = 0;
|
|
|
|
for (i=0;i<c;i++) {
|
|
|
|
x |= (long)r_byte(arg) << (8*i);
|
|
|
|
}
|
|
|
|
}
|
1999-01-19 23:59:39 -05:00
|
|
|
else {
|
2000-12-05 04:36:54 -05:00
|
|
|
if (-129 < c && c < -4) {
|
|
|
|
return c + 5;
|
|
|
|
}
|
1998-01-16 07:19:09 -05:00
|
|
|
c = -c;
|
2000-11-20 02:31:55 -05:00
|
|
|
if (c > sizeof(long)) long_toobig(c);
|
1998-01-16 07:19:09 -05:00
|
|
|
x = -1;
|
|
|
|
for (i=0;i<c;i++) {
|
2001-08-29 02:28:51 -04:00
|
|
|
x &= ~((long)0xff << (8*i));
|
1998-01-16 07:19:09 -05:00
|
|
|
x |= (long)r_byte(arg) << (8*i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2002-09-04 02:37:39 -04:00
|
|
|
#define r_bytes(arg) r_bytes0(r_long(arg), (arg))
|
1998-01-16 07:19:09 -05:00
|
|
|
|
2002-09-04 02:37:39 -04:00
|
|
|
static VALUE
|
|
|
|
r_bytes0(len, arg)
|
2000-11-20 02:31:55 -05:00
|
|
|
long len;
|
1998-01-16 07:19:09 -05:00
|
|
|
struct load_arg *arg;
|
|
|
|
{
|
2002-09-04 02:37:39 -04:00
|
|
|
VALUE str;
|
|
|
|
|
2003-03-03 02:20:17 -05:00
|
|
|
if (!arg->end) {
|
2002-10-17 06:20:52 -04:00
|
|
|
VALUE src = (VALUE)arg->ptr;
|
|
|
|
VALUE n = LONG2NUM(len);
|
|
|
|
str = rb_funcall2(src, s_read, 1, &n);
|
|
|
|
if (NIL_P(str)) goto too_short;
|
2002-12-19 04:20:20 -05:00
|
|
|
StringValue(str);
|
2002-10-17 06:20:52 -04:00
|
|
|
if (RSTRING(str)->len != len) goto too_short;
|
|
|
|
if (OBJ_TAINTED(str)) arg->taint = Qtrue;
|
|
|
|
}
|
1998-01-16 07:19:09 -05:00
|
|
|
else {
|
|
|
|
if (arg->ptr + len > arg->end) {
|
2003-03-03 02:20:17 -05:00
|
|
|
too_short:
|
|
|
|
rb_raise(rb_eArgError, "marshal data too short");
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
2002-09-04 02:37:39 -04:00
|
|
|
str = rb_str_new(arg->ptr, len);
|
1998-01-16 07:19:09 -05:00
|
|
|
arg->ptr += len;
|
|
|
|
}
|
2002-09-04 02:37:39 -04:00
|
|
|
return str;
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static ID
|
2000-04-10 01:48:43 -04:00
|
|
|
r_symlink(arg)
|
1998-01-16 07:19:09 -05:00
|
|
|
struct load_arg *arg;
|
|
|
|
{
|
|
|
|
ID id;
|
2000-11-20 02:31:55 -05:00
|
|
|
long num = r_long(arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
|
2003-08-06 17:50:06 -04:00
|
|
|
if (st_lookup(arg->symbols, num, &id)) {
|
2000-04-10 01:48:43 -04:00
|
|
|
return id;
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
2003-05-22 04:30:58 -04:00
|
|
|
rb_raise(rb_eArgError, "bad symbol");
|
2000-04-10 01:48:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static ID
|
|
|
|
r_symreal(arg)
|
|
|
|
struct load_arg *arg;
|
|
|
|
{
|
|
|
|
ID id;
|
|
|
|
|
2002-09-04 02:37:39 -04:00
|
|
|
id = rb_intern(RSTRING(r_bytes(arg))->ptr);
|
2003-08-06 17:50:06 -04:00
|
|
|
st_insert(arg->symbols, arg->symbols->num_entries, id);
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
2000-04-10 01:48:43 -04:00
|
|
|
static ID
|
|
|
|
r_symbol(arg)
|
|
|
|
struct load_arg *arg;
|
|
|
|
{
|
|
|
|
if (r_byte(arg) == TYPE_SYMLINK) {
|
|
|
|
return r_symlink(arg);
|
|
|
|
}
|
|
|
|
return r_symreal(arg);
|
|
|
|
}
|
|
|
|
|
1998-01-16 07:19:09 -05:00
|
|
|
static char*
|
|
|
|
r_unique(arg)
|
|
|
|
struct load_arg *arg;
|
|
|
|
{
|
|
|
|
return rb_id2name(r_symbol(arg));
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
r_string(arg)
|
|
|
|
struct load_arg *arg;
|
|
|
|
{
|
2002-09-04 02:37:39 -04:00
|
|
|
return r_bytes(arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2003-10-02 04:25:00 -04:00
|
|
|
r_entry(v, arg)
|
1998-01-16 07:19:09 -05:00
|
|
|
VALUE v;
|
|
|
|
struct load_arg *arg;
|
|
|
|
{
|
1999-10-20 03:10:23 -04:00
|
|
|
rb_hash_aset(arg->data, INT2FIX(RHASH(arg->data)->tbl->num_entries), v);
|
2000-07-21 04:45:34 -04:00
|
|
|
if (arg->taint) OBJ_TAINT(v);
|
1998-01-16 07:19:09 -05:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2000-01-04 23:41:21 -05:00
|
|
|
static void
|
|
|
|
r_ivar(obj, arg)
|
|
|
|
VALUE obj;
|
|
|
|
struct load_arg *arg;
|
|
|
|
{
|
2000-11-20 02:31:55 -05:00
|
|
|
long len;
|
2000-01-04 23:41:21 -05:00
|
|
|
|
|
|
|
len = r_long(arg);
|
|
|
|
if (len > 0) {
|
|
|
|
while (len--) {
|
|
|
|
ID id = r_symbol(arg);
|
|
|
|
VALUE val = r_object(arg);
|
|
|
|
rb_ivar_set(obj, id, val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-09-05 05:42:56 -04:00
|
|
|
static VALUE
|
|
|
|
path2class(path)
|
|
|
|
char *path;
|
|
|
|
{
|
|
|
|
VALUE v = rb_path2class(path);
|
|
|
|
|
|
|
|
if (TYPE(v) != T_CLASS) {
|
2003-05-22 04:30:58 -04:00
|
|
|
rb_raise(rb_eArgError, "%s does not refer class", path);
|
2002-09-05 05:42:56 -04:00
|
|
|
}
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
path2module(path)
|
|
|
|
char *path;
|
|
|
|
{
|
|
|
|
VALUE v = rb_path2class(path);
|
|
|
|
|
|
|
|
if (TYPE(v) != T_MODULE) {
|
2003-05-22 04:30:58 -04:00
|
|
|
rb_raise(rb_eArgError, "%s does not refer module", path);
|
2002-09-05 05:42:56 -04:00
|
|
|
}
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
1998-01-16 07:19:09 -05:00
|
|
|
static VALUE
|
2003-10-02 04:25:00 -04:00
|
|
|
r_object0(arg, proc, ivp)
|
1998-01-16 07:19:09 -05:00
|
|
|
struct load_arg *arg;
|
2002-08-28 11:58:35 -04:00
|
|
|
VALUE proc;
|
2003-10-02 04:25:00 -04:00
|
|
|
int *ivp;
|
1998-01-16 07:19:09 -05:00
|
|
|
{
|
2002-02-26 01:48:59 -05:00
|
|
|
VALUE v = Qnil;
|
1998-01-16 07:19:09 -05:00
|
|
|
int type = r_byte(arg);
|
1999-10-20 03:10:23 -04:00
|
|
|
long id;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case TYPE_LINK:
|
1999-10-20 03:10:23 -04:00
|
|
|
id = r_long(arg);
|
2002-08-21 11:47:54 -04:00
|
|
|
v = rb_hash_aref(arg->data, LONG2FIX(id));
|
1999-10-27 00:20:00 -04:00
|
|
|
if (NIL_P(v)) {
|
|
|
|
rb_raise(rb_eArgError, "dump format error (unlinked)");
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
1999-10-27 00:20:00 -04:00
|
|
|
return v;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
2000-01-04 23:41:21 -05:00
|
|
|
case TYPE_IVAR:
|
2003-10-02 04:25:00 -04:00
|
|
|
{
|
|
|
|
int ivar = Qtrue;
|
|
|
|
|
|
|
|
v = r_object0(arg, 0, &ivar);
|
|
|
|
if (ivar) r_ivar(v, arg);
|
|
|
|
}
|
2002-08-28 11:58:35 -04:00
|
|
|
break;
|
2000-01-04 23:41:21 -05:00
|
|
|
|
2002-09-05 05:42:56 -04:00
|
|
|
case TYPE_EXTENDED:
|
|
|
|
{
|
|
|
|
VALUE m = path2module(r_unique(arg));
|
|
|
|
|
2003-10-02 04:25:00 -04:00
|
|
|
v = r_object0(arg, 0, 0);
|
2002-09-05 05:42:56 -04:00
|
|
|
rb_extend_object(v, m);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
1998-01-16 07:19:09 -05:00
|
|
|
case TYPE_UCLASS:
|
|
|
|
{
|
2002-09-05 05:42:56 -04:00
|
|
|
VALUE c = path2class(r_unique(arg));
|
2001-10-03 03:19:19 -04:00
|
|
|
|
2002-12-12 02:29:14 -05:00
|
|
|
if (FL_TEST(c, FL_SINGLETON)) {
|
|
|
|
rb_raise(rb_eTypeError, "singleton can't be loaded");
|
|
|
|
}
|
2003-10-02 04:25:00 -04:00
|
|
|
v = r_object0(arg, 0, 0);
|
2001-10-22 02:48:18 -04:00
|
|
|
if (rb_special_const_p(v) || TYPE(v) == T_OBJECT || TYPE(v) == T_CLASS) {
|
|
|
|
format_error:
|
1999-01-19 23:59:39 -05:00
|
|
|
rb_raise(rb_eArgError, "dump format error (user class)");
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
2001-10-22 02:48:18 -04:00
|
|
|
if (TYPE(v) == T_MODULE || !RTEST(rb_funcall(c, '<', 1, RBASIC(v)->klass))) {
|
|
|
|
VALUE tmp = rb_obj_alloc(c);
|
|
|
|
|
|
|
|
if (TYPE(v) != TYPE(tmp)) goto format_error;
|
2001-10-03 03:19:19 -04:00
|
|
|
}
|
1999-01-19 23:59:39 -05:00
|
|
|
RBASIC(v)->klass = c;
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
2002-08-28 11:58:35 -04:00
|
|
|
break;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
case TYPE_NIL:
|
2002-02-26 01:48:59 -05:00
|
|
|
v = Qnil;
|
|
|
|
break;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
case TYPE_TRUE:
|
2002-02-26 01:48:59 -05:00
|
|
|
v = Qtrue;
|
|
|
|
break;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
case TYPE_FALSE:
|
2002-02-26 01:48:59 -05:00
|
|
|
v = Qfalse;
|
2002-02-28 01:53:33 -05:00
|
|
|
break;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
case TYPE_FIXNUM:
|
|
|
|
{
|
2000-11-20 02:31:55 -05:00
|
|
|
long i = r_long(arg);
|
2002-08-21 11:47:54 -04:00
|
|
|
v = LONG2FIX(i);
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
2002-02-26 01:48:59 -05:00
|
|
|
break;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
case TYPE_FLOAT:
|
|
|
|
{
|
2001-11-19 00:03:03 -05:00
|
|
|
double d, t = 0.0;
|
2002-09-04 02:37:39 -04:00
|
|
|
VALUE str = r_bytes(arg);
|
2003-04-20 11:11:20 -04:00
|
|
|
const char *ptr = RSTRING(str)->ptr;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
2003-04-20 11:11:20 -04:00
|
|
|
if (strcmp(ptr, "nan") == 0) {
|
2001-11-19 00:03:03 -05:00
|
|
|
d = t / t;
|
|
|
|
}
|
2003-04-20 11:11:20 -04:00
|
|
|
else if (strcmp(ptr, "inf") == 0) {
|
2001-11-19 00:03:03 -05:00
|
|
|
d = 1.0 / t;
|
|
|
|
}
|
2003-04-20 11:11:20 -04:00
|
|
|
else if (strcmp(ptr, "-inf") == 0) {
|
2001-11-19 00:03:03 -05:00
|
|
|
d = -1.0 / t;
|
|
|
|
}
|
|
|
|
else {
|
2003-04-20 11:11:20 -04:00
|
|
|
char *e;
|
|
|
|
d = strtod(ptr, &e);
|
2003-04-22 06:08:57 -04:00
|
|
|
d = load_mantissa(d, e, RSTRING(str)->len - (e - ptr));
|
2001-11-19 00:03:03 -05:00
|
|
|
}
|
|
|
|
v = rb_float_new(d);
|
2003-10-02 04:25:00 -04:00
|
|
|
r_entry(v, arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
2002-02-26 01:48:59 -05:00
|
|
|
break;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
case TYPE_BIGNUM:
|
|
|
|
{
|
2000-11-20 02:31:55 -05:00
|
|
|
long len;
|
2000-10-31 03:37:47 -05:00
|
|
|
BDIGIT *digits;
|
2002-10-17 06:20:52 -04:00
|
|
|
VALUE data;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
NEWOBJ(big, struct RBignum);
|
1999-01-19 23:59:39 -05:00
|
|
|
OBJSETUP(big, rb_cBignum, T_BIGNUM);
|
1998-01-16 07:19:09 -05:00
|
|
|
big->sign = (r_byte(arg) == '+');
|
2000-10-31 03:37:47 -05:00
|
|
|
len = r_long(arg);
|
2002-10-17 06:20:52 -04:00
|
|
|
data = r_bytes0(len * 2, arg);
|
2001-03-22 03:59:26 -05:00
|
|
|
#if SIZEOF_BDIGITS == SIZEOF_SHORT
|
|
|
|
big->len = len;
|
|
|
|
#else
|
2001-08-29 02:28:51 -04:00
|
|
|
big->len = (len + 1) * 2 / sizeof(BDIGIT);
|
2001-03-22 03:59:26 -05:00
|
|
|
#endif
|
2000-10-31 03:37:47 -05:00
|
|
|
big->digits = digits = ALLOC_N(BDIGIT, big->len);
|
2002-10-17 06:20:52 -04:00
|
|
|
MEMCPY(digits, RSTRING(data)->ptr, char, len * 2);
|
2000-10-31 03:37:47 -05:00
|
|
|
#if SIZEOF_BDIGITS > SIZEOF_SHORT
|
2002-10-17 06:20:52 -04:00
|
|
|
MEMZERO((char *)digits + len * 2, char,
|
|
|
|
big->len * sizeof(BDIGIT) - len * 2);
|
|
|
|
#endif
|
|
|
|
len = big->len;
|
|
|
|
while (len > 0) {
|
|
|
|
unsigned char *p = (unsigned char *)digits;
|
2000-10-31 03:37:47 -05:00
|
|
|
BDIGIT num = 0;
|
2002-10-17 06:20:52 -04:00
|
|
|
#if SIZEOF_BDIGITS > SIZEOF_SHORT
|
2000-10-31 03:37:47 -05:00
|
|
|
int shift = 0;
|
|
|
|
int i;
|
|
|
|
|
2002-10-17 06:20:52 -04:00
|
|
|
for (i=0; i<SIZEOF_BDIGITS; i++) {
|
|
|
|
num |= (int)p[i] << shift;
|
|
|
|
shift += 8;
|
2000-10-31 03:37:47 -05:00
|
|
|
}
|
|
|
|
#else
|
2002-10-17 06:20:52 -04:00
|
|
|
num = p[0] | (p[1] << 8);
|
2000-10-31 03:37:47 -05:00
|
|
|
#endif
|
2002-10-17 06:20:52 -04:00
|
|
|
*digits++ = num;
|
|
|
|
len--;
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
2002-02-26 23:52:21 -05:00
|
|
|
v = rb_big_norm((VALUE)big);
|
2003-10-02 04:25:00 -04:00
|
|
|
r_entry(v, arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
2002-02-26 01:48:59 -05:00
|
|
|
break;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
case TYPE_STRING:
|
2003-10-02 04:25:00 -04:00
|
|
|
v = r_entry(r_string(arg), arg);
|
2002-02-26 01:48:59 -05:00
|
|
|
break;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
case TYPE_REGEXP:
|
|
|
|
{
|
2002-09-04 02:37:39 -04:00
|
|
|
volatile VALUE str = r_bytes(arg);
|
|
|
|
int options = r_byte(arg);
|
2003-10-02 04:25:00 -04:00
|
|
|
v = r_entry(rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len, options), arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
2002-02-26 01:48:59 -05:00
|
|
|
break;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
case TYPE_ARRAY:
|
|
|
|
{
|
2000-11-20 02:31:55 -05:00
|
|
|
volatile long len = r_long(arg); /* gcc 2.7.2.3 -O2 bug?? */
|
1999-08-24 04:21:56 -04:00
|
|
|
|
1999-01-19 23:59:39 -05:00
|
|
|
v = rb_ary_new2(len);
|
2003-10-02 04:25:00 -04:00
|
|
|
r_entry(v, arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
while (len--) {
|
1999-01-19 23:59:39 -05:00
|
|
|
rb_ary_push(v, r_object(arg));
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
}
|
2002-02-26 01:48:59 -05:00
|
|
|
break;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
case TYPE_HASH:
|
1999-12-01 04:24:48 -05:00
|
|
|
case TYPE_HASH_DEF:
|
1998-01-16 07:19:09 -05:00
|
|
|
{
|
2000-11-20 02:31:55 -05:00
|
|
|
long len = r_long(arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
|
1999-01-19 23:59:39 -05:00
|
|
|
v = rb_hash_new();
|
2003-10-02 04:25:00 -04:00
|
|
|
r_entry(v, arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
while (len--) {
|
|
|
|
VALUE key = r_object(arg);
|
|
|
|
VALUE value = r_object(arg);
|
1999-01-19 23:59:39 -05:00
|
|
|
rb_hash_aset(v, key, value);
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
1999-12-02 01:58:52 -05:00
|
|
|
if (type == TYPE_HASH_DEF) {
|
1999-12-01 04:24:48 -05:00
|
|
|
RHASH(v)->ifnone = r_object(arg);
|
|
|
|
}
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
2002-02-26 01:48:59 -05:00
|
|
|
break;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
|
|
|
case TYPE_STRUCT:
|
|
|
|
{
|
1999-01-19 23:59:39 -05:00
|
|
|
VALUE klass, mem, values;
|
2000-11-20 02:31:55 -05:00
|
|
|
volatile long i; /* gcc 2.7.2.3 -O2 bug?? */
|
|
|
|
long len;
|
1998-01-16 07:19:09 -05:00
|
|
|
ID slot;
|
|
|
|
|
2002-09-05 05:42:56 -04:00
|
|
|
klass = path2class(r_unique(arg));
|
2001-10-19 10:32:51 -04:00
|
|
|
mem = rb_struct_iv_get(klass, "__member__");
|
1998-01-16 07:19:09 -05:00
|
|
|
if (mem == Qnil) {
|
2000-05-24 00:34:26 -04:00
|
|
|
rb_raise(rb_eTypeError, "uninitialized struct");
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
len = r_long(arg);
|
|
|
|
|
1999-01-19 23:59:39 -05:00
|
|
|
values = rb_ary_new2(len);
|
1998-01-16 07:19:09 -05:00
|
|
|
for (i=0; i<len; i++) {
|
1999-01-19 23:59:39 -05:00
|
|
|
rb_ary_push(values, Qnil);
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
1999-01-19 23:59:39 -05:00
|
|
|
v = rb_struct_alloc(klass, values);
|
2003-10-02 04:25:00 -04:00
|
|
|
r_entry(v, arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
for (i=0; i<len; i++) {
|
|
|
|
slot = r_symbol(arg);
|
|
|
|
|
2000-06-14 01:30:29 -04:00
|
|
|
if (RARRAY(mem)->ptr[i] != ID2SYM(slot)) {
|
1999-01-19 23:59:39 -05:00
|
|
|
rb_raise(rb_eTypeError, "struct %s not compatible (:%s for :%s)",
|
|
|
|
rb_class2name(klass),
|
|
|
|
rb_id2name(slot),
|
2000-06-14 01:30:29 -04:00
|
|
|
rb_id2name(SYM2ID(RARRAY(mem)->ptr[i])));
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
2002-08-21 11:47:54 -04:00
|
|
|
rb_struct_aset(v, LONG2FIX(i), r_object(arg));
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TYPE_USERDEF:
|
|
|
|
{
|
2002-09-05 05:42:56 -04:00
|
|
|
VALUE klass = path2class(r_unique(arg));
|
2003-10-02 04:25:00 -04:00
|
|
|
VALUE data;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
2002-02-26 01:48:59 -05:00
|
|
|
if (!rb_respond_to(klass, s_load)) {
|
|
|
|
rb_raise(rb_eTypeError, "class %s needs to have method `_load'",
|
|
|
|
rb_class2name(klass));
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
2003-10-02 04:25:00 -04:00
|
|
|
data = r_string(arg);
|
|
|
|
if (ivp) {
|
|
|
|
r_ivar(data, arg);
|
|
|
|
*ivp = Qfalse;
|
|
|
|
}
|
|
|
|
v = rb_funcall(klass, s_load, 1, data);
|
|
|
|
r_entry(v, arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2003-07-29 14:26:55 -04:00
|
|
|
case TYPE_USRMARSHAL:
|
|
|
|
{
|
|
|
|
VALUE klass = path2class(r_unique(arg));
|
2003-10-02 04:25:00 -04:00
|
|
|
VALUE data;
|
2003-07-29 14:26:55 -04:00
|
|
|
|
|
|
|
v = rb_obj_alloc(klass);
|
|
|
|
if (!rb_respond_to(v, s_mload)) {
|
|
|
|
rb_raise(rb_eTypeError, "instance of %s needs to have method `marshal_load'",
|
|
|
|
rb_class2name(klass));
|
|
|
|
}
|
2003-10-02 04:25:00 -04:00
|
|
|
r_entry(v, arg);
|
|
|
|
data = r_object(arg);
|
|
|
|
if (ivp) {
|
|
|
|
r_ivar(v, arg);
|
|
|
|
*ivp = Qfalse;
|
|
|
|
}
|
|
|
|
rb_funcall(v, s_mload, 1, data);
|
2003-07-29 14:26:55 -04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
1998-01-16 07:19:09 -05:00
|
|
|
case TYPE_OBJECT:
|
|
|
|
{
|
2002-09-05 05:42:56 -04:00
|
|
|
VALUE klass = path2class(r_unique(arg));
|
1998-01-16 07:19:09 -05:00
|
|
|
|
1999-01-19 23:59:39 -05:00
|
|
|
v = rb_obj_alloc(klass);
|
2001-10-03 03:19:19 -04:00
|
|
|
if (TYPE(v) != T_OBJECT) {
|
|
|
|
rb_raise(rb_eArgError, "dump format error");
|
|
|
|
}
|
2003-10-02 04:25:00 -04:00
|
|
|
r_entry(v, arg);
|
2000-01-04 23:41:21 -05:00
|
|
|
r_ivar(v, arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2002-04-24 00:54:16 -04:00
|
|
|
case TYPE_DATA:
|
|
|
|
{
|
2002-09-05 05:42:56 -04:00
|
|
|
VALUE klass = path2class(r_unique(arg));
|
2002-08-29 05:08:18 -04:00
|
|
|
if (rb_respond_to(klass, s_alloc)) {
|
|
|
|
static int warn = Qtrue;
|
|
|
|
if (warn) {
|
|
|
|
rb_warn("define `allocate' instead of `_alloc'");
|
|
|
|
warn = Qfalse;
|
|
|
|
}
|
|
|
|
v = rb_funcall(klass, s_alloc, 0);
|
2002-04-24 00:54:16 -04:00
|
|
|
}
|
2002-08-29 05:08:18 -04:00
|
|
|
else {
|
|
|
|
v = rb_obj_alloc(klass);
|
|
|
|
}
|
2002-04-24 00:54:16 -04:00
|
|
|
if (TYPE(v) != T_DATA) {
|
|
|
|
rb_raise(rb_eArgError, "dump format error");
|
|
|
|
}
|
2003-10-02 04:25:00 -04:00
|
|
|
r_entry(v, arg);
|
2002-04-24 00:54:16 -04:00
|
|
|
if (!rb_respond_to(v, s_load_data)) {
|
|
|
|
rb_raise(rb_eTypeError,
|
|
|
|
"class %s needs to have instance method `_load_data'",
|
|
|
|
rb_class2name(klass));
|
|
|
|
}
|
2003-10-02 04:25:00 -04:00
|
|
|
rb_funcall(v, s_load_data, 1, r_object0(arg, 0, 0));
|
2002-04-24 00:54:16 -04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
1999-12-01 04:24:48 -05:00
|
|
|
case TYPE_MODULE_OLD:
|
1998-01-16 07:19:09 -05:00
|
|
|
{
|
2003-04-18 14:05:11 -04:00
|
|
|
volatile VALUE str = r_bytes(arg);
|
2002-09-05 05:42:56 -04:00
|
|
|
|
2003-04-18 14:05:11 -04:00
|
|
|
v = rb_path2class(RSTRING(str)->ptr);
|
2003-10-02 04:25:00 -04:00
|
|
|
r_entry(v, arg);
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
2002-02-26 01:48:59 -05:00
|
|
|
break;
|
1998-01-16 07:19:09 -05:00
|
|
|
|
1999-12-01 04:24:48 -05:00
|
|
|
case TYPE_CLASS:
|
|
|
|
{
|
2003-04-18 14:05:11 -04:00
|
|
|
volatile VALUE str = r_bytes(arg);
|
2002-09-05 05:42:56 -04:00
|
|
|
|
|
|
|
v = path2class(RSTRING(str)->ptr);
|
2003-10-02 04:25:00 -04:00
|
|
|
r_entry(v, arg);
|
1999-12-01 04:24:48 -05:00
|
|
|
}
|
2002-02-26 01:48:59 -05:00
|
|
|
break;
|
1999-12-01 04:24:48 -05:00
|
|
|
|
|
|
|
case TYPE_MODULE:
|
|
|
|
{
|
2003-04-18 14:05:11 -04:00
|
|
|
volatile VALUE str = r_bytes(arg);
|
2002-09-05 05:42:56 -04:00
|
|
|
|
|
|
|
v = path2module(RSTRING(str)->ptr);
|
2003-10-02 04:25:00 -04:00
|
|
|
r_entry(v, arg);
|
1999-12-01 04:24:48 -05:00
|
|
|
}
|
2002-02-26 01:48:59 -05:00
|
|
|
break;
|
2000-04-10 01:48:43 -04:00
|
|
|
|
2000-03-07 03:37:59 -05:00
|
|
|
case TYPE_SYMBOL:
|
2002-02-26 01:48:59 -05:00
|
|
|
v = ID2SYM(r_symreal(arg));
|
2002-02-26 23:52:21 -05:00
|
|
|
break;
|
2000-04-10 01:48:43 -04:00
|
|
|
|
|
|
|
case TYPE_SYMLINK:
|
2002-02-26 23:52:21 -05:00
|
|
|
return ID2SYM(r_symlink(arg));
|
1999-12-01 04:24:48 -05:00
|
|
|
|
1998-01-16 07:19:09 -05:00
|
|
|
default:
|
1999-01-19 23:59:39 -05:00
|
|
|
rb_raise(rb_eArgError, "dump format error(0x%x)", type);
|
1998-01-16 07:19:09 -05:00
|
|
|
break;
|
|
|
|
}
|
2002-08-28 11:58:35 -04:00
|
|
|
if (proc) {
|
2003-05-30 12:08:03 -04:00
|
|
|
rb_funcall(proc, rb_intern("call"), 1, v);
|
2002-02-26 01:48:59 -05:00
|
|
|
}
|
|
|
|
return v;
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
|
2002-08-28 11:58:35 -04:00
|
|
|
static VALUE
|
|
|
|
r_object(arg)
|
|
|
|
struct load_arg *arg;
|
|
|
|
{
|
2003-10-02 04:25:00 -04:00
|
|
|
return r_object0(arg, arg->proc, 0);
|
2002-08-28 11:58:35 -04:00
|
|
|
}
|
|
|
|
|
1998-01-16 07:19:09 -05:00
|
|
|
static VALUE
|
|
|
|
load(arg)
|
|
|
|
struct load_arg *arg;
|
|
|
|
{
|
|
|
|
return r_object(arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
load_ensure(arg)
|
|
|
|
struct load_arg *arg;
|
|
|
|
{
|
2003-08-06 17:50:06 -04:00
|
|
|
st_free_table(arg->symbols);
|
1999-01-19 23:59:39 -05:00
|
|
|
return 0;
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
marshal_load(argc, argv)
|
|
|
|
int argc;
|
|
|
|
VALUE *argv;
|
|
|
|
{
|
|
|
|
VALUE port, proc;
|
2000-11-20 02:31:55 -05:00
|
|
|
int major, minor;
|
1998-01-16 07:19:09 -05:00
|
|
|
VALUE v;
|
|
|
|
struct load_arg arg;
|
|
|
|
|
|
|
|
rb_scan_args(argc, argv, "11", &port, &proc);
|
2003-03-03 02:20:17 -05:00
|
|
|
if (rb_respond_to(port, rb_intern("to_str"))) {
|
2001-05-02 00:22:21 -04:00
|
|
|
arg.taint = OBJ_TAINTED(port); /* original taintedness */
|
|
|
|
StringValue(port); /* possible conversion */
|
|
|
|
arg.ptr = RSTRING(port)->ptr;
|
|
|
|
arg.end = arg.ptr + RSTRING(port)->len;
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
2002-10-17 06:20:52 -04:00
|
|
|
else if (rb_respond_to(port, s_getc) && rb_respond_to(port, s_read)) {
|
2003-03-03 02:20:17 -05:00
|
|
|
if (rb_respond_to(port, s_binmode)) {
|
|
|
|
rb_funcall2(port, s_binmode, 0, 0);
|
|
|
|
}
|
2003-07-29 14:26:55 -04:00
|
|
|
arg.taint = Qtrue;
|
2002-10-17 06:20:52 -04:00
|
|
|
arg.ptr = (char *)port;
|
|
|
|
arg.end = 0;
|
|
|
|
}
|
1998-01-16 07:19:09 -05:00
|
|
|
else {
|
1999-01-19 23:59:39 -05:00
|
|
|
rb_raise(rb_eTypeError, "instance of IO needed");
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
major = r_byte(&arg);
|
2000-11-20 02:31:55 -05:00
|
|
|
minor = r_byte(&arg);
|
2000-11-21 09:31:11 -05:00
|
|
|
if (major != MARSHAL_MAJOR || minor > MARSHAL_MINOR) {
|
2000-11-20 02:31:55 -05:00
|
|
|
rb_raise(rb_eTypeError, "incompatible marshal file format (can't be read)\n\
|
|
|
|
\tformat version %d.%d required; %d.%d given",
|
|
|
|
MARSHAL_MAJOR, MARSHAL_MINOR, major, minor);
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
2001-07-31 02:24:45 -04:00
|
|
|
if (RTEST(ruby_verbose) && minor != MARSHAL_MINOR) {
|
2000-11-20 02:31:55 -05:00
|
|
|
rb_warn("incompatible marshal file format (can be read)\n\
|
|
|
|
\tformat version %d.%d required; %d.%d given",
|
|
|
|
MARSHAL_MAJOR, MARSHAL_MINOR, major, minor);
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
|
|
|
|
2003-08-06 17:50:06 -04:00
|
|
|
arg.symbols = st_init_numtable();
|
2003-06-06 05:24:59 -04:00
|
|
|
arg.data = rb_hash_new();
|
2000-11-20 02:31:55 -05:00
|
|
|
if (NIL_P(proc)) arg.proc = 0;
|
|
|
|
else arg.proc = proc;
|
|
|
|
v = rb_ensure(load, (VALUE)&arg, load_ensure, (VALUE)&arg);
|
|
|
|
|
1998-01-16 07:19:09 -05:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
1999-01-19 23:59:39 -05:00
|
|
|
void
|
1998-01-16 07:19:09 -05:00
|
|
|
Init_marshal()
|
|
|
|
{
|
1999-01-19 23:59:39 -05:00
|
|
|
VALUE rb_mMarshal = rb_define_module("Marshal");
|
1998-01-16 07:19:09 -05:00
|
|
|
|
1999-01-19 23:59:39 -05:00
|
|
|
s_dump = rb_intern("_dump");
|
|
|
|
s_load = rb_intern("_load");
|
2003-07-29 14:26:55 -04:00
|
|
|
s_mdump = rb_intern("marshal_dump");
|
|
|
|
s_mload = rb_intern("marshal_load");
|
2002-04-24 00:54:16 -04:00
|
|
|
s_dump_data = rb_intern("_dump_data");
|
|
|
|
s_load_data = rb_intern("_load_data");
|
|
|
|
s_alloc = rb_intern("_alloc");
|
2002-10-17 06:20:52 -04:00
|
|
|
s_getc = rb_intern("getc");
|
|
|
|
s_read = rb_intern("read");
|
|
|
|
s_write = rb_intern("write");
|
2003-03-03 02:20:17 -05:00
|
|
|
s_binmode = rb_intern("binmode");
|
2002-10-17 06:20:52 -04:00
|
|
|
|
1999-01-19 23:59:39 -05:00
|
|
|
rb_define_module_function(rb_mMarshal, "dump", marshal_dump, -1);
|
|
|
|
rb_define_module_function(rb_mMarshal, "load", marshal_load, -1);
|
2000-06-23 03:05:59 -04:00
|
|
|
rb_define_module_function(rb_mMarshal, "restore", marshal_load, -1);
|
2001-07-31 02:24:45 -04:00
|
|
|
|
2001-07-31 04:33:17 -04:00
|
|
|
rb_define_const(rb_mMarshal, "MAJOR_VERSION", INT2FIX(MARSHAL_MAJOR));
|
|
|
|
rb_define_const(rb_mMarshal, "MINOR_VERSION", INT2FIX(MARSHAL_MINOR));
|
1998-01-16 07:19:09 -05:00
|
|
|
}
|
2001-07-03 03:29:00 -04:00
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_marshal_dump(obj, port)
|
|
|
|
VALUE obj, port;
|
|
|
|
{
|
|
|
|
int argc = 1;
|
|
|
|
VALUE argv[2];
|
|
|
|
|
|
|
|
argv[0] = obj;
|
|
|
|
argv[1] = port;
|
|
|
|
if (!NIL_P(port)) argc = 2;
|
|
|
|
return marshal_dump(argc, argv);
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_marshal_load(port)
|
|
|
|
VALUE port;
|
|
|
|
{
|
|
|
|
return marshal_load(1, &port);
|
|
|
|
}
|