/// <summary> /// static void w_object(VALUE obj, struct dump_arg *arg, int limit) /// </summary> /// <param name="obj"></param> public void WriteObject(object obj) { int num; if (_m_objects.TryGetValue(obj, out num)) { WriteByte(RubyMarshal.Types.LINK); WriteLong(num); return; } if (obj == null || obj == RubyNil.Instance) { WriteByte(RubyMarshal.Types.NIL); } else if (obj is bool && (bool)obj) { WriteByte(RubyMarshal.Types.TRUE); } else if (obj is bool && (bool)obj == false) { WriteByte(RubyMarshal.Types.FALSE); } else if (obj is RubyBool ruby_bool) { WriteByte(ruby_bool.Value ? RubyMarshal.Types.TRUE : RubyMarshal.Types.FALSE); } else if (obj is int || obj is long || obj is RubyFixnum) { long v; if (obj is int | obj is long) { v = (long)obj; } else { v = ((RubyFixnum)obj).Value; } // (2**30).class => Bignum // (2**30-1).class => Fixnum // (-2**30-1).class=> Bignum // (-2**30).class => Fixnum if (v <= RubyFixnum.MaxValue && v >= RubyFixnum.MinValue) { WriteByte(RubyMarshal.Types.FIXNUM); WriteLong((int)v); } else { WriteObject(RubyBignum.Create(v)); } } else if (obj is RubySymbol ruby_symbol) { WriteSymbol(ruby_symbol); } else { var fobj = obj as RubyObject; var hasiv = false; if (fobj != null) { hasiv = (obj is RubyArray || obj is RubyHash) && fobj.InstanceVariables.Count > 0; } if (fobj is RubyString ruby_string) { hasiv |= StringStyle == RubyMarshal.StringStyleType.Style19 && fobj.Encoding != null && ruby_string.Text.Length > 0; } if (obj is DefaultRubyUserDefinedMarshalDumpObject default_ruby_user_defined_marshal_dump_object) { if (hasiv) { WriteByte(RubyMarshal.Types.INSTANCE_VARIABLE); } WriteClass(RubyMarshal.Types.USER_MARSHAL, obj, false); default_ruby_user_defined_marshal_dump_object.Write(_m_writer); if (hasiv) { WriteObjectInstanceVariable(fobj); } _m_objects.Add(obj, _m_objects.Count); return; } if (obj is RubyUserDefinedObject ruby_user_defined_object) { if (hasiv) { WriteByte(RubyMarshal.Types.INSTANCE_VARIABLE); } _m_writer.Write(RubyMarshal.Types.USER_DEFINED); WriteSymbol(fobj.ClassName); ruby_user_defined_object.Write(_m_writer); if (hasiv) { WriteObjectInstanceVariable(fobj); } _m_objects.Add(obj, _m_objects.Count); return; } _m_objects.Add(obj, _m_objects.Count); if (hasiv) { WriteByte(RubyMarshal.Types.INSTANCE_VARIABLE); } if (obj is RubyClass ruby_class) { WriteByte(RubyMarshal.Types.CLASS); WriteCString(ruby_class.Name); } else if (obj is RubyModule ruby_module) { WriteByte(RubyMarshal.Types.MODULE); WriteCString(ruby_module.Name); } else if (obj is float _float) { WriteByte(RubyMarshal.Types.FLOAT); WriteFloat(_float); } else if (obj is double _double) { WriteByte(RubyMarshal.Types.FLOAT); WriteFloat(_double); } else if (obj is RubyFloat ruby_float) { WriteByte(RubyMarshal.Types.FLOAT); WriteFloat(ruby_float); } else if (obj is RubyBignum ruby_bignum) { char ch; if (ruby_bignum.Sign > 0) { ch = '+'; } else if (ruby_bignum.Sign < 0) { ch = '-'; } else { ch = '0'; } _m_writer.Write((byte)ch); var words = ruby_bignum.GetWords(); var num2 = words.Length * 2; var index = words.Length - 1; /* * var flag = false; * if (words.Length > 0 && words[index] >> 0x10 == 0) * { * num--; * flag = true; * }*/ var flag = words.Length > 0 && words[index] >> 0x10 == 0; WriteLong(num2); for (var i = 0; i < words.Length; i++) { if (flag && i == index) { _m_writer.Write((ushort)words[i]); } else { _m_writer.Write(words[i]); } } } else if (obj is RubyString || obj is string) { RubyString v; if (obj is string _string) { v = new RubyString(_string); } else { v = (RubyString)obj; } WriteUserClass(v, RubyClass.GetClass("String")); WriteByte(RubyMarshal.Types.STRING); WriteBytes(v.Raw); } else if (obj is RubyRegexp ruby_regexp) { WriteUserClass(obj, RubyClass.GetClass("Regexp")); WriteByte(RubyMarshal.Types.REGEXP); WriteBytes(ruby_regexp.pattern.Raw); WriteByte((byte)ruby_regexp.options); } else if (obj is RubyArray || obj is List <object> ) { RubyArray v; if (obj is List <object> list) { v = new RubyArray(list); } else { v = (RubyArray)obj; } WriteUserClass(v, RubyClass.GetClass("Array")); WriteByte(RubyMarshal.Types.ARRAY); WriteLong(v.Length); foreach (var t in v) { WriteObject(t); } } else if (obj is RubyHash ruby_hash) { WriteUserClass(obj, RubyClass.GetClass("Hash")); WriteByte(ruby_hash.DefaultValue != null ? RubyMarshal.Types.HASH_WITH_DEFAULT : RubyMarshal.Types.HASH); WriteLong(ruby_hash.Length); foreach (var item in ruby_hash) { WriteObject(item.Key); WriteObject(item.Value); } if (ruby_hash.DefaultValue != null) { WriteObject(ruby_hash.DefaultValue); } } else if (obj is RubyStruct ruby_struct) { WriteUserClass(obj, RubyClass.GetClass("Struct")); WriteLong(ruby_struct.InstanceVariables.Count); foreach (var item in ruby_struct.InstanceVariables) { WriteObject(item.Key); WriteObject(item.Value); } } else if (obj is RubyObject ruby_object) { WriteClass(RubyMarshal.Types.OBJECT, obj, true); WriteObjectInstanceVariable(ruby_object); } else { throw new InvalidDataException($"can't dump {obj.GetType().FullName}"); } if (hasiv) { WriteInstanceVariable(fobj, fobj.InstanceVariables); } } }
/// <summary> /// static void w_object(VALUE obj, struct dump_arg *arg, int limit) /// </summary> /// <param name="obj"></param> public void WriteObject(object obj) { int num; if (this.m_objects.TryGetValue(obj, out num)) { WriteByte(RubyMarshal.Types.Link); WriteLong(num); return; } if (obj == null || obj == RubyNil.Instance) { WriteByte(RubyMarshal.Types.Nil); } else if (obj is bool && (bool)obj == true) { WriteByte(RubyMarshal.Types.True); } else if (obj is bool && (bool)obj == false) { WriteByte(RubyMarshal.Types.False); } else if (obj is int) { int v = (int)obj; // (2**30).class => Bignum // (2**30-1).class => Fixnum // (-2**30-1).class=> Bignum // (-2**30).class => Fixnum if (v <= 1073741823 && v >= -1073741824) { WriteByte(RubyMarshal.Types.Fixnum); WriteLong(v); } else { WriteObject(RubyBignum.Create(v)); } } else if (obj is RubySymbol) { WriteSymbol(obj as RubySymbol); } else { RubyObject fobj = obj as RubyObject; bool hasiv = false; if (fobj != null) { hasiv = (obj as RubyObject).InstanceVariables.Count > 0 || fobj.Encoding != null; } if (obj is IRubyUserdefinedMarshalDumpObject) { this.m_objects.Add(obj, this.m_objects.Count); object result = (obj as IRubyUserdefinedMarshalDumpObject).Dump(); if (hasiv) { WriteByte(RubyMarshal.Types.InstanceVariable); } WriteClass(RubyMarshal.Types.UserMarshal, obj, false); WriteObject(result); if (hasiv) { WriteObjectInstanceVariable(fobj); } return; } if (obj is IRubyUserdefinedDumpObject) { byte[] result = (obj as IRubyUserdefinedDumpObject).Dump(); if (hasiv) { WriteByte(RubyMarshal.Types.InstanceVariable); } WriteClass(RubyMarshal.Types.UserDefined, obj, false); WriteBytes(result, result.Length); if (hasiv) { WriteObjectInstanceVariable(fobj); } this.m_objects.Add(obj, this.m_objects.Count); return; } this.m_objects.Add(obj, this.m_objects.Count); /* * { * st_data_t compat_data; * rb_alloc_func_t allocator = rb_get_alloc_func(RBASIC(obj)->klass); * if (st_lookup(compat_allocator_tbl, * (st_data_t)allocator, * &compat_data)) { * marshal_compat_t *compat = (marshal_compat_t*)compat_data; * VALUE real_obj = obj; * obj = compat->dumper(real_obj); * st_insert(arg->compat_tbl, (st_data_t)obj, (st_data_t)real_obj); * if (obj != real_obj && !ivtbl) hasiv = 0; * } * }*/ if (hasiv) { WriteByte(RubyMarshal.Types.InstanceVariable); } if (obj is RubyClass) { WriteByte(RubyMarshal.Types.Class); WriteCString((obj as RubyClass).Name); } else if (obj is RubyModule) { WriteByte(RubyMarshal.Types.Module); WriteCString((obj as RubyModule).Name); } else if (obj is float) { WriteByte(RubyMarshal.Types.Float); WriteFloat((float)obj); } else if (obj is double) { WriteByte(RubyMarshal.Types.Float); WriteFloat((double)obj); } else if (obj is RubyFloat) { WriteByte(RubyMarshal.Types.Float); WriteFloat((RubyFloat)obj); } else if (obj is RubyBignum) { RubyBignum value = (RubyBignum)obj; char ch; if (value.Sign > 0) { ch = '+'; } else if (value.Sign < 0) { ch = '-'; } else { ch = '0'; } this.m_writer.Write((byte)ch); uint[] words = value.GetWords(); int num2 = words.Length * 2; int index = words.Length - 1; bool flag = false; if ((words.Length > 0) && ((words[index] >> 0x10) == 0)) { num--; flag = true; } this.WriteLong(num2); for (int i = 0; i < words.Length; i++) { if (flag && (i == index)) { this.m_writer.Write((ushort)words[i]); } else { this.m_writer.Write(words[i]); } } } else if (obj is RubyString || obj is string) { RubyString v; if (obj is string) { v = new RubyString(obj as string); } else { v = (RubyString)obj; } WriteUserClass(v, RubyClass.GetClass("String")); WriteByte(RubyMarshal.Types.String); WriteBytes(v.Raw); } else if (obj is RubyRegexp) { RubyRegexp v = (RubyRegexp)obj; WriteUserClass(obj, RubyClass.GetClass("Regexp")); WriteByte(RubyMarshal.Types.Regexp); WriteBytes(v.Pattern.Raw); WriteByte((byte)v.Options); } else if (obj is RubyArray || obj is List <object> ) { RubyArray v; if (obj is List <object> ) { v = new RubyArray(obj as List <object>); } else { v = (RubyArray)obj; } WriteUserClass(v, RubyClass.GetClass("Array")); WriteByte(RubyMarshal.Types.Array); WriteLong(v.Length); for (int i = 0; i < v.Count; i++) { WriteObject(v[i]); } } else if (obj is RubyHash) { RubyHash v = (RubyHash)obj; WriteUserClass(obj, RubyClass.GetClass("Hash")); WriteByte(v.DefaultValue != null ? RubyMarshal.Types.HashWithDefault : RubyMarshal.Types.Hash); WriteLong(v.Length); foreach (KeyValuePair <object, object> item in v) { WriteObject(item.Key); WriteObject(item.Value); } if (v.DefaultValue != null) { WriteObject(v.DefaultValue); } } else if (obj is RubyStruct) { RubyStruct v = (RubyStruct)obj; WriteUserClass(obj, RubyClass.GetClass("Struct")); WriteLong(v.InstanceVariables.Count); foreach (KeyValuePair <RubySymbol, object> item in v.InstanceVariables) { WriteObject(item.Key); WriteObject(item.Value); } } else if (obj is RubyObject) { WriteClass(RubyMarshal.Types.Object, obj, true); WriteObjectInstanceVariable((RubyObject)obj); } /* TODO: Data * case T_DATA: * { * VALUE v; * * if (!rb_respond_to(obj, s_dump_data)) { * rb_raise(rb_eTypeError, * "no _dump_data is defined for class %s", * rb_obj_classname(obj)); * } * v = rb_funcall(obj, s_dump_data, 0); * check_dump_arg(arg, s_dump_data); * w_class(TYPE_DATA, obj, arg, TRUE); * w_object(v, arg, limit); * } * break;*/ else { throw new InvalidDataException(string.Format("can't dump {0}", obj.GetType().FullName)); } if (hasiv) { WriteInstanceVariable(fobj, fobj.InstanceVariables); } } }