internal static string r_unique(Frame caller, load_arg arg) { return Symbol.rb_id2name((uint)r_symbol(caller, arg)); }
internal static object r_entry(Frame caller, object v, load_arg arg) { Ruby.Methods.rb_hash_aset.singleton.Call2(null, arg.data, caller, null, ((Hash)(arg.data)).value.Count, v); if (arg.taint) { ((Basic)v).Tainted = true; } return v; }
internal static int r_symreal(Frame caller, load_arg arg) { int id; id = (int)Symbol.rb_intern(((String)r_bytes(caller, arg)).value); arg.symbols.Add(arg.symbols.Count, id); return id; }
internal static int r_symbol(Frame caller, load_arg arg) { if (r_byte(caller, arg) == TYPE_SYMLINK) { return r_symlink(caller, arg); } return r_symreal(caller, arg); }
internal static object load_ensure(load_arg arg) { arg.symbols = null; return null; }
//---------------------------------------------------------------------------------- internal static int r_symlink(Frame caller, load_arg arg) { int id; int num = r_long(caller, arg); if (arg.symbols.ContainsKey(num)) { id = arg.symbols[num]; return id; } throw new ArgumentError("bad symbol").raise(caller); }
internal static object r_object0(Frame caller, load_arg arg, object proc, ref int ivp, object extmod) { object v = null; int type = r_byte(caller, arg); int id; switch (type) { case TYPE_LINK: //TEST: id = r_long(caller, arg); v = Ruby.Methods.rb_hash_aref.singleton.Call1(null, arg.data, caller, null, id); if (v == null) { throw new ArgumentError("dump format error (unlinked)").raise(caller); } return v; case TYPE_IVAR: //TEST: { int ivar = 1; v = r_object0(caller, arg, null, ref ivar, extmod); if (ivar > 0) r_ivar(caller, v, arg); } break; case TYPE_EXTENDED: //TEST: { object m = path2module(r_unique(caller, arg), caller); if (extmod == null) { extmod = new Array(); ((Array)extmod).value.Add(m); } int temp = 0; v = r_object0(caller, arg, null, ref temp, extmod); while (((Array)extmod).value.Count > 0) { m = ((Array)extmod).value[((Array)extmod).value.Count - 1]; ((Array)extmod).value.RemoveAt(((Array)extmod).value.Count - 1); Class.rb_extend_object(caller, v, (Class)m); } } break; case TYPE_UCLASS: { object c = path2class(caller, r_unique(caller, arg)); if (((Class)c)._type == Class.Type.Singleton) { throw new TypeError("singleton can't be loaded").raise(caller); } int temp = 0; v = r_object0(caller, arg, null, ref temp, extmod); if (rb_special_const_p(v) || v is Object || (v is Class && ((Class)v)._type == Class.Type.Class)) { throw new ArgumentError("dump format error (user class)").raise(caller); } if ((v is Class && ((Class)v)._type == Class.Type.Module) || !RTEST(Ruby.Methods.rb_class_inherited_p.singleton.Call1(null, c, caller, null, ((Basic)v).my_class))) { object tmp = new Object((Class)c); //TODO: Write this comparison //if (TYPE(v) != TYPE(tmp)) //{ // throw new ArgumentError("dump format error (user class)").raise(caller); //} } ((Basic)v).my_class = (Class)c; } break; case TYPE_NIL: v = null; break; case TYPE_TRUE: v = true; break; case TYPE_FALSE: v = false; break; case TYPE_FIXNUM: { v = r_long(caller, arg); } break; case TYPE_FLOAT: { double d; object str = r_bytes(caller, arg); string ptr = ((String)str).value; if (ptr.Equals("nan")) { d = double.NaN; } else if (ptr.Equals("inf")) { d = double.PositiveInfinity; } else if (ptr.Equals("-inf")) { d = double.NegativeInfinity; } else if (ptr.Equals("-0")) { d = -0.0; } else { int e = 0; d = String.strtod(ptr, 0, out e); d = load_mantissa(d, ptr.Substring(e), ((String)str).value.Length - e); } v = new Float(d); r_entry(caller, v, arg); } break; case TYPE_BIGNUM: { int len; uint[] digits; object data; int sign = ((char)r_byte(caller, arg) == '+') ? 1 : -1; len = r_long(caller, arg); data = r_bytes0(caller, len * 2, arg); int bigLen = (len + 1) * 2 / SIZEOF_BDIGITS; //extract data to bytes digits = new uint[bigLen]; byte[] digitData = new byte[bigLen * SIZEOF_BDIGITS]; char[] charDigitData = ((String)data).value.ToCharArray(); for (int i = 0; i < ((String)data).value.Length; i++) { digitData[i] = (byte)charDigitData[i]; } //save data to digits for (int uintCount = 0; uintCount < digits.Length; uintCount++) { digits[uintCount] = System.BitConverter.ToUInt32(digitData, (uintCount * 4)); } v = new Bignum(new IronMath.integer(sign, digits)); r_entry(caller, v, arg); } break; case TYPE_STRING: v = r_entry(caller, r_string(caller, arg), arg); break; case TYPE_REGEXP: { object str = r_bytes(caller, arg); int options = r_byte(caller, arg); v = r_entry(caller, new Regexp(((String)str).value, options), arg); } break; case TYPE_ARRAY: { int len = r_long(caller, arg); v = new Array(); r_entry(caller, v, arg); while (len-- > 0) { ((Array)v).value.Add(r_object(caller, arg)); } } break; case TYPE_HASH: case TYPE_HASH_DEF: { int len = r_long(caller, arg); v = new Hash(); r_entry(caller, v, arg); while (len-- > 0) { object key = r_object(caller, arg); object value = r_object(caller, arg); ((Hash)v).Add(key, value); } if (type == TYPE_HASH_DEF) { ((Hash)v).defaultValue = r_object(caller, arg); } } break; case TYPE_STRUCT: { Class klass; object mem; object[] values; int len; int slot; string klassPath = r_unique(caller, arg); klass = (Class)path2class(caller, klassPath); mem = Ruby.Methods.rb_struct_s_members.singleton.Call0(klass, klass, caller, null); if (mem == null) { throw new TypeError("uninitialized struct").raise(caller); } len = r_long(caller, arg); values = new object[len]; for (int i = 0; i < len; i++) { slot = r_symbol(caller, arg); if ((string)((Array)mem).value[i] != Symbol.rb_id2name((uint)slot)) { string errorString = string.Format(CultureInfo.InvariantCulture, "struct {0} not compatible (:{1} for :{2})", rb_class2name(klass, caller), Symbol.rb_id2name((uint)slot), ((Array)mem).value[i]); throw new TypeError(errorString).raise(caller); } values[i] = r_object(caller, arg); } v = Ruby.Methods.rb_class_new_instance.singleton.Call(klass, klass, caller, null, new Array(values)); r_entry(caller, v, arg); } break; case TYPE_USERDEF: { object klass = path2class(caller, r_unique(caller, arg)); object data; if (!Eval.RespondTo(klass, s_load)) { throw new TypeError(string.Format(CultureInfo.InvariantCulture, "class {0} needs to have method `_load'", rb_class2name(klass, caller))).raise(caller); } data = r_string(caller, arg); if (ivp > 0) { r_ivar(caller, data, arg); ivp = 0; } v = Eval.CallPrivate1(klass, caller, s_load, null, data); r_entry(caller, v, arg); } break; case TYPE_USRMARSHAL: { object klass = path2class(caller, r_unique(caller, arg)); object data; v = Ruby.Methods.rb_obj_alloc.singleton.Call0(null, klass, caller, null); if (extmod != null) { while (((Array)extmod).value.Count > 0) { object m = ((Array)extmod).value[((Array)extmod).value.Count - 1]; ((Array)extmod).value.RemoveAt(((Array)extmod).value.Count - 1); Class.rb_extend_object(caller, v, (Class)m); } } if (!Eval.RespondTo(v, s_mload)) { throw new TypeError(string.Format(CultureInfo.InvariantCulture, "instance of {0} needs to have method `marshal_load'", rb_class2name(klass, caller))).raise(caller); } r_entry(caller, v, arg); data = r_object(caller, arg); Eval.CallPrivate1(v, caller, s_mload, null, data); } break; case TYPE_OBJECT: { object klass = path2class(caller, r_unique(caller, arg)); v = Ruby.Methods.rb_obj_alloc.singleton.Call0(null, klass, caller, null); if (!(v is Object)) { throw new ArgumentError("dump format error").raise(caller); } r_entry(caller, v, arg); r_ivar(caller, v, arg); } break; case TYPE_DATA://TEST { object klass = path2class(caller, r_unique(caller, arg)); if (Eval.RespondTo(klass, s_alloc)) { type_data_warn = true; //TEST: static int warn = Qtrue; - test that this is equivalent note the 'STATIC' keyword if (type_data_warn) { Errors.rb_warn("define `allocate' instead of `_alloc'"); type_data_warn = false; } v = Eval.CallPrivate0(klass, caller, s_alloc, null); } else { v = Ruby.Methods.rb_obj_alloc.singleton.Call0(null, klass, caller, null); } if (!(v is Data)) { throw new ArgumentError("dump format error").raise(caller); } r_entry(caller, v, arg); if (!Eval.RespondTo(v, s_load_data)) { throw new TypeError(string.Format(CultureInfo.InvariantCulture, "class {0} needs to have instance method `_load_data'", rb_class2name(klass, caller))).raise(caller); } int temp = 0; Eval.CallPrivate1(v, caller, s_load_data, null, r_object0(caller, arg, null, ref temp, extmod)); } break; case TYPE_MODULE_OLD: //TEST: { object str = r_bytes(caller, arg); v = rb_path2class(caller, ((String)str).value); r_entry(caller, v, arg); } break; case TYPE_CLASS: { object str = r_bytes(caller, arg); v = path2class(caller, ((String)str).value); r_entry(caller, v, arg); } break; case TYPE_MODULE: //TEST: { object str = r_bytes(caller, arg); v = path2module(((String)str).value, caller); r_entry(caller, v, arg); } break; case TYPE_SYMBOL: //TEST: v = new Symbol((uint)r_symreal(caller, arg)); break; case TYPE_SYMLINK: //TEST: return new Symbol((uint)r_symlink(caller, arg)); default: throw new ArgumentError(string.Format(CultureInfo.InvariantCulture, "dump format error(0x{0})", type)).raise(caller); } if (proc != null) //TEST: { Eval.CallPrivate1(proc, caller, "call", null, v); } return v; }
//---------------------------------------------------------------------------------- internal static object load(Frame caller, load_arg arg) { return r_object(caller, arg); }
internal static object r_object( Frame caller, load_arg arg) { int temp = 0; return r_object0(caller, arg, arg.proc, ref temp, null); }
internal static void r_ivar(Frame caller, object obj, load_arg arg) { int len; len = r_long(caller, arg); if (len > 0) { while (len-- > 0) { int id = r_symbol(caller, arg); object val = r_object(caller, arg); rb_ivar_set(caller, obj, id, val); } } }
internal static object r_string(Frame caller, load_arg arg) { return r_bytes(caller, arg); }
internal static int r_long( Frame caller, load_arg arg) { int x; int c = ((((char)r_byte(caller, arg)) ^ 128) - 128); if (c == 0) return 0; if (c > 0) { if (4 < c && c < 128) { return c - 5; } if (c > SIZEOF_LONG) long_toobig(caller, c); x = 0; for (int i = 0; i < c; i++) { x |= (int)r_byte(caller, arg) << (8 * i); } } else { if (-129 < c && c < -4) { return c + 5; } c = -c; if (c > SIZEOF_LONG) long_toobig(caller, c); x = -1; for (int i = 0; i < c; i++) { x &= ~((int)0xff << (8 * i)); x |= (int)r_byte(caller, arg) << (8 * i); } } return x; }
internal static int r_byte(Frame caller, load_arg arg) { int c; if (arg.src is String) { if (((String)arg.src).value.Length > arg.offset) { c = (byte)((String)arg.src).value[arg.offset++]; } else { throw new ArgumentError("marshal data too short").raise(caller); } } else { object src = arg.src; object v = Eval.CallPrivate(src, caller, s_getc, null); if (v == null) { throw EOFError.rb_eof_error().raise(caller); } c = (byte)(int)v; } return c; }
internal static object r_bytes0(Frame caller, int len, load_arg arg) { object str; if (len == 0) return new String(); if (arg.src is String) { if (((String)arg.src).value.Length > arg.offset) { str = new String(((String)arg.src).value.Substring(arg.offset, len)); arg.offset += len; } else { goto too_short; } } else { object src = arg.src; object n = len; //TEST: the address of n is passed in the ruby code, these calls probably arn't equivalent // str = rb_funcall2(src, s_read, 1, &n); str = Eval.CallPrivate(src, caller, s_read, null, n); if (str == null) goto too_short; if (!(str is String)) { str = String.StringValue(str, caller); } if (((String)str).value.Length != len) goto too_short; if (((Basic)str).Tainted) { arg.taint = true; } if(((Basic)str).Tainted) { arg.taint = true; } } return str; too_short: throw new ArgumentError("marshal data too short").raise(caller); }
internal static object r_bytes(Frame caller, load_arg arg) { return r_bytes0(caller, r_long(caller, arg), arg); }