00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "ruby/ruby.h"
00013 #include "ruby/io.h"
00014 #include "ruby/st.h"
00015 #include "ruby/util.h"
00016 #include "ruby/encoding.h"
00017 #include "internal.h"
00018
00019 #include <math.h>
00020 #ifdef HAVE_FLOAT_H
00021 #include <float.h>
00022 #endif
00023 #ifdef HAVE_IEEEFP_H
00024 #include <ieeefp.h>
00025 #endif
00026
00027 #define BITSPERSHORT (2*CHAR_BIT)
00028 #define SHORTMASK ((1<<BITSPERSHORT)-1)
00029 #define SHORTDN(x) RSHIFT((x),BITSPERSHORT)
00030
00031 #if SIZEOF_SHORT == SIZEOF_BDIGITS
00032 #define SHORTLEN(x) (x)
00033 #else
00034 static long
00035 shortlen(long len, BDIGIT *ds)
00036 {
00037 BDIGIT num;
00038 int offset = 0;
00039
00040 num = ds[len-1];
00041 while (num) {
00042 num = SHORTDN(num);
00043 offset++;
00044 }
00045 return (len - 1)*SIZEOF_BDIGITS/2 + offset;
00046 }
00047 #define SHORTLEN(x) shortlen((x),d)
00048 #endif
00049
00050 #define MARSHAL_MAJOR 4
00051 #define MARSHAL_MINOR 8
00052
00053 #define TYPE_NIL '0'
00054 #define TYPE_TRUE 'T'
00055 #define TYPE_FALSE 'F'
00056 #define TYPE_FIXNUM 'i'
00057
00058 #define TYPE_EXTENDED 'e'
00059 #define TYPE_UCLASS 'C'
00060 #define TYPE_OBJECT 'o'
00061 #define TYPE_DATA 'd'
00062 #define TYPE_USERDEF 'u'
00063 #define TYPE_USRMARSHAL 'U'
00064 #define TYPE_FLOAT 'f'
00065 #define TYPE_BIGNUM 'l'
00066 #define TYPE_STRING '"'
00067 #define TYPE_REGEXP '/'
00068 #define TYPE_ARRAY '['
00069 #define TYPE_HASH '{'
00070 #define TYPE_HASH_DEF '}'
00071 #define TYPE_STRUCT 'S'
00072 #define TYPE_MODULE_OLD 'M'
00073 #define TYPE_CLASS 'c'
00074 #define TYPE_MODULE 'm'
00075
00076 #define TYPE_SYMBOL ':'
00077 #define TYPE_SYMLINK ';'
00078
00079 #define TYPE_IVAR 'I'
00080 #define TYPE_LINK '@'
00081
00082 static ID s_dump, s_load, s_mdump, s_mload;
00083 static ID s_dump_data, s_load_data, s_alloc, s_call;
00084 static ID s_getbyte, s_read, s_write, s_binmode;
00085
00086 typedef struct {
00087 VALUE newclass;
00088 VALUE oldclass;
00089 VALUE (*dumper)(VALUE);
00090 VALUE (*loader)(VALUE, VALUE);
00091 } marshal_compat_t;
00092
00093 static st_table *compat_allocator_tbl;
00094 static VALUE compat_allocator_tbl_wrapper;
00095
00096 static int
00097 mark_marshal_compat_i(st_data_t key, st_data_t value)
00098 {
00099 marshal_compat_t *p = (marshal_compat_t *)value;
00100 rb_gc_mark(p->newclass);
00101 rb_gc_mark(p->oldclass);
00102 return ST_CONTINUE;
00103 }
00104
00105 static void
00106 mark_marshal_compat_t(void *tbl)
00107 {
00108 if (!tbl) return;
00109 st_foreach(tbl, mark_marshal_compat_i, 0);
00110 }
00111
00112 void
00113 rb_marshal_define_compat(VALUE newclass, VALUE oldclass, VALUE (*dumper)(VALUE), VALUE (*loader)(VALUE, VALUE))
00114 {
00115 marshal_compat_t *compat;
00116 rb_alloc_func_t allocator = rb_get_alloc_func(newclass);
00117
00118 if (!allocator) {
00119 rb_raise(rb_eTypeError, "no allocator");
00120 }
00121
00122 compat = ALLOC(marshal_compat_t);
00123 compat->newclass = Qnil;
00124 compat->oldclass = Qnil;
00125 compat->newclass = newclass;
00126 compat->oldclass = oldclass;
00127 compat->dumper = dumper;
00128 compat->loader = loader;
00129
00130 st_insert(compat_allocator_tbl, (st_data_t)allocator, (st_data_t)compat);
00131 }
00132
00133 #define MARSHAL_INFECTION FL_TAINT
00134 typedef char ruby_check_marshal_viral_flags[MARSHAL_INFECTION == (int)MARSHAL_INFECTION ? 1 : -1];
00135
00136 struct dump_arg {
00137 VALUE str, dest;
00138 st_table *symbols;
00139 st_table *data;
00140 st_table *compat_tbl;
00141 st_table *encodings;
00142 int infection;
00143 };
00144
00145 struct dump_call_arg {
00146 VALUE obj;
00147 struct dump_arg *arg;
00148 int limit;
00149 };
00150
00151 static void
00152 check_dump_arg(struct dump_arg *arg, ID sym)
00153 {
00154 if (!arg->symbols) {
00155 rb_raise(rb_eRuntimeError, "Marshal.dump reentered at %s",
00156 rb_id2name(sym));
00157 }
00158 }
00159
00160 static void clear_dump_arg(struct dump_arg *arg);
00161
00162 static void
00163 mark_dump_arg(void *ptr)
00164 {
00165 struct dump_arg *p = ptr;
00166 if (!p->symbols)
00167 return;
00168 rb_mark_set(p->data);
00169 rb_mark_hash(p->compat_tbl);
00170 rb_gc_mark(p->str);
00171 }
00172
00173 static void
00174 free_dump_arg(void *ptr)
00175 {
00176 clear_dump_arg(ptr);
00177 xfree(ptr);
00178 }
00179
00180 static size_t
00181 memsize_dump_arg(const void *ptr)
00182 {
00183 return ptr ? sizeof(struct dump_arg) : 0;
00184 }
00185
00186 static const rb_data_type_t dump_arg_data = {
00187 "dump_arg",
00188 {mark_dump_arg, free_dump_arg, memsize_dump_arg,},
00189 NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
00190 };
00191
00192 static const char *
00193 must_not_be_anonymous(const char *type, VALUE path)
00194 {
00195 char *n = RSTRING_PTR(path);
00196
00197 if (!rb_enc_asciicompat(rb_enc_get(path))) {
00198
00199 rb_raise(rb_eTypeError, "can't dump non-ascii %s name", type);
00200 }
00201 if (n[0] == '#') {
00202 rb_raise(rb_eTypeError, "can't dump anonymous %s %.*s", type,
00203 (int)RSTRING_LEN(path), n);
00204 }
00205 return n;
00206 }
00207
00208 static VALUE
00209 class2path(VALUE klass)
00210 {
00211 VALUE path = rb_class_path(klass);
00212 const char *n;
00213
00214 n = must_not_be_anonymous((RB_TYPE_P(klass, T_CLASS) ? "class" : "module"), path);
00215 if (rb_path_to_class(path) != rb_class_real(klass)) {
00216 rb_raise(rb_eTypeError, "%s can't be referred to", n);
00217 }
00218 return path;
00219 }
00220
00221 static void w_long(long, struct dump_arg*);
00222 static void w_encoding(VALUE obj, long num, struct dump_call_arg *arg);
00223
00224 static void
00225 w_nbyte(const char *s, long n, struct dump_arg *arg)
00226 {
00227 VALUE buf = arg->str;
00228 rb_str_buf_cat(buf, s, n);
00229 RBASIC(buf)->flags |= arg->infection;
00230 if (arg->dest && RSTRING_LEN(buf) >= BUFSIZ) {
00231 rb_io_write(arg->dest, buf);
00232 rb_str_resize(buf, 0);
00233 }
00234 }
00235
00236 static void
00237 w_byte(char c, struct dump_arg *arg)
00238 {
00239 w_nbyte(&c, 1, arg);
00240 }
00241
00242 static void
00243 w_bytes(const char *s, long n, struct dump_arg *arg)
00244 {
00245 w_long(n, arg);
00246 w_nbyte(s, n, arg);
00247 }
00248
00249 #define w_cstr(s, arg) w_bytes((s), strlen(s), (arg))
00250
00251 static void
00252 w_short(int x, struct dump_arg *arg)
00253 {
00254 w_byte((char)((x >> 0) & 0xff), arg);
00255 w_byte((char)((x >> 8) & 0xff), arg);
00256 }
00257
00258 static void
00259 w_long(long x, struct dump_arg *arg)
00260 {
00261 char buf[sizeof(long)+1];
00262 int i, len = 0;
00263
00264 #if SIZEOF_LONG > 4
00265 if (!(RSHIFT(x, 31) == 0 || RSHIFT(x, 31) == -1)) {
00266
00267 rb_raise(rb_eTypeError, "long too big to dump");
00268 }
00269 #endif
00270
00271 if (x == 0) {
00272 w_byte(0, arg);
00273 return;
00274 }
00275 if (0 < x && x < 123) {
00276 w_byte((char)(x + 5), arg);
00277 return;
00278 }
00279 if (-124 < x && x < 0) {
00280 w_byte((char)((x - 5)&0xff), arg);
00281 return;
00282 }
00283 for (i=1;i<(int)sizeof(long)+1;i++) {
00284 buf[i] = (char)(x & 0xff);
00285 x = RSHIFT(x,8);
00286 if (x == 0) {
00287 buf[0] = i;
00288 break;
00289 }
00290 if (x == -1) {
00291 buf[0] = -i;
00292 break;
00293 }
00294 }
00295 len = i;
00296 for (i=0;i<=len;i++) {
00297 w_byte(buf[i], arg);
00298 }
00299 }
00300
00301 #ifdef DBL_MANT_DIG
00302 #define DECIMAL_MANT (53-16)
00303
00304 #if DBL_MANT_DIG > 32
00305 #define MANT_BITS 32
00306 #elif DBL_MANT_DIG > 24
00307 #define MANT_BITS 24
00308 #elif DBL_MANT_DIG > 16
00309 #define MANT_BITS 16
00310 #else
00311 #define MANT_BITS 8
00312 #endif
00313
00314 static double
00315 load_mantissa(double d, const char *buf, long len)
00316 {
00317 if (!len) return d;
00318 if (--len > 0 && !*buf++) {
00319 int e, s = d < 0, dig = 0;
00320 unsigned long m;
00321
00322 modf(ldexp(frexp(fabs(d), &e), DECIMAL_MANT), &d);
00323 do {
00324 m = 0;
00325 switch (len) {
00326 default: m = *buf++ & 0xff;
00327 #if MANT_BITS > 24
00328 case 3: m = (m << 8) | (*buf++ & 0xff);
00329 #endif
00330 #if MANT_BITS > 16
00331 case 2: m = (m << 8) | (*buf++ & 0xff);
00332 #endif
00333 #if MANT_BITS > 8
00334 case 1: m = (m << 8) | (*buf++ & 0xff);
00335 #endif
00336 }
00337 dig -= len < MANT_BITS / 8 ? 8 * (unsigned)len : MANT_BITS;
00338 d += ldexp((double)m, dig);
00339 } while ((len -= MANT_BITS / 8) > 0);
00340 d = ldexp(d, e - DECIMAL_MANT);
00341 if (s) d = -d;
00342 }
00343 return d;
00344 }
00345 #else
00346 #define load_mantissa(d, buf, len) (d)
00347 #endif
00348
00349 #ifdef DBL_DIG
00350 #define FLOAT_DIG (DBL_DIG+2)
00351 #else
00352 #define FLOAT_DIG 17
00353 #endif
00354
00355 static void
00356 w_float(double d, struct dump_arg *arg)
00357 {
00358 char *ruby_dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve);
00359 char buf[FLOAT_DIG + (DECIMAL_MANT + 7) / 8 + 10];
00360
00361 if (isinf(d)) {
00362 if (d < 0) w_cstr("-inf", arg);
00363 else w_cstr("inf", arg);
00364 }
00365 else if (isnan(d)) {
00366 w_cstr("nan", arg);
00367 }
00368 else if (d == 0.0) {
00369 if (1.0/d < 0) w_cstr("-0", arg);
00370 else w_cstr("0", arg);
00371 }
00372 else {
00373 int decpt, sign, digs, len = 0;
00374 char *e, *p = ruby_dtoa(d, 0, 0, &decpt, &sign, &e);
00375 if (sign) buf[len++] = '-';
00376 digs = (int)(e - p);
00377 if (decpt < -3 || decpt > digs) {
00378 buf[len++] = p[0];
00379 if (--digs > 0) buf[len++] = '.';
00380 memcpy(buf + len, p + 1, digs);
00381 len += digs;
00382 len += snprintf(buf + len, sizeof(buf) - len, "e%d", decpt - 1);
00383 }
00384 else if (decpt > 0) {
00385 memcpy(buf + len, p, decpt);
00386 len += decpt;
00387 if ((digs -= decpt) > 0) {
00388 buf[len++] = '.';
00389 memcpy(buf + len, p + decpt, digs);
00390 len += digs;
00391 }
00392 }
00393 else {
00394 buf[len++] = '0';
00395 buf[len++] = '.';
00396 if (decpt) {
00397 memset(buf + len, '0', -decpt);
00398 len -= decpt;
00399 }
00400 memcpy(buf + len, p, digs);
00401 len += digs;
00402 }
00403 xfree(p);
00404 w_bytes(buf, len, arg);
00405 }
00406 }
00407
00408 static void
00409 w_symbol(ID id, struct dump_arg *arg)
00410 {
00411 VALUE sym;
00412 st_data_t num;
00413 int encidx = -1;
00414
00415 if (st_lookup(arg->symbols, id, &num)) {
00416 w_byte(TYPE_SYMLINK, arg);
00417 w_long((long)num, arg);
00418 }
00419 else {
00420 sym = rb_id2str(id);
00421 if (!sym) {
00422 rb_raise(rb_eTypeError, "can't dump anonymous ID %"PRIdVALUE, id);
00423 }
00424 encidx = rb_enc_get_index(sym);
00425 if (encidx == rb_usascii_encindex() ||
00426 rb_enc_str_coderange(sym) == ENC_CODERANGE_7BIT) {
00427 encidx = -1;
00428 }
00429 else {
00430 w_byte(TYPE_IVAR, arg);
00431 }
00432 w_byte(TYPE_SYMBOL, arg);
00433 w_bytes(RSTRING_PTR(sym), RSTRING_LEN(sym), arg);
00434 st_add_direct(arg->symbols, id, arg->symbols->num_entries);
00435 if (encidx != -1) {
00436 struct dump_call_arg c_arg;
00437 c_arg.limit = 1;
00438 c_arg.arg = arg;
00439 w_encoding(sym, 0, &c_arg);
00440 }
00441 }
00442 }
00443
00444 static void
00445 w_unique(VALUE s, struct dump_arg *arg)
00446 {
00447 must_not_be_anonymous("class", s);
00448 w_symbol(rb_intern_str(s), arg);
00449 }
00450
00451 static void w_object(VALUE,struct dump_arg*,int);
00452
00453 static int
00454 hash_each(VALUE key, VALUE value, struct dump_call_arg *arg)
00455 {
00456 w_object(key, arg->arg, arg->limit);
00457 w_object(value, arg->arg, arg->limit);
00458 return ST_CONTINUE;
00459 }
00460
00461 #define SINGLETON_DUMP_UNABLE_P(klass) \
00462 (RCLASS_M_TBL(klass)->num_entries || \
00463 (RCLASS_IV_TBL(klass) && RCLASS_IV_TBL(klass)->num_entries > 1))
00464
00465 static void
00466 w_extended(VALUE klass, struct dump_arg *arg, int check)
00467 {
00468 if (check && FL_TEST(klass, FL_SINGLETON)) {
00469 VALUE origin = RCLASS_ORIGIN(klass);
00470 if (SINGLETON_DUMP_UNABLE_P(klass) ||
00471 (origin != klass && SINGLETON_DUMP_UNABLE_P(origin))) {
00472 rb_raise(rb_eTypeError, "singleton can't be dumped");
00473 }
00474 klass = RCLASS_SUPER(klass);
00475 }
00476 while (BUILTIN_TYPE(klass) == T_ICLASS) {
00477 VALUE path = rb_class_name(RBASIC(klass)->klass);
00478 w_byte(TYPE_EXTENDED, arg);
00479 w_unique(path, arg);
00480 klass = RCLASS_SUPER(klass);
00481 }
00482 }
00483
00484 static void
00485 w_class(char type, VALUE obj, struct dump_arg *arg, int check)
00486 {
00487 VALUE path;
00488 st_data_t real_obj;
00489 VALUE klass;
00490
00491 if (st_lookup(arg->compat_tbl, (st_data_t)obj, &real_obj)) {
00492 obj = (VALUE)real_obj;
00493 }
00494 klass = CLASS_OF(obj);
00495 w_extended(klass, arg, check);
00496 w_byte(type, arg);
00497 path = class2path(rb_class_real(klass));
00498 w_unique(path, arg);
00499 }
00500
00501 static void
00502 w_uclass(VALUE obj, VALUE super, struct dump_arg *arg)
00503 {
00504 VALUE klass = CLASS_OF(obj);
00505
00506 w_extended(klass, arg, TRUE);
00507 klass = rb_class_real(klass);
00508 if (klass != super) {
00509 w_byte(TYPE_UCLASS, arg);
00510 w_unique(class2path(klass), arg);
00511 }
00512 }
00513
00514 static int
00515 w_obj_each(st_data_t key, st_data_t val, st_data_t a)
00516 {
00517 ID id = (ID)key;
00518 VALUE value = (VALUE)val;
00519 struct dump_call_arg *arg = (struct dump_call_arg *)a;
00520
00521 if (id == rb_id_encoding()) return ST_CONTINUE;
00522 if (id == rb_intern("E")) return ST_CONTINUE;
00523 w_symbol(id, arg->arg);
00524 w_object(value, arg->arg, arg->limit);
00525 return ST_CONTINUE;
00526 }
00527
00528 static void
00529 w_encoding(VALUE obj, long num, struct dump_call_arg *arg)
00530 {
00531 int encidx = rb_enc_get_index(obj);
00532 rb_encoding *enc = 0;
00533 st_data_t name;
00534
00535 if (encidx <= 0 || !(enc = rb_enc_from_index(encidx))) {
00536 w_long(num, arg->arg);
00537 return;
00538 }
00539 w_long(num + 1, arg->arg);
00540
00541
00542 if (encidx == rb_usascii_encindex()) {
00543 w_symbol(rb_intern("E"), arg->arg);
00544 w_object(Qfalse, arg->arg, arg->limit + 1);
00545 return;
00546 }
00547 else if (encidx == rb_utf8_encindex()) {
00548 w_symbol(rb_intern("E"), arg->arg);
00549 w_object(Qtrue, arg->arg, arg->limit + 1);
00550 return;
00551 }
00552
00553 w_symbol(rb_id_encoding(), arg->arg);
00554 do {
00555 if (!arg->arg->encodings)
00556 arg->arg->encodings = st_init_strcasetable();
00557 else if (st_lookup(arg->arg->encodings, (st_data_t)rb_enc_name(enc), &name))
00558 break;
00559 name = (st_data_t)rb_str_new2(rb_enc_name(enc));
00560 st_insert(arg->arg->encodings, (st_data_t)rb_enc_name(enc), name);
00561 } while (0);
00562 w_object(name, arg->arg, arg->limit + 1);
00563 }
00564
00565 static void
00566 w_ivar(VALUE obj, st_table *tbl, struct dump_call_arg *arg)
00567 {
00568 long num = tbl ? tbl->num_entries : 0;
00569
00570 w_encoding(obj, num, arg);
00571 if (tbl) {
00572 st_foreach_safe(tbl, w_obj_each, (st_data_t)arg);
00573 }
00574 }
00575
00576 static void
00577 w_objivar(VALUE obj, struct dump_call_arg *arg)
00578 {
00579 VALUE *ptr;
00580 long i, len, num;
00581
00582 len = ROBJECT_NUMIV(obj);
00583 ptr = ROBJECT_IVPTR(obj);
00584 num = 0;
00585 for (i = 0; i < len; i++)
00586 if (ptr[i] != Qundef)
00587 num += 1;
00588
00589 w_encoding(obj, num, arg);
00590 if (num != 0) {
00591 rb_ivar_foreach(obj, w_obj_each, (st_data_t)arg);
00592 }
00593 }
00594
00595 static void
00596 w_object(VALUE obj, struct dump_arg *arg, int limit)
00597 {
00598 struct dump_call_arg c_arg;
00599 st_table *ivtbl = 0;
00600 st_data_t num;
00601 int hasiv = 0;
00602 #define has_ivars(obj, ivtbl) ((((ivtbl) = rb_generic_ivar_table(obj)) != 0) || \
00603 (!SPECIAL_CONST_P(obj) && !ENCODING_IS_ASCII8BIT(obj)))
00604
00605 if (limit == 0) {
00606 rb_raise(rb_eArgError, "exceed depth limit");
00607 }
00608
00609 limit--;
00610 c_arg.limit = limit;
00611 c_arg.arg = arg;
00612
00613 if (st_lookup(arg->data, obj, &num)) {
00614 w_byte(TYPE_LINK, arg);
00615 w_long((long)num, arg);
00616 return;
00617 }
00618
00619 if (obj == Qnil) {
00620 w_byte(TYPE_NIL, arg);
00621 }
00622 else if (obj == Qtrue) {
00623 w_byte(TYPE_TRUE, arg);
00624 }
00625 else if (obj == Qfalse) {
00626 w_byte(TYPE_FALSE, arg);
00627 }
00628 else if (FIXNUM_P(obj)) {
00629 #if SIZEOF_LONG <= 4
00630 w_byte(TYPE_FIXNUM, arg);
00631 w_long(FIX2INT(obj), arg);
00632 #else
00633 if (RSHIFT((long)obj, 31) == 0 || RSHIFT((long)obj, 31) == -1) {
00634 w_byte(TYPE_FIXNUM, arg);
00635 w_long(FIX2LONG(obj), arg);
00636 }
00637 else {
00638 w_object(rb_int2big(FIX2LONG(obj)), arg, limit);
00639 }
00640 #endif
00641 }
00642 else if (SYMBOL_P(obj)) {
00643 w_symbol(SYM2ID(obj), arg);
00644 }
00645 else if (FLONUM_P(obj)) {
00646 st_add_direct(arg->data, obj, arg->data->num_entries);
00647 w_byte(TYPE_FLOAT, arg);
00648 w_float(RFLOAT_VALUE(obj), arg);
00649 }
00650 else {
00651 VALUE v;
00652
00653 if (!RBASIC_CLASS(obj)) {
00654 rb_raise(rb_eTypeError, "can't dump internal %s",
00655 rb_builtin_type_name(BUILTIN_TYPE(obj)));
00656 }
00657
00658 arg->infection |= (int)FL_TEST(obj, MARSHAL_INFECTION);
00659
00660 if (rb_obj_respond_to(obj, s_mdump, TRUE)) {
00661 st_add_direct(arg->data, obj, arg->data->num_entries);
00662
00663 v = rb_funcall2(obj, s_mdump, 0, 0);
00664 check_dump_arg(arg, s_mdump);
00665 w_class(TYPE_USRMARSHAL, obj, arg, FALSE);
00666 w_object(v, arg, limit);
00667 return;
00668 }
00669 if (rb_obj_respond_to(obj, s_dump, TRUE)) {
00670 st_table *ivtbl2 = 0;
00671 int hasiv2;
00672
00673 v = INT2NUM(limit);
00674 v = rb_funcall2(obj, s_dump, 1, &v);
00675 check_dump_arg(arg, s_dump);
00676 if (!RB_TYPE_P(v, T_STRING)) {
00677 rb_raise(rb_eTypeError, "_dump() must return string");
00678 }
00679 hasiv = has_ivars(obj, ivtbl);
00680 if (hasiv) w_byte(TYPE_IVAR, arg);
00681 if ((hasiv2 = has_ivars(v, ivtbl2)) != 0 && !hasiv) {
00682 w_byte(TYPE_IVAR, arg);
00683 }
00684 w_class(TYPE_USERDEF, obj, arg, FALSE);
00685 w_bytes(RSTRING_PTR(v), RSTRING_LEN(v), arg);
00686 if (hasiv2) {
00687 w_ivar(v, ivtbl2, &c_arg);
00688 }
00689 else if (hasiv) {
00690 w_ivar(obj, ivtbl, &c_arg);
00691 }
00692 st_add_direct(arg->data, obj, arg->data->num_entries);
00693 return;
00694 }
00695
00696 st_add_direct(arg->data, obj, arg->data->num_entries);
00697
00698 hasiv = has_ivars(obj, ivtbl);
00699 {
00700 st_data_t compat_data;
00701 rb_alloc_func_t allocator = rb_get_alloc_func(RBASIC(obj)->klass);
00702 if (st_lookup(compat_allocator_tbl,
00703 (st_data_t)allocator,
00704 &compat_data)) {
00705 marshal_compat_t *compat = (marshal_compat_t*)compat_data;
00706 VALUE real_obj = obj;
00707 obj = compat->dumper(real_obj);
00708 st_insert(arg->compat_tbl, (st_data_t)obj, (st_data_t)real_obj);
00709 if (obj != real_obj && !ivtbl) hasiv = 0;
00710 }
00711 }
00712 if (hasiv) w_byte(TYPE_IVAR, arg);
00713
00714 switch (BUILTIN_TYPE(obj)) {
00715 case T_CLASS:
00716 if (FL_TEST(obj, FL_SINGLETON)) {
00717 rb_raise(rb_eTypeError, "singleton class can't be dumped");
00718 }
00719 w_byte(TYPE_CLASS, arg);
00720 {
00721 VALUE path = class2path(obj);
00722 w_bytes(RSTRING_PTR(path), RSTRING_LEN(path), arg);
00723 RB_GC_GUARD(path);
00724 }
00725 break;
00726
00727 case T_MODULE:
00728 w_byte(TYPE_MODULE, arg);
00729 {
00730 VALUE path = class2path(obj);
00731 w_bytes(RSTRING_PTR(path), RSTRING_LEN(path), arg);
00732 RB_GC_GUARD(path);
00733 }
00734 break;
00735
00736 case T_FLOAT:
00737 w_byte(TYPE_FLOAT, arg);
00738 w_float(RFLOAT_VALUE(obj), arg);
00739 break;
00740
00741 case T_BIGNUM:
00742 w_byte(TYPE_BIGNUM, arg);
00743 {
00744 char sign = RBIGNUM_SIGN(obj) ? '+' : '-';
00745 long len = RBIGNUM_LEN(obj);
00746 BDIGIT *d = RBIGNUM_DIGITS(obj);
00747
00748 w_byte(sign, arg);
00749 w_long(SHORTLEN(len), arg);
00750 while (len--) {
00751 #if SIZEOF_BDIGITS > SIZEOF_SHORT
00752 BDIGIT num = *d;
00753 int i;
00754
00755 for (i=0; i<SIZEOF_BDIGITS; i+=SIZEOF_SHORT) {
00756 w_short(num & SHORTMASK, arg);
00757 num = SHORTDN(num);
00758 if (len == 0 && num == 0) break;
00759 }
00760 #else
00761 w_short(*d, arg);
00762 #endif
00763 d++;
00764 }
00765 }
00766 break;
00767
00768 case T_STRING:
00769 w_uclass(obj, rb_cString, arg);
00770 w_byte(TYPE_STRING, arg);
00771 w_bytes(RSTRING_PTR(obj), RSTRING_LEN(obj), arg);
00772 break;
00773
00774 case T_REGEXP:
00775 w_uclass(obj, rb_cRegexp, arg);
00776 w_byte(TYPE_REGEXP, arg);
00777 {
00778 int opts = rb_reg_options(obj);
00779 w_bytes(RREGEXP_SRC_PTR(obj), RREGEXP_SRC_LEN(obj), arg);
00780 w_byte((char)opts, arg);
00781 }
00782 break;
00783
00784 case T_ARRAY:
00785 w_uclass(obj, rb_cArray, arg);
00786 w_byte(TYPE_ARRAY, arg);
00787 {
00788 long i, len = RARRAY_LEN(obj);
00789
00790 w_long(len, arg);
00791 for (i=0; i<RARRAY_LEN(obj); i++) {
00792 w_object(RARRAY_AREF(obj, i), arg, limit);
00793 if (len != RARRAY_LEN(obj)) {
00794 rb_raise(rb_eRuntimeError, "array modified during dump");
00795 }
00796 }
00797 }
00798 break;
00799
00800 case T_HASH:
00801 w_uclass(obj, rb_cHash, arg);
00802 if (NIL_P(RHASH_IFNONE(obj))) {
00803 w_byte(TYPE_HASH, arg);
00804 }
00805 else if (FL_TEST(obj, HASH_PROC_DEFAULT)) {
00806 rb_raise(rb_eTypeError, "can't dump hash with default proc");
00807 }
00808 else {
00809 w_byte(TYPE_HASH_DEF, arg);
00810 }
00811 w_long(RHASH_SIZE(obj), arg);
00812 rb_hash_foreach(obj, hash_each, (st_data_t)&c_arg);
00813 if (!NIL_P(RHASH_IFNONE(obj))) {
00814 w_object(RHASH_IFNONE(obj), arg, limit);
00815 }
00816 break;
00817
00818 case T_STRUCT:
00819 w_class(TYPE_STRUCT, obj, arg, TRUE);
00820 {
00821 long len = RSTRUCT_LEN(obj);
00822 VALUE mem;
00823 long i;
00824
00825 w_long(len, arg);
00826 mem = rb_struct_members(obj);
00827 for (i=0; i<len; i++) {
00828 w_symbol(SYM2ID(RARRAY_AREF(mem, i)), arg);
00829 w_object(RSTRUCT_GET(obj, i), arg, limit);
00830 }
00831 }
00832 break;
00833
00834 case T_OBJECT:
00835 w_class(TYPE_OBJECT, obj, arg, TRUE);
00836 w_objivar(obj, &c_arg);
00837 break;
00838
00839 case T_DATA:
00840 {
00841 VALUE v;
00842
00843 if (!rb_obj_respond_to(obj, s_dump_data, TRUE)) {
00844 rb_raise(rb_eTypeError,
00845 "no _dump_data is defined for class %s",
00846 rb_obj_classname(obj));
00847 }
00848 v = rb_funcall2(obj, s_dump_data, 0, 0);
00849 check_dump_arg(arg, s_dump_data);
00850 w_class(TYPE_DATA, obj, arg, TRUE);
00851 w_object(v, arg, limit);
00852 }
00853 break;
00854
00855 default:
00856 rb_raise(rb_eTypeError, "can't dump %s",
00857 rb_obj_classname(obj));
00858 break;
00859 }
00860 RB_GC_GUARD(obj);
00861 }
00862 if (hasiv) {
00863 w_ivar(obj, ivtbl, &c_arg);
00864 }
00865 }
00866
00867 static void
00868 clear_dump_arg(struct dump_arg *arg)
00869 {
00870 if (!arg->symbols) return;
00871 st_free_table(arg->symbols);
00872 arg->symbols = 0;
00873 st_free_table(arg->data);
00874 arg->data = 0;
00875 st_free_table(arg->compat_tbl);
00876 arg->compat_tbl = 0;
00877 if (arg->encodings) {
00878 st_free_table(arg->encodings);
00879 arg->encodings = 0;
00880 }
00881 }
00882
00883 NORETURN(static inline void io_needed(void));
00884 static inline void
00885 io_needed(void)
00886 {
00887 rb_raise(rb_eTypeError, "instance of IO needed");
00888 }
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924 static VALUE
00925 marshal_dump(int argc, VALUE *argv)
00926 {
00927 VALUE obj, port, a1, a2;
00928 int limit = -1;
00929 struct dump_arg *arg;
00930 volatile VALUE wrapper;
00931
00932 port = Qnil;
00933 rb_scan_args(argc, argv, "12", &obj, &a1, &a2);
00934 if (argc == 3) {
00935 if (!NIL_P(a2)) limit = NUM2INT(a2);
00936 if (NIL_P(a1)) io_needed();
00937 port = a1;
00938 }
00939 else if (argc == 2) {
00940 if (FIXNUM_P(a1)) limit = FIX2INT(a1);
00941 else if (NIL_P(a1)) io_needed();
00942 else port = a1;
00943 }
00944 RB_GC_GUARD(wrapper) = TypedData_Make_Struct(rb_cData, struct dump_arg, &dump_arg_data, arg);
00945 arg->dest = 0;
00946 arg->symbols = st_init_numtable();
00947 arg->data = st_init_numtable();
00948 arg->infection = 0;
00949 arg->compat_tbl = st_init_numtable();
00950 arg->encodings = 0;
00951 arg->str = rb_str_buf_new(0);
00952 if (!NIL_P(port)) {
00953 if (!rb_respond_to(port, s_write)) {
00954 io_needed();
00955 }
00956 arg->dest = port;
00957 if (rb_check_funcall(port, s_binmode, 0, 0) != Qundef) {
00958 check_dump_arg(arg, s_binmode);
00959 }
00960 }
00961 else {
00962 port = arg->str;
00963 }
00964
00965 w_byte(MARSHAL_MAJOR, arg);
00966 w_byte(MARSHAL_MINOR, arg);
00967
00968 w_object(obj, arg, limit);
00969 if (arg->dest) {
00970 rb_io_write(arg->dest, arg->str);
00971 rb_str_resize(arg->str, 0);
00972 }
00973 clear_dump_arg(arg);
00974 RB_GC_GUARD(wrapper);
00975
00976 return port;
00977 }
00978
00979 struct load_arg {
00980 VALUE src;
00981 char *buf;
00982 long buflen;
00983 long readable;
00984 long offset;
00985 st_table *symbols;
00986 st_table *data;
00987 VALUE proc;
00988 st_table *compat_tbl;
00989 int infection;
00990 };
00991
00992 static void
00993 check_load_arg(struct load_arg *arg, ID sym)
00994 {
00995 if (!arg->symbols) {
00996 rb_raise(rb_eRuntimeError, "Marshal.load reentered at %s",
00997 rb_id2name(sym));
00998 }
00999 }
01000
01001 static void clear_load_arg(struct load_arg *arg);
01002
01003 static void
01004 mark_load_arg(void *ptr)
01005 {
01006 struct load_arg *p = ptr;
01007 if (!p->symbols)
01008 return;
01009 rb_mark_tbl(p->data);
01010 rb_mark_hash(p->compat_tbl);
01011 }
01012
01013 static void
01014 free_load_arg(void *ptr)
01015 {
01016 clear_load_arg(ptr);
01017 xfree(ptr);
01018 }
01019
01020 static size_t
01021 memsize_load_arg(const void *ptr)
01022 {
01023 return ptr ? sizeof(struct load_arg) : 0;
01024 }
01025
01026 static const rb_data_type_t load_arg_data = {
01027 "load_arg",
01028 {mark_load_arg, free_load_arg, memsize_load_arg,},
01029 NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
01030 };
01031
01032 #define r_entry(v, arg) r_entry0((v), (arg)->data->num_entries, (arg))
01033 static VALUE r_entry0(VALUE v, st_index_t num, struct load_arg *arg);
01034 static VALUE r_object(struct load_arg *arg);
01035 static ID r_symbol(struct load_arg *arg);
01036 static VALUE path2class(VALUE path);
01037
01038 NORETURN(static void too_short(void));
01039 static void
01040 too_short(void)
01041 {
01042 rb_raise(rb_eArgError, "marshal data too short");
01043 }
01044
01045 static st_index_t
01046 r_prepare(struct load_arg *arg)
01047 {
01048 st_index_t idx = arg->data->num_entries;
01049
01050 st_insert(arg->data, (st_data_t)idx, (st_data_t)Qundef);
01051 return idx;
01052 }
01053
01054 static unsigned char
01055 r_byte1_buffered(struct load_arg *arg)
01056 {
01057 if (arg->buflen == 0) {
01058 long readable = arg->readable < BUFSIZ ? arg->readable : BUFSIZ;
01059 VALUE str, n = LONG2NUM(readable);
01060
01061 str = rb_funcall2(arg->src, s_read, 1, &n);
01062
01063 check_load_arg(arg, s_read);
01064 if (NIL_P(str)) too_short();
01065 StringValue(str);
01066 arg->infection |= (int)FL_TEST(str, MARSHAL_INFECTION);
01067 memcpy(arg->buf, RSTRING_PTR(str), RSTRING_LEN(str));
01068 arg->offset = 0;
01069 arg->buflen = RSTRING_LEN(str);
01070 }
01071 arg->buflen--;
01072 return arg->buf[arg->offset++];
01073 }
01074
01075 static int
01076 r_byte(struct load_arg *arg)
01077 {
01078 int c;
01079
01080 if (RB_TYPE_P(arg->src, T_STRING)) {
01081 if (RSTRING_LEN(arg->src) > arg->offset) {
01082 c = (unsigned char)RSTRING_PTR(arg->src)[arg->offset++];
01083 }
01084 else {
01085 too_short();
01086 }
01087 }
01088 else {
01089 if (arg->readable >0 || arg->buflen > 0) {
01090 c = r_byte1_buffered(arg);
01091 }
01092 else {
01093 VALUE v = rb_funcall2(arg->src, s_getbyte, 0, 0);
01094 check_load_arg(arg, s_getbyte);
01095 if (NIL_P(v)) rb_eof_error();
01096 c = (unsigned char)NUM2CHR(v);
01097 }
01098 }
01099 return c;
01100 }
01101
01102 static void
01103 long_toobig(int size)
01104 {
01105 rb_raise(rb_eTypeError, "long too big for this architecture (size "
01106 STRINGIZE(SIZEOF_LONG)", given %d)", size);
01107 }
01108
01109 #undef SIGN_EXTEND_CHAR
01110 #if __STDC__
01111 # define SIGN_EXTEND_CHAR(c) ((signed char)(c))
01112 #else
01113
01114 # define SIGN_EXTEND_CHAR(c) ((((unsigned char)(c)) ^ 128) - 128)
01115 #endif
01116
01117 static long
01118 r_long(struct load_arg *arg)
01119 {
01120 register long x;
01121 int c = SIGN_EXTEND_CHAR(r_byte(arg));
01122 long i;
01123
01124 if (c == 0) return 0;
01125 if (c > 0) {
01126 if (4 < c && c < 128) {
01127 return c - 5;
01128 }
01129 if (c > (int)sizeof(long)) long_toobig(c);
01130 x = 0;
01131 for (i=0;i<c;i++) {
01132 x |= (long)r_byte(arg) << (8*i);
01133 }
01134 }
01135 else {
01136 if (-129 < c && c < -4) {
01137 return c + 5;
01138 }
01139 c = -c;
01140 if (c > (int)sizeof(long)) long_toobig(c);
01141 x = -1;
01142 for (i=0;i<c;i++) {
01143 x &= ~((long)0xff << (8*i));
01144 x |= (long)r_byte(arg) << (8*i);
01145 }
01146 }
01147 return x;
01148 }
01149
01150 static VALUE
01151 r_bytes1(long len, struct load_arg *arg)
01152 {
01153 VALUE str, n = LONG2NUM(len);
01154
01155 str = rb_funcall2(arg->src, s_read, 1, &n);
01156 check_load_arg(arg, s_read);
01157 if (NIL_P(str)) too_short();
01158 StringValue(str);
01159 if (RSTRING_LEN(str) != len) too_short();
01160 arg->infection |= (int)FL_TEST(str, MARSHAL_INFECTION);
01161
01162 return str;
01163 }
01164
01165 static VALUE
01166 r_bytes1_buffered(long len, struct load_arg *arg)
01167 {
01168 VALUE str;
01169
01170 if (len <= arg->buflen) {
01171 str = rb_str_new(arg->buf+arg->offset, len);
01172 arg->offset += len;
01173 arg->buflen -= len;
01174 }
01175 else {
01176 long buflen = arg->buflen;
01177 long readable = arg->readable + 1;
01178 long tmp_len, read_len, need_len = len - buflen;
01179 VALUE tmp, n;
01180
01181 readable = readable < BUFSIZ ? readable : BUFSIZ;
01182 read_len = need_len > readable ? need_len : readable;
01183 n = LONG2NUM(read_len);
01184 tmp = rb_funcall2(arg->src, s_read, 1, &n);
01185
01186 check_load_arg(arg, s_read);
01187 if (NIL_P(tmp)) too_short();
01188 StringValue(tmp);
01189
01190 tmp_len = RSTRING_LEN(tmp);
01191
01192 if (tmp_len < need_len) too_short();
01193 arg->infection |= (int)FL_TEST(tmp, MARSHAL_INFECTION);
01194
01195 str = rb_str_new(arg->buf+arg->offset, buflen);
01196 rb_str_cat(str, RSTRING_PTR(tmp), need_len);
01197
01198 if (tmp_len > need_len) {
01199 buflen = tmp_len - need_len;
01200 memcpy(arg->buf, RSTRING_PTR(tmp)+need_len, buflen);
01201 arg->buflen = buflen;
01202 }
01203 else {
01204 arg->buflen = 0;
01205 }
01206 arg->offset = 0;
01207 }
01208
01209 return str;
01210 }
01211
01212 #define r_bytes(arg) r_bytes0(r_long(arg), (arg))
01213
01214 static VALUE
01215 r_bytes0(long len, struct load_arg *arg)
01216 {
01217 VALUE str;
01218
01219 if (len == 0) return rb_str_new(0, 0);
01220 if (RB_TYPE_P(arg->src, T_STRING)) {
01221 if (RSTRING_LEN(arg->src) - arg->offset >= len) {
01222 str = rb_str_new(RSTRING_PTR(arg->src)+arg->offset, len);
01223 arg->offset += len;
01224 }
01225 else {
01226 too_short();
01227 }
01228 }
01229 else {
01230 if (arg->readable > 0 || arg->buflen > 0) {
01231 str = r_bytes1_buffered(len, arg);
01232 }
01233 else {
01234 str = r_bytes1(len, arg);
01235 }
01236 }
01237 return str;
01238 }
01239
01240 static int
01241 id2encidx(ID id, VALUE val)
01242 {
01243 if (id == rb_id_encoding()) {
01244 int idx = rb_enc_find_index(StringValueCStr(val));
01245 return idx;
01246 }
01247 else if (id == rb_intern("E")) {
01248 if (val == Qfalse) return rb_usascii_encindex();
01249 else if (val == Qtrue) return rb_utf8_encindex();
01250
01251 }
01252 return -1;
01253 }
01254
01255 static ID
01256 r_symlink(struct load_arg *arg)
01257 {
01258 st_data_t id;
01259 long num = r_long(arg);
01260
01261 if (!st_lookup(arg->symbols, num, &id)) {
01262 rb_raise(rb_eArgError, "bad symbol");
01263 }
01264 return (ID)id;
01265 }
01266
01267 static ID
01268 r_symreal(struct load_arg *arg, int ivar)
01269 {
01270 VALUE s = r_bytes(arg);
01271 ID id;
01272 int idx = -1;
01273 st_index_t n = arg->symbols->num_entries;
01274
01275 st_insert(arg->symbols, (st_data_t)n, (st_data_t)0);
01276 if (ivar) {
01277 long num = r_long(arg);
01278 while (num-- > 0) {
01279 id = r_symbol(arg);
01280 idx = id2encidx(id, r_object(arg));
01281 }
01282 }
01283 if (idx > 0) rb_enc_associate_index(s, idx);
01284 id = rb_intern_str(s);
01285 st_insert(arg->symbols, (st_data_t)n, (st_data_t)id);
01286
01287 return id;
01288 }
01289
01290 static ID
01291 r_symbol(struct load_arg *arg)
01292 {
01293 int type, ivar = 0;
01294
01295 again:
01296 switch ((type = r_byte(arg))) {
01297 default:
01298 rb_raise(rb_eArgError, "dump format error for symbol(0x%x)", type);
01299 case TYPE_IVAR:
01300 ivar = 1;
01301 goto again;
01302 case TYPE_SYMBOL:
01303 return r_symreal(arg, ivar);
01304 case TYPE_SYMLINK:
01305 if (ivar) {
01306 rb_raise(rb_eArgError, "dump format error (symlink with encoding)");
01307 }
01308 return r_symlink(arg);
01309 }
01310 }
01311
01312 static VALUE
01313 r_unique(struct load_arg *arg)
01314 {
01315 return rb_id2str(r_symbol(arg));
01316 }
01317
01318 static VALUE
01319 r_string(struct load_arg *arg)
01320 {
01321 return r_bytes(arg);
01322 }
01323
01324 static VALUE
01325 r_entry0(VALUE v, st_index_t num, struct load_arg *arg)
01326 {
01327 st_data_t real_obj = (VALUE)Qundef;
01328 if (st_lookup(arg->compat_tbl, v, &real_obj)) {
01329 st_insert(arg->data, num, (st_data_t)real_obj);
01330 }
01331 else {
01332 st_insert(arg->data, num, (st_data_t)v);
01333 }
01334 if (arg->infection &&
01335 !RB_TYPE_P(v, T_CLASS) && !RB_TYPE_P(v, T_MODULE)) {
01336 FL_SET(v, arg->infection);
01337 if ((VALUE)real_obj != Qundef)
01338 FL_SET((VALUE)real_obj, arg->infection);
01339 }
01340 return v;
01341 }
01342
01343 static VALUE
01344 r_fixup_compat(VALUE v, struct load_arg *arg)
01345 {
01346 st_data_t data;
01347 if (st_lookup(arg->compat_tbl, v, &data)) {
01348 VALUE real_obj = (VALUE)data;
01349 rb_alloc_func_t allocator = rb_get_alloc_func(CLASS_OF(real_obj));
01350 st_data_t key = v;
01351 if (st_lookup(compat_allocator_tbl, (st_data_t)allocator, &data)) {
01352 marshal_compat_t *compat = (marshal_compat_t*)data;
01353 compat->loader(real_obj, v);
01354 }
01355 st_delete(arg->compat_tbl, &key, 0);
01356 v = real_obj;
01357 }
01358 return v;
01359 }
01360
01361 static VALUE
01362 r_post_proc(VALUE v, struct load_arg *arg)
01363 {
01364 if (arg->proc) {
01365 v = rb_funcall(arg->proc, s_call, 1, v);
01366 check_load_arg(arg, s_call);
01367 }
01368 return v;
01369 }
01370
01371 static VALUE
01372 r_leave(VALUE v, struct load_arg *arg)
01373 {
01374 v = r_fixup_compat(v, arg);
01375 v = r_post_proc(v, arg);
01376 return v;
01377 }
01378
01379 static int
01380 copy_ivar_i(st_data_t key, st_data_t val, st_data_t arg)
01381 {
01382 VALUE obj = (VALUE)arg, value = (VALUE)val;
01383 ID vid = (ID)key;
01384
01385 if (!rb_ivar_defined(obj, vid))
01386 rb_ivar_set(obj, vid, value);
01387 return ST_CONTINUE;
01388 }
01389
01390 static VALUE
01391 r_copy_ivar(VALUE v, VALUE data)
01392 {
01393 rb_ivar_foreach(data, copy_ivar_i, (st_data_t)v);
01394 return v;
01395 }
01396
01397 static void
01398 r_ivar(VALUE obj, int *has_encoding, struct load_arg *arg)
01399 {
01400 long len;
01401
01402 len = r_long(arg);
01403 if (len > 0) {
01404 do {
01405 ID id = r_symbol(arg);
01406 VALUE val = r_object(arg);
01407 int idx = id2encidx(id, val);
01408 if (idx >= 0) {
01409 rb_enc_associate_index(obj, idx);
01410 if (has_encoding) *has_encoding = TRUE;
01411 }
01412 else {
01413 rb_ivar_set(obj, id, val);
01414 }
01415 } while (--len > 0);
01416 }
01417 }
01418
01419 static VALUE
01420 path2class(VALUE path)
01421 {
01422 VALUE v = rb_path_to_class(path);
01423
01424 if (!RB_TYPE_P(v, T_CLASS)) {
01425 rb_raise(rb_eArgError, "%"PRIsVALUE" does not refer to class", path);
01426 }
01427 return v;
01428 }
01429
01430 #define path2module(path) must_be_module(rb_path_to_class(path), path)
01431
01432 static VALUE
01433 must_be_module(VALUE v, VALUE path)
01434 {
01435 if (!RB_TYPE_P(v, T_MODULE)) {
01436 rb_raise(rb_eArgError, "%"PRIsVALUE" does not refer to module", path);
01437 }
01438 return v;
01439 }
01440
01441 static VALUE
01442 obj_alloc_by_klass(VALUE klass, struct load_arg *arg, VALUE *oldclass)
01443 {
01444 st_data_t data;
01445 rb_alloc_func_t allocator;
01446
01447 allocator = rb_get_alloc_func(klass);
01448 if (st_lookup(compat_allocator_tbl, (st_data_t)allocator, &data)) {
01449 marshal_compat_t *compat = (marshal_compat_t*)data;
01450 VALUE real_obj = rb_obj_alloc(klass);
01451 VALUE obj = rb_obj_alloc(compat->oldclass);
01452 if (oldclass) *oldclass = compat->oldclass;
01453 st_insert(arg->compat_tbl, (st_data_t)obj, (st_data_t)real_obj);
01454 return obj;
01455 }
01456
01457 return rb_obj_alloc(klass);
01458 }
01459
01460 static VALUE
01461 obj_alloc_by_path(VALUE path, struct load_arg *arg)
01462 {
01463 return obj_alloc_by_klass(path2class(path), arg, 0);
01464 }
01465
01466 static VALUE
01467 append_extmod(VALUE obj, VALUE extmod)
01468 {
01469 long i = RARRAY_LEN(extmod);
01470 while (i > 0) {
01471 VALUE m = RARRAY_AREF(extmod, --i);
01472 rb_extend_object(obj, m);
01473 }
01474 return obj;
01475 }
01476
01477 #define prohibit_ivar(type, str) do { \
01478 if (!ivp || !*ivp) break; \
01479 rb_raise(rb_eTypeError, \
01480 "can't override instance variable of "type" `%"PRIsVALUE"'", \
01481 (str)); \
01482 } while (0)
01483
01484 static VALUE
01485 r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
01486 {
01487 VALUE v = Qnil;
01488 int type = r_byte(arg);
01489 long id;
01490 st_data_t link;
01491
01492 switch (type) {
01493 case TYPE_LINK:
01494 id = r_long(arg);
01495 if (!st_lookup(arg->data, (st_data_t)id, &link)) {
01496 rb_raise(rb_eArgError, "dump format error (unlinked)");
01497 }
01498 v = (VALUE)link;
01499 r_post_proc(v, arg);
01500 break;
01501
01502 case TYPE_IVAR:
01503 {
01504 int ivar = TRUE;
01505
01506 v = r_object0(arg, &ivar, extmod);
01507 if (ivar) r_ivar(v, NULL, arg);
01508 }
01509 break;
01510
01511 case TYPE_EXTENDED:
01512 {
01513 VALUE path = r_unique(arg);
01514 VALUE m = rb_path_to_class(path);
01515
01516 if (RB_TYPE_P(m, T_CLASS)) {
01517 VALUE c;
01518
01519 v = r_object0(arg, 0, Qnil);
01520 c = CLASS_OF(v);
01521 if (c != m || FL_TEST(c, FL_SINGLETON)) {
01522 rb_raise(rb_eArgError,
01523 "prepended class %"PRIsVALUE" differs from class %"PRIsVALUE,
01524 path, rb_class_name(c));
01525 }
01526 c = rb_singleton_class(v);
01527 while (RARRAY_LEN(extmod) > 0) {
01528 m = rb_ary_pop(extmod);
01529 rb_prepend_module(c, m);
01530 }
01531 }
01532 else {
01533 must_be_module(m, path);
01534 if (NIL_P(extmod)) extmod = rb_ary_tmp_new(0);
01535 rb_ary_push(extmod, m);
01536
01537 v = r_object0(arg, 0, extmod);
01538 while (RARRAY_LEN(extmod) > 0) {
01539 m = rb_ary_pop(extmod);
01540 rb_extend_object(v, m);
01541 }
01542 }
01543 }
01544 break;
01545
01546 case TYPE_UCLASS:
01547 {
01548 VALUE c = path2class(r_unique(arg));
01549
01550 if (FL_TEST(c, FL_SINGLETON)) {
01551 rb_raise(rb_eTypeError, "singleton can't be loaded");
01552 }
01553 v = r_object0(arg, 0, extmod);
01554 if (rb_special_const_p(v) || RB_TYPE_P(v, T_OBJECT) || RB_TYPE_P(v, T_CLASS)) {
01555 format_error:
01556 rb_raise(rb_eArgError, "dump format error (user class)");
01557 }
01558 if (RB_TYPE_P(v, T_MODULE) || !RTEST(rb_class_inherited_p(c, RBASIC(v)->klass))) {
01559 VALUE tmp = rb_obj_alloc(c);
01560
01561 if (TYPE(v) != TYPE(tmp)) goto format_error;
01562 }
01563 RBASIC_SET_CLASS(v, c);
01564 }
01565 break;
01566
01567 case TYPE_NIL:
01568 v = Qnil;
01569 v = r_leave(v, arg);
01570 break;
01571
01572 case TYPE_TRUE:
01573 v = Qtrue;
01574 v = r_leave(v, arg);
01575 break;
01576
01577 case TYPE_FALSE:
01578 v = Qfalse;
01579 v = r_leave(v, arg);
01580 break;
01581
01582 case TYPE_FIXNUM:
01583 {
01584 long i = r_long(arg);
01585 v = LONG2FIX(i);
01586 }
01587 v = r_leave(v, arg);
01588 break;
01589
01590 case TYPE_FLOAT:
01591 {
01592 double d;
01593 VALUE str = r_bytes(arg);
01594 const char *ptr = RSTRING_PTR(str);
01595
01596 if (strcmp(ptr, "nan") == 0) {
01597 d = NAN;
01598 }
01599 else if (strcmp(ptr, "inf") == 0) {
01600 d = INFINITY;
01601 }
01602 else if (strcmp(ptr, "-inf") == 0) {
01603 d = -INFINITY;
01604 }
01605 else {
01606 char *e;
01607 d = strtod(ptr, &e);
01608 d = load_mantissa(d, e, RSTRING_LEN(str) - (e - ptr));
01609 }
01610 v = DBL2NUM(d);
01611 v = r_entry(v, arg);
01612 v = r_leave(v, arg);
01613 }
01614 break;
01615
01616 case TYPE_BIGNUM:
01617 {
01618 long len;
01619 VALUE data;
01620 int sign;
01621
01622 sign = r_byte(arg);
01623 len = r_long(arg);
01624 data = r_bytes0(len * 2, arg);
01625 v = rb_integer_unpack(RSTRING_PTR(data), len, 2, 0,
01626 INTEGER_PACK_LITTLE_ENDIAN | (sign == '-' ? INTEGER_PACK_NEGATIVE : 0));
01627 rb_str_resize(data, 0L);
01628 v = r_entry(v, arg);
01629 v = r_leave(v, arg);
01630 }
01631 break;
01632
01633 case TYPE_STRING:
01634 v = r_entry(r_string(arg), arg);
01635 v = r_leave(v, arg);
01636 break;
01637
01638 case TYPE_REGEXP:
01639 {
01640 VALUE str = r_bytes(arg);
01641 int options = r_byte(arg);
01642 int has_encoding = FALSE;
01643 st_index_t idx = r_prepare(arg);
01644
01645 if (ivp) {
01646 r_ivar(str, &has_encoding, arg);
01647 *ivp = FALSE;
01648 }
01649 if (!has_encoding) {
01650
01651 char *ptr = RSTRING_PTR(str), *dst = ptr, *src = ptr;
01652 long len = RSTRING_LEN(str);
01653 long bs = 0;
01654 for (; len-- > 0; *dst++ = *src++) {
01655 switch (*src) {
01656 case '\\': bs++; break;
01657 case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
01658 case 'm': case 'o': case 'p': case 'q': case 'u': case 'y':
01659 case 'E': case 'F': case 'H': case 'I': case 'J': case 'K':
01660 case 'L': case 'N': case 'O': case 'P': case 'Q': case 'R':
01661 case 'S': case 'T': case 'U': case 'V': case 'X': case 'Y':
01662 if (bs & 1) --dst;
01663 default: bs = 0; break;
01664 }
01665 }
01666 rb_str_set_len(str, dst - ptr);
01667 }
01668 v = r_entry0(rb_reg_new_str(str, options), idx, arg);
01669 v = r_leave(v, arg);
01670 }
01671 break;
01672
01673 case TYPE_ARRAY:
01674 {
01675 volatile long len = r_long(arg);
01676
01677 v = rb_ary_new2(len);
01678 v = r_entry(v, arg);
01679 arg->readable += len - 1;
01680 while (len--) {
01681 rb_ary_push(v, r_object(arg));
01682 arg->readable--;
01683 }
01684 v = r_leave(v, arg);
01685 arg->readable++;
01686 }
01687 break;
01688
01689 case TYPE_HASH:
01690 case TYPE_HASH_DEF:
01691 {
01692 long len = r_long(arg);
01693
01694 v = rb_hash_new();
01695 v = r_entry(v, arg);
01696 arg->readable += (len - 1) * 2;
01697 while (len--) {
01698 VALUE key = r_object(arg);
01699 VALUE value = r_object(arg);
01700 rb_hash_aset(v, key, value);
01701 arg->readable -= 2;
01702 }
01703 arg->readable += 2;
01704 if (type == TYPE_HASH_DEF) {
01705 RHASH_SET_IFNONE(v, r_object(arg));
01706 }
01707 v = r_leave(v, arg);
01708 }
01709 break;
01710
01711 case TYPE_STRUCT:
01712 {
01713 VALUE mem, values;
01714 volatile long i;
01715 ID slot;
01716 st_index_t idx = r_prepare(arg);
01717 VALUE klass = path2class(r_unique(arg));
01718 long len = r_long(arg);
01719
01720 v = rb_obj_alloc(klass);
01721 if (!RB_TYPE_P(v, T_STRUCT)) {
01722 rb_raise(rb_eTypeError, "class %s not a struct", rb_class2name(klass));
01723 }
01724 mem = rb_struct_s_members(klass);
01725 if (RARRAY_LEN(mem) != len) {
01726 rb_raise(rb_eTypeError, "struct %s not compatible (struct size differs)",
01727 rb_class2name(klass));
01728 }
01729
01730 arg->readable += (len - 1) * 2;
01731 v = r_entry0(v, idx, arg);
01732 values = rb_ary_new2(len);
01733 for (i=0; i<len; i++) {
01734 slot = r_symbol(arg);
01735
01736 if (RARRAY_AREF(mem, i) != ID2SYM(slot)) {
01737 rb_raise(rb_eTypeError, "struct %s not compatible (:%s for :%s)",
01738 rb_class2name(klass),
01739 rb_id2name(slot),
01740 rb_id2name(SYM2ID(RARRAY_AREF(mem, i))));
01741 }
01742 rb_ary_push(values, r_object(arg));
01743 arg->readable -= 2;
01744 }
01745 rb_struct_initialize(v, values);
01746 v = r_leave(v, arg);
01747 arg->readable += 2;
01748 }
01749 break;
01750
01751 case TYPE_USERDEF:
01752 {
01753 VALUE klass = path2class(r_unique(arg));
01754 VALUE data;
01755
01756 if (!rb_obj_respond_to(klass, s_load, TRUE)) {
01757 rb_raise(rb_eTypeError, "class %s needs to have method `_load'",
01758 rb_class2name(klass));
01759 }
01760 data = r_string(arg);
01761 if (ivp) {
01762 r_ivar(data, NULL, arg);
01763 *ivp = FALSE;
01764 }
01765 v = rb_funcall2(klass, s_load, 1, &data);
01766 check_load_arg(arg, s_load);
01767 v = r_entry(v, arg);
01768 v = r_leave(v, arg);
01769 }
01770 break;
01771
01772 case TYPE_USRMARSHAL:
01773 {
01774 VALUE klass = path2class(r_unique(arg));
01775 VALUE oldclass = 0;
01776 VALUE data;
01777
01778 v = obj_alloc_by_klass(klass, arg, &oldclass);
01779 if (!NIL_P(extmod)) {
01780
01781 append_extmod(v, extmod);
01782 }
01783 if (!rb_obj_respond_to(v, s_mload, TRUE)) {
01784 rb_raise(rb_eTypeError, "instance of %s needs to have method `marshal_load'",
01785 rb_class2name(klass));
01786 }
01787 v = r_entry(v, arg);
01788 data = r_object(arg);
01789 rb_funcall2(v, s_mload, 1, &data);
01790 check_load_arg(arg, s_mload);
01791 v = r_fixup_compat(v, arg);
01792 v = r_copy_ivar(v, data);
01793 v = r_post_proc(v, arg);
01794 if (!NIL_P(extmod)) {
01795 if (oldclass) append_extmod(v, extmod);
01796 rb_ary_clear(extmod);
01797 }
01798 }
01799 break;
01800
01801 case TYPE_OBJECT:
01802 {
01803 st_index_t idx = r_prepare(arg);
01804 v = obj_alloc_by_path(r_unique(arg), arg);
01805 if (!RB_TYPE_P(v, T_OBJECT)) {
01806 rb_raise(rb_eArgError, "dump format error");
01807 }
01808 v = r_entry0(v, idx, arg);
01809 r_ivar(v, NULL, arg);
01810 v = r_leave(v, arg);
01811 }
01812 break;
01813
01814 case TYPE_DATA:
01815 {
01816 VALUE klass = path2class(r_unique(arg));
01817 VALUE oldclass = 0;
01818 VALUE r;
01819
01820 v = obj_alloc_by_klass(klass, arg, &oldclass);
01821 if (!RB_TYPE_P(v, T_DATA)) {
01822 rb_raise(rb_eArgError, "dump format error");
01823 }
01824 v = r_entry(v, arg);
01825 if (!rb_obj_respond_to(v, s_load_data, TRUE)) {
01826 rb_raise(rb_eTypeError,
01827 "class %s needs to have instance method `_load_data'",
01828 rb_class2name(klass));
01829 }
01830 r = r_object0(arg, 0, extmod);
01831 rb_funcall2(v, s_load_data, 1, &r);
01832 check_load_arg(arg, s_load_data);
01833 v = r_leave(v, arg);
01834 }
01835 break;
01836
01837 case TYPE_MODULE_OLD:
01838 {
01839 VALUE str = r_bytes(arg);
01840
01841 v = rb_path_to_class(str);
01842 prohibit_ivar("class/module", str);
01843 v = r_entry(v, arg);
01844 v = r_leave(v, arg);
01845 }
01846 break;
01847
01848 case TYPE_CLASS:
01849 {
01850 VALUE str = r_bytes(arg);
01851
01852 v = path2class(str);
01853 prohibit_ivar("class", str);
01854 v = r_entry(v, arg);
01855 v = r_leave(v, arg);
01856 }
01857 break;
01858
01859 case TYPE_MODULE:
01860 {
01861 VALUE str = r_bytes(arg);
01862
01863 v = path2module(str);
01864 prohibit_ivar("module", str);
01865 v = r_entry(v, arg);
01866 v = r_leave(v, arg);
01867 }
01868 break;
01869
01870 case TYPE_SYMBOL:
01871 if (ivp) {
01872 v = ID2SYM(r_symreal(arg, *ivp));
01873 *ivp = FALSE;
01874 }
01875 else {
01876 v = ID2SYM(r_symreal(arg, 0));
01877 }
01878 v = r_leave(v, arg);
01879 break;
01880
01881 case TYPE_SYMLINK:
01882 v = ID2SYM(r_symlink(arg));
01883 break;
01884
01885 default:
01886 rb_raise(rb_eArgError, "dump format error(0x%x)", type);
01887 break;
01888 }
01889 return v;
01890 }
01891
01892 static VALUE
01893 r_object(struct load_arg *arg)
01894 {
01895 return r_object0(arg, 0, Qnil);
01896 }
01897
01898 static void
01899 clear_load_arg(struct load_arg *arg)
01900 {
01901 if (arg->buf) {
01902 xfree(arg->buf);
01903 arg->buf = 0;
01904 }
01905 arg->buflen = 0;
01906 arg->offset = 0;
01907 arg->readable = 0;
01908 if (!arg->symbols) return;
01909 st_free_table(arg->symbols);
01910 arg->symbols = 0;
01911 st_free_table(arg->data);
01912 arg->data = 0;
01913 st_free_table(arg->compat_tbl);
01914 arg->compat_tbl = 0;
01915 }
01916
01917
01918
01919
01920
01921
01922
01923
01924
01925
01926
01927
01928
01929
01930
01931 static VALUE
01932 marshal_load(int argc, VALUE *argv)
01933 {
01934 VALUE port, proc;
01935 int major, minor, infection = 0;
01936 VALUE v;
01937 volatile VALUE wrapper;
01938 struct load_arg *arg;
01939
01940 rb_scan_args(argc, argv, "11", &port, &proc);
01941 v = rb_check_string_type(port);
01942 if (!NIL_P(v)) {
01943 infection = (int)FL_TEST(port, MARSHAL_INFECTION);
01944 port = v;
01945 }
01946 else if (rb_respond_to(port, s_getbyte) && rb_respond_to(port, s_read)) {
01947 rb_check_funcall(port, s_binmode, 0, 0);
01948 infection = (int)FL_TAINT;
01949 }
01950 else {
01951 io_needed();
01952 }
01953 RB_GC_GUARD(wrapper) = TypedData_Make_Struct(rb_cData, struct load_arg, &load_arg_data, arg);
01954 arg->infection = infection;
01955 arg->src = port;
01956 arg->offset = 0;
01957 arg->symbols = st_init_numtable();
01958 arg->data = st_init_numtable();
01959 arg->compat_tbl = st_init_numtable();
01960 arg->proc = 0;
01961 arg->readable = 0;
01962
01963 if (NIL_P(v))
01964 arg->buf = xmalloc(BUFSIZ);
01965 else
01966 arg->buf = 0;
01967
01968 major = r_byte(arg);
01969 minor = r_byte(arg);
01970 if (major != MARSHAL_MAJOR || minor > MARSHAL_MINOR) {
01971 clear_load_arg(arg);
01972 rb_raise(rb_eTypeError, "incompatible marshal file format (can't be read)\n\
01973 \tformat version %d.%d required; %d.%d given",
01974 MARSHAL_MAJOR, MARSHAL_MINOR, major, minor);
01975 }
01976 if (RTEST(ruby_verbose) && minor != MARSHAL_MINOR) {
01977 rb_warn("incompatible marshal file format (can be read)\n\
01978 \tformat version %d.%d required; %d.%d given",
01979 MARSHAL_MAJOR, MARSHAL_MINOR, major, minor);
01980 }
01981
01982 if (!NIL_P(proc)) arg->proc = proc;
01983 v = r_object(arg);
01984 clear_load_arg(arg);
01985 RB_GC_GUARD(wrapper);
01986
01987 return v;
01988 }
01989
01990
01991
01992
01993
01994
01995
01996
01997
01998
01999
02000
02001
02002
02003
02004
02005
02006
02007
02008
02009
02010
02011
02012
02013
02014
02015
02016
02017
02018
02019
02020
02021
02022
02023
02024
02025
02026
02027
02028
02029
02030
02031
02032
02033
02034
02035
02036
02037
02038
02039
02040
02041
02042
02043
02044
02045
02046
02047
02048
02049
02050
02051
02052
02053
02054
02055
02056
02057
02058
02059
02060
02061
02062
02063
02064
02065
02066
02067
02068
02069
02070
02071
02072
02073
02074
02075
02076
02077
02078
02079
02080
02081
02082
02083
02084
02085
02086
02087
02088
02089
02090
02091
02092
02093
02094
02095
02096
02097
02098
02099
02100
02101 void
02102 Init_marshal(void)
02103 {
02104 #undef rb_intern
02105 #define rb_intern(str) rb_intern_const(str)
02106
02107 VALUE rb_mMarshal = rb_define_module("Marshal");
02108
02109 s_dump = rb_intern("_dump");
02110 s_load = rb_intern("_load");
02111 s_mdump = rb_intern("marshal_dump");
02112 s_mload = rb_intern("marshal_load");
02113 s_dump_data = rb_intern("_dump_data");
02114 s_load_data = rb_intern("_load_data");
02115 s_alloc = rb_intern("_alloc");
02116 s_call = rb_intern("call");
02117 s_getbyte = rb_intern("getbyte");
02118 s_read = rb_intern("read");
02119 s_write = rb_intern("write");
02120 s_binmode = rb_intern("binmode");
02121
02122 rb_define_module_function(rb_mMarshal, "dump", marshal_dump, -1);
02123 rb_define_module_function(rb_mMarshal, "load", marshal_load, -1);
02124 rb_define_module_function(rb_mMarshal, "restore", marshal_load, -1);
02125
02126
02127 rb_define_const(rb_mMarshal, "MAJOR_VERSION", INT2FIX(MARSHAL_MAJOR));
02128
02129 rb_define_const(rb_mMarshal, "MINOR_VERSION", INT2FIX(MARSHAL_MINOR));
02130
02131 compat_allocator_tbl = st_init_numtable();
02132 compat_allocator_tbl_wrapper =
02133 Data_Wrap_Struct(rb_cData, mark_marshal_compat_t, 0, compat_allocator_tbl);
02134 rb_gc_register_mark_object(compat_allocator_tbl_wrapper);
02135 }
02136
02137 VALUE
02138 rb_marshal_dump(VALUE obj, VALUE port)
02139 {
02140 int argc = 1;
02141 VALUE argv[2];
02142
02143 argv[0] = obj;
02144 argv[1] = port;
02145 if (!NIL_P(port)) argc = 2;
02146 return marshal_dump(argc, argv);
02147 }
02148
02149 VALUE
02150 rb_marshal_load(VALUE port)
02151 {
02152 return marshal_load(1, &port);
02153 }
02154