Ejemplo n.º 1
0
        /// <summary>
        /// static VALUE r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
        /// </summary>
        /// <param name="hasivp"></param>
        /// <param name="ivp"></param>
        /// <param name="extmod"></param>
        /// <returns></returns>
        public object ReadObject0(bool hasivp, ref bool ivp, List <FuzzyModule> extmod)
        {
            object v    = null;
            int    type = ReadByte();
            int    id;
            object link;

            switch (type)
            {
            case RubyMarshal.Types.Link:
                id = ReadLong();
                if (!this.m_objects.TryGetValue(id, out link))
                {
                    throw new InvalidDataException("dump format error (unlinked)");
                }
                v = link;
                if (this.m_proc != null)
                {
                    v = this.m_proc(v);
                }
                break;

            case RubyMarshal.Types.InstanceVariable:
            {
                bool ivar = true;
                v = ReadObject0(ref ivar, extmod);
                bool hasenc = false;
                if (ivar)
                {
                    ReadInstanceVariable(v, ref hasenc);
                }
            }
            break;

            case RubyMarshal.Types.Extended:
            {
                FuzzyModule m = FuzzyModule.GetModule(ReadUnique());
                if (extmod == null)
                {
                    extmod = new List <FuzzyModule>();
                }
                extmod.Add(m);
                v = ReadObject0(extmod);
                FuzzyObject fobj = v as FuzzyObject;
                if (fobj != null)
                {
                    fobj.ExtendModules.AddRange(extmod);
                }
            }
            break;

            case RubyMarshal.Types.UserClass:
            {
                FuzzyClass c = FuzzyClass.GetClass(ReadUnique());

                v = ReadObject0(extmod);
                if (v is FuzzyObject)
                {
                    (v as FuzzyObject).ClassName = c.Symbol;
                }
            }
            break;

            case RubyMarshal.Types.Nil:
                v = FuzzyNil.Instance;
                v = Leave(v);
                break;

            case RubyMarshal.Types.True:
                v = FuzzyBool.True;
                v = Leave(v);
                break;

            case RubyMarshal.Types.False:
                v = FuzzyBool.False;
                v = Leave(v);
                break;

            case RubyMarshal.Types.Fixnum:
                v = ReadLong();
                v = new FuzzyFixnum(Convert.ToInt64(v));
                v = Leave(v);
                break;

            case RubyMarshal.Types.Float:
            {
                double      d;
                FuzzyString fstr = ReadString();
                string      str  = fstr.Text;

                if (str == "inf")
                {
                    d = double.PositiveInfinity;
                }
                else if (str == "-inf")
                {
                    d = double.NegativeInfinity;
                }
                else if (str == "nan")
                {
                    d = double.NaN;
                }
                else
                {
                    if (str.Contains("\0"))
                    {
                        str = str.Remove(str.IndexOf("\0"));
                    }
                    d = Convert.ToDouble(str);
                }
                v = new FuzzyFloat(d);
                v = Entry(v);
                v = Leave(v);
            }
            break;

            case RubyMarshal.Types.Bignum:
            {
                int sign = 0;
                switch (ReadByte())
                {
                case 0x2b:
                    sign = 1;
                    break;

                case 0x2d:
                    sign = -1;
                    break;

                default:
                    sign = 0;
                    break;
                }
                int    num3  = ReadLong();
                int    index = num3 / 2;
                int    num5  = (num3 + 1) / 2;
                uint[] data  = new uint[num5];
                for (int i = 0; i < index; i++)
                {
                    data[i] = m_reader.ReadUInt32();
                }
                if (index != num5)
                {
                    data[index] = m_reader.ReadUInt16();
                }
                v = new FuzzyBignum(sign, data);
                v = new FuzzyBignumAdapter(v as FuzzyBignum);
                v = Entry(v);
                v = Leave(v);
            }
            break;

            case RubyMarshal.Types.String:
                v = Entry(ReadString());
                v = Leave(v);
                break;

            case RubyMarshal.Types.Regexp:
            {
                FuzzyString str          = ReadString();
                int         options      = ReadByte();
                bool        has_encoding = false;
                int         idx          = Prepare();
                if (hasivp)
                {
                    ReadInstanceVariable(str, ref has_encoding);
                    ivp = false;
                }
                if (!has_encoding)
                {
                    // TODO: 1.8 compatibility; remove escapes undefined in 1.8

                    /*
                     * char *ptr = RSTRING_PTR(str), *dst = ptr, *src = ptr;
                     * long len = RSTRING_LEN(str);
                     * long bs = 0;
                     * for (; len-- > 0; *dst++ = *src++) {
                     *  switch (*src) {
                     *      case '\\': bs++; break;
                     *      case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
                     *      case 'm': case 'o': case 'p': case 'q': case 'u': case 'y':
                     *      case 'E': case 'F': case 'H': case 'I': case 'J': case 'K':
                     *      case 'L': case 'N': case 'O': case 'P': case 'Q': case 'R':
                     *      case 'S': case 'T': case 'U': case 'V': case 'X': case 'Y':
                     *      if (bs & 1) --dst;
                     *      default: bs = 0; break;
                     *  }
                     * }
                     * rb_str_set_len(str, dst - ptr);
                     */
                }
                v = Entry0(new FuzzyRegexp(str, (FuzzyRegexpOptions)options), idx);
                v = Leave(v);
            }
            break;

            case RubyMarshal.Types.Array:
            {
                int        len = ReadLong();
                FuzzyArray ary = new FuzzyArray();
                v = ary;
                v = Entry(v);
                while (len-- > 0)
                {
                    ary.Push(ReadObject());
                }
                v = Leave(v);
            }
            break;

            case RubyMarshal.Types.Hash:
            case RubyMarshal.Types.HashWithDefault:
            {
                int       len  = ReadLong();
                FuzzyHash hash = new FuzzyHash();
                v = hash;
                v = Entry(v);
                while (len-- > 0)
                {
                    object key   = ReadObject();
                    object value = ReadObject();
                    hash.Add(key, value);
                }
                if (type == RubyMarshal.Types.HashWithDefault)
                {
                    hash.DefaultValue = ReadObject();
                }
                v = Leave(v);
            }
            break;

            case RubyMarshal.Types.Struct:
            {
                int         idx   = Prepare();
                FuzzyStruct obj   = new FuzzyStruct();
                FuzzySymbol klass = ReadUnique();
                obj.ClassName = klass;
                int len = ReadLong();
                v = obj;
                v = Entry0(v, idx);
                while (len-- > 0)
                {
                    FuzzySymbol key   = ReadSymbol();
                    object      value = ReadObject();
                    obj.InstanceVariable[key] = value;
                }
                v = Leave(v);
            }
            break;

            case RubyMarshal.Types.UserDefined:
            {
                FuzzySymbol klass  = ReadUnique();
                var         factor = Factory <byte[]> .Factor(klass.Name);

                if (factor == null)
                {
                    FuzzyString data = ReadString();
                    if (hasivp)
                    {
                        ReadInstanceVariable(data);
                        ivp = false;
                    }

                    FuzzyUserdefinedDumpObject obj = new FuzzyUserdefinedDumpObject();
                    obj.ClassName    = klass;
                    obj.DumpedObject = data.Raw;
                    v = obj;
                    v = Entry(v);
                    v = Leave(v);
                }
                else
                {
                    object obj = factor._dump(m_stream, null);
                    v = obj;
                    v = Entry(v);
                    v = Leave(v);
                }
            }
            break;

            case RubyMarshal.Types.UserMarshal:
            {
                FuzzySymbol klass = ReadUnique();
                FuzzyUserdefinedMarshalDumpObject obj = new FuzzyUserdefinedMarshalDumpObject();
                v = obj;
                if (extmod != null)
                {
                    AppendExtendedModule(obj, extmod);
                }
                v = Entry(v);
                object data = ReadObject();
                obj.ClassName    = klass;
                obj.DumpedObject = data;
                v = Leave(v);
                if (extmod != null)
                {
                    extmod.Clear();
                }
            }
            break;

            case RubyMarshal.Types.Object:
            {
                int         idx   = Prepare();
                FuzzyObject obj   = new FuzzyObject();
                FuzzySymbol klass = ReadUnique();
                obj.ClassName = klass;
                v             = obj;
                v             = Entry0(v, idx);
                ReadInstanceVariable(v);
                v = Leave(v);
            }
            break;

            case RubyMarshal.Types.Class:
            {
                FuzzyString str = ReadString();
                v = FuzzyClass.GetClass(FuzzySymbol.GetSymbol(str));
                v = Entry(v);
                v = Leave(v);
            }
            break;

            case RubyMarshal.Types.Module:
            {
                FuzzyString str = ReadString();
                v = FuzzyModule.GetModule(FuzzySymbol.GetSymbol(str));
                v = Entry(v);
                v = Leave(v);
            }
            break;

            case RubyMarshal.Types.Symbol:
                if (hasivp)
                {
                    v   = ReadSymbolReal(ivp);
                    ivp = false;
                }
                else
                {
                    v = ReadSymbolReal(false);
                }
                v = Leave(v);
                break;

            case RubyMarshal.Types.SymbolLink:
                v = ReadSymbolLink();
                break;

            case RubyMarshal.Types.Data:
            /*  TODO: Data Support
             *  {
             *      VALUE klass = path2class(r_unique(arg));
             *      VALUE oldclass = 0;
             *
             *      v = obj_alloc_by_klass(klass, arg, &oldclass);
             *      if (!RB_TYPE_P(v, T_DATA)) {
             *          rb_raise(rb_eArgError, "dump format error");
             *      }
             *      v = r_entry(v, arg);
             *      if (!rb_respond_to(v, s_load_data)) {
             *          rb_raise(rb_eTypeError, "class %s needs to have instance method `_load_data'", rb_class2name(klass));
             *      }
             *      rb_funcall(v, s_load_data, 1, r_object0(arg, 0, extmod));
             *      check_load_arg(arg, s_load_data);
             *      v = r_leave(v, arg);
             *  }
             */
            case RubyMarshal.Types.ModuleOld:
            /*
             *  TODO: ModuleOld Support
             *  {
             *      volatile VALUE str = r_bytes(arg);
             *      v = rb_path_to_class(str);
             *      v = r_entry(v, arg);
             *      v = r_leave(v, arg);
             *  }
             */
            default:
                throw new InvalidDataException(string.Format("dump format error(0x{0:X2})", type));
            }
            return(v);
        }