internal static void w_object(object obj, dump_arg arg, int limit, Frame caller) { dump_call_arg c_arg = new dump_call_arg(); System.Collections.Generic.Dictionary<string, object> ivtbl = null; // st_data_t num; if (limit == 0) { throw new ArgumentError("exceed depth limit").raise(caller); } limit--; c_arg.limit = limit; c_arg.arg = arg; if (obj != null && arg.data.ContainsKey(obj)) { int num = arg.data[obj]; w_byte(TYPE_LINK, arg, caller); w_long(num, arg, caller); return; } ivtbl = Object.get_generic_ivars(obj); if (ivtbl != null) { w_byte(TYPE_IVAR, arg, caller); } if (obj == null) { w_byte(TYPE_NIL, arg, caller); } else if (obj is bool && (bool)obj == true) { w_byte(TYPE_TRUE, arg, caller); } else if (obj is bool && (bool)obj == false) { w_byte(TYPE_FALSE, arg, caller); } else if (obj is int) { w_byte((char)TYPE_FIXNUM, arg, caller); w_long((int)obj, arg, caller); } else if (obj is Symbol) { //FIXME: This code isn't being reached at the moment. //should be ok since the latest fixes - haven't tested this though w_symbol((int)((Symbol)obj).id_new, arg, caller); } else { if (((Basic)obj).Tainted) { arg.taint = true; } arg.data[obj] = arg.data.Count; if (Eval.RespondTo(obj, s_mdump)) { object v; v = Eval.CallPublic0(obj, caller, s_mdump, null); w_class(TYPE_USRMARSHAL, obj, arg, false, caller); w_object(v, arg, limit, caller); if (ivtbl != null) w_ivar(null, c_arg, caller); return; } if (Eval.RespondTo(obj, s_dump)) //TEST: { object v; v = Eval.CallPrivate(obj, caller, s_dump, null, limit); if (!(v is String)) { throw new TypeError("_dump() must return string").raise(caller); } if (ivtbl == null && (ivtbl = Object.get_generic_ivars(v)) != null) { w_byte(TYPE_IVAR, arg, caller); } w_class(TYPE_USERDEF, obj, arg, false, caller); w_bytes(((String)v).value, ((String)v).value.Length, arg, caller); if (ivtbl != null) { w_ivar(ivtbl, c_arg, caller); } return; } if (obj is Class) { if (((Class)obj)._type == Class.Type.Class) { if (((Class)obj)._type == Class.Type.Singleton) { throw new TypeError("singleton class can't be dumped").raise(caller); } w_byte(TYPE_CLASS, arg, caller); { object path = class2path(obj, caller); w_bytes(((String)path).value, ((String)path).value.Length, arg, caller); } } else if (((Class)obj)._type == Class.Type.Module)//TEST: { w_byte(TYPE_MODULE, arg, caller); { object path = class2path(obj, caller); w_bytes(((String)path).value, ((String)path).value.Length, arg, caller); } } } else if (obj is Float) { w_byte((char)TYPE_FLOAT, arg, caller); w_float(((Float)obj).value, arg, caller); } else if (obj is Bignum) { w_byte((char)TYPE_BIGNUM, arg, caller); { char sign = ((Bignum)(obj)).value.Sign < 0 ? '-' : '+'; long len = ((Bignum)(obj)).value.length; uint[] d = ((Bignum)(obj)).value.Data; w_byte((char)sign, arg, caller); w_long(shortlen(len, d), arg, caller); /* w_short? */ int dIndex = 0; while (len-- > 0) { uint num = d[dIndex]; int i; for (i = 0; i < SIZEOF_BDIGITS; i += SIZEOF_SHORT) { w_short((int)num & SHORTMASK, arg, caller); num = num >> BITSPERSHORT; if (len == 0 && num == 0) break; } dIndex++; } } } else if (obj is Struct) { w_class(TYPE_STRUCT, obj, arg, true, caller); { int len; object mem; len = StructLen(obj, caller); mem = rb_struct_members(obj, caller); w_long(len, arg, caller); for (int i = 0; i < len; i++) { string symbolString = (string)((Array)mem).value[i]; //no interning atm w_symbol((int)Symbol.rb_intern(symbolString), arg, caller); w_object(((Struct)obj).instance_vars[symbolString], arg, limit, caller); } } } else if (obj is String) { w_uclass(obj, Ruby.Runtime.Init.rb_cString, arg, caller); w_byte((char)TYPE_STRING, arg, caller); w_bytes(((String)obj).value, ((String)obj).value.Length, arg, caller); } else if (obj is Regexp) { w_uclass(obj, Ruby.Runtime.Init.rb_cRegexp, arg, caller); w_byte(TYPE_REGEXP, arg, caller); string regExpStr = ((Regexp)obj).value.ToString(); w_bytes(regExpStr, regExpStr.Length, arg, caller); w_byte((char)Regexp.rb_reg_options(caller, (Regexp)obj), arg, caller); } else if (obj is Array) { w_uclass(obj, Ruby.Runtime.Init.rb_cArray, arg, caller); w_byte((char)TYPE_ARRAY, arg, caller); { int len = ((Array)obj).Count; System.Collections.ArrayList ptr = ((Array)obj).value; w_long(len, arg, caller); foreach (object arrObj in ptr) { w_object(arrObj, arg, limit, caller); } } } else if (obj is Hash) { w_uclass(obj, Ruby.Runtime.Init.rb_cHash, arg, caller); if (((Hash)obj).defaultProc != null) throw new TypeError("cannot dump hash with default proc").raise(caller); else if (((Hash)obj).defaultValue == null) w_byte(TYPE_HASH, arg, caller); else w_byte(TYPE_HASH_DEF, arg, caller); w_long(((Hash)(obj)).value.Count, arg, caller); foreach (HashKeyValuePair pair in ((Hash)obj).value) { w_object(pair.Key.key, c_arg.arg, c_arg.limit, caller); w_object(pair.Value, c_arg.arg, c_arg.limit, caller); } if (((Hash)obj).defaultValue != null) w_object(((Hash)obj).defaultValue, arg, limit, caller); } else if (obj is Data) //TEST: { object v; w_class(TYPE_DATA, obj, arg, true, caller); if (!Eval.RespondTo(obj, s_dump_data)) throw new TypeError(string.Format(CultureInfo.InvariantCulture, "no marshal_dump is defined for class {0}", rb_obj_classname(obj, caller))).raise(caller); v = Eval.CallPrivate0(obj, caller, s_dump_data, null); w_object(v, arg, limit, caller); } else if (obj is Object)//TEST: { w_class(TYPE_OBJECT, obj, arg, true, caller); w_ivar(((Object)obj).instance_vars, c_arg, caller); } else throw new TypeError(string.Format(CultureInfo.InvariantCulture, "can't dump {0}", ((Basic)obj).my_class.classname())).raise(caller); } if (ivtbl != null) { w_ivar(ivtbl, c_arg, caller); } }
internal static void w_extended(Class klass, dump_arg arg, bool check, Frame caller) { string path; if (klass._type == Class.Type.Singleton) { if (check && klass._methods.Count > 0 || (klass.instance_vars.Count > 0)) { throw new TypeError("singleton can't be dumped").raise(caller); } klass = klass.super; } while (klass._type == Class.Type.IClass) //TEST: { path = rb_class2name(((Basic)klass).my_class, caller); w_byte(TYPE_EXTENDED, arg, caller); w_unique(path, arg, caller); klass = ((Class)klass).super; } }
internal static void w_class(char type, object obj, dump_arg arg, bool check, Frame caller) { string path; object klass = Class.CLASS_OF(obj); w_extended((Class)klass, arg, check, caller); w_byte(type, arg, caller); path = ((String)class2path(((Class)klass).class_real(), caller)).value; w_unique(path, arg, caller); }
internal static void w_unique(string s, dump_arg arg, Frame caller) { if (s.Length > 0 && s[0] == '#') { throw new TypeError(string.Format(CultureInfo.InvariantCulture, "can't dump anonymous class {0}", s)).raise(caller); } w_symbol((int)Symbol.rb_intern(s), arg, caller); }
internal static void w_uclass(object obj, Class base_klass, dump_arg arg, Frame caller) { Class klass = Class.CLASS_OF(obj); w_extended(klass, arg, true, caller); klass = klass.class_real(); if (klass != base_klass) { w_byte((char)TYPE_UCLASS, arg, caller); w_unique(klass.classname(), arg, caller); } }
internal static void w_float(double d, dump_arg arg, Frame caller) { System.Text.StringBuilder buf = new System.Text.StringBuilder(); if (double.IsInfinity(d)) { if (double.IsNegativeInfinity(d)) { buf.Append("-inf"); } else { buf.Append("inf"); } } else if (double.IsNaN(d)) { buf.Append("nan"); } else if (d == 0.00) { if (1.0 / d < 0)//TEST: will this behave correctly in C#??? { buf.Append("-0"); } else { buf.Append("0"); } } else { int len; buf.Append(d.ToString("r", CultureInfo.InvariantCulture)); len = buf.Length; char[] bufArray = new char[20]; int manLength = save_mantissa(d, bufArray); len += manLength; buf.Append(new System.String(bufArray, 0, manLength)); w_bytes(buf.ToString(), len, arg, caller); return; } string bufString = buf.ToString(); w_bytes(bufString, bufString.Length, arg, caller); }
internal static void w_symbol(int id, dump_arg arg, Frame caller) { string sym = Symbol.rb_id2name((uint) id); int num; if (arg.symbols.ContainsKey(id)) { num = arg.symbols[id]; w_byte(TYPE_SYMLINK, arg, caller); w_long(num, arg, caller); } else { w_byte(TYPE_SYMBOL, arg, caller); w_bytes(sym, sym.Length, arg, caller); arg.symbols.Add(id, arg.symbols.Count); } }
internal static void w_short(int x, dump_arg arg, Frame caller) { w_byte((char)((x >> 0) & 0xff), arg, caller); w_byte((char)((x >> 8) & 0xff), arg, caller); }
internal static void w_long(int x, dump_arg arg, Frame caller) { int sizeOfInt = 4; char[] buf = new char[sizeOfInt + 1]; int i = 0; int len = 0; if (x == 0) { w_byte((char)0, arg, caller); return; } if (0 < x && x < 123) { w_byte((char)(x + 5), arg, caller); return; } if (-124 < x && x < 0) { w_byte((char)((x - 5) & 0xff), arg, caller); return; } for (i = 1; i < sizeOfInt + 1; i++) { buf[i] = (char)(x & 0xff); x = x >> 8; if (x == 0) { buf[0] = (char)(byte)i; break; } if (x == 0) { buf[0] = (char)(byte)i; break; } if (x == -1) { buf[0] = (char)(byte)-i; break; } } len = i; for (i = 0; i <= len; i++) { w_byte(buf[i], arg, caller); } }
internal static void w_bytes(string s, int n, dump_arg arg, Frame caller) { w_long(n, arg, caller); w_nbyte(s, n, arg, caller); }
internal static void w_nbyte(string s, int n, dump_arg arg, Frame caller) { object buf = arg.str; ((String)buf).value = ((String)buf).value + s.Substring(0, n); if (arg.dest != null && ((String)buf).value.Length >= BUFSIZ) { if (arg.taint) { ((Basic)buf).Tainted = true; } rb_io_write(arg.dest, buf, caller); ((String)buf).value = ""; } }
//---------------------------------------------------------------------------------- internal static void w_byte(char c, dump_arg arg, Frame caller) { w_nbyte(c.ToString(), 1, arg, caller); }
internal static object dump_ensure(dump_arg arg) { arg.symbols = null; arg.data = null; if (arg.taint) { ((Basic)arg.str).Tainted = true; } return null; }
internal dump_call_arg() { obj = null; arg = null; limit = 0; }