Esempio n. 1
0
        private static object DeserializeObjectWithProperties(TextReader r, Type type, ObjectGraphContext context, StringBuilder log)
        {
            // create object and add it to our context
            var o = type.Instantiate();

            context.Add(o);

            // properties count - need to create object and populate properties
            int    count;
            string s = r.ReadTo(':', log);

            if (!int.TryParse(s, out count))
            {
                throw new SerializationException("Expected integer, got \"" + s + "\" when parsing property count.");
            }


            var dict = new SafeDictionary <string, object>();

            // deserialize the properties
            var props = ObjectGraphContext.GetKnownProperties(type, true);

            for (int i = 0; i < count; i++)
            {
                var pname = r.ReadTo(':', log).Trim();
                if (type == typeof(Game.Objects.Civilization.Empire) && pname == "StoredResources")
                {
                }
                if (props.ContainsKey(pname))
                {
                    // TODO - get base class recursively, not just derived class and declaring type
                    var prop = type.GetProperty(pname, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) ?? props[pname];                     // get concrete type property in case it has DoNotSerialize and the abstract type doesn't
                    if (prop != null)
                    {
                        if (prop.Name == "StarSystemNames")
                        {
                        }
                        var data = Deserialize(r, prop.PropertyType, false, context, log);
                        if (prop.HasAttribute <SerializationPriorityAttribute>())
                        {
                            prop.SetValue(o, data);                             // TODO - use cached reflection lambdas
                        }
                        if (!prop.HasAttribute <DoNotSerializeAttribute>())
                        {
                            dict[pname] = data;
                        }
                    }
                    else
                    {
                        r.ReadToEndOfLine(';', log);                         // throw away this property, we don't need it
                    }
                    // if p is null or has do not serialize attribute, it must be data from an old version with different property names, so don't crash
                }
            }

            //propertySetterTasks.Add(Task.Factory.StartNew(() =>
            //{
            o.SetData(dict, context);
            //}));

            // clean up
            ReadSemicolon(r, type, log);

            return(o);
        }
Esempio n. 2
0
        private static object DeserializeStringifiedObject(TextReader r, Type type, ObjectGraphContext context, StringBuilder log)
        {
            object o;
            // read tag to see if it's actually a stringified object
            var fin = r.Read();

            while (fin != 0 && char.IsWhiteSpace((char)fin))
            {
                if (log != null)
                {
                    log.Append((char)fin);
                }
                fin = r.Read();
            }
            if (fin != 0 && log != null)
            {
                log.Append((char)fin);
            }
            if (fin == 's')
            {
                IStringifier stringifier = null;
                var          t           = type;
                while (stringifier == null && t != null)
                {
                    stringifier = StringifierLibrary.Instance.All.SingleOrDefault(x => x.SupportedType == t);
                    t           = t.BaseType;
                }
                if (stringifier == null)
                {
                    throw new Exception("Can't find stringifier to deserialize " + type);
                }
                var dummy = r.ReadTo(':', log);
                var val   = r.ReadToEndOfLine(';', log);
                o = stringifier.Destringify(val);
            }
            else if (fin == 'p')
            {
                o = DeserializeObjectWithProperties(r, type, context, log);
            }
            else if (fin == 'i')
            {
                o = DeserializeObjectWithID(r, type, context, log);
            }
            else if (fin == 'n')
            {
                // null object!
                o = null;

                // clean up
                ReadSemicolon(r, type, log);
            }
            else if (fin == 'd')
            {
                o = DeserializeDictionary(r, type, context, log);
            }
            else if (fin == 'c')
            {
                o = DeserializeList(r, type, context, log);
            }
            else
            {
                throw new Exception("Unknown data tag " + fin + ", was expecting s/p/i/n/d/c.");
            }
            if (!context.KnownObjects.ContainsKey(type) || !context.KnownObjects[type].Contains(o))
            {
                context.Add(o);
            }
            return(o);
        }
Esempio n. 3
0
        private static IEnumerable DeserializeDictionary(TextReader r, Type type, ObjectGraphContext context, StringBuilder log)
        {
            IEnumerable o;
            int         size;
            var         sizeStr = r.ReadTo(':', log);

            if (!int.TryParse(sizeStr, out size))
            {
                throw new SerializationException("Expected integer, got \"" + sizeStr + "\" when parsing collection size.");
            }
            var coll = type.Instantiate();

            context.Add(coll);
            var  adder = type.GetMethods().Single(m => m.Name == "Add" && m.GetParameters().Length == 2);
            Type itemType;

            if (type.GetGenericArguments().Count() == 2)
            {
                itemType = typeof(KeyValuePair <,>).MakeGenericType(type.GetGenericArguments());
            }
            else if (type == typeof(DynamicDictionary))
            {
                itemType = typeof(KeyValuePair <object, object>);
            }
            else
            {
                // HACK - Resources inherits from a dictionary type
                itemType = typeof(KeyValuePair <,>).MakeGenericType(type.BaseType.GetGenericArguments());
            }

            var      collParm = Expression.Parameter(typeof(object), "coll");
            var      keyParm  = Expression.Parameter(typeof(object), "key");
            var      valParm  = Expression.Parameter(typeof(object), "val");
            var      keyprop  = ObjectGraphContext.GetKnownProperties(itemType, true)["Key"];
            var      valprop  = ObjectGraphContext.GetKnownProperties(itemType, true)["Value"];
            Delegate lambdaAdder;

            if (ObjectGraphContext.CollectionAdders[type] == null)
            {
                // lambda has not been created yet, so create it
                ObjectGraphContext.CollectionAdders[type] =
                    Expression.Lambda(Expression.Call(
                                          Expression.Convert(collParm, type),
                                          adder,
                                          Expression.Convert(keyParm, keyprop.PropertyType),
                                          Expression.Convert(valParm, valprop.PropertyType)
                                          ), collParm, keyParm, valParm).Compile();
            }

            // get lambda
            lambdaAdder = ObjectGraphContext.CollectionAdders[type];

            // load items and add them
            for (int i = 0; i < size; i++)
            {
                var key = Deserialize(r, keyprop.PropertyType, false, context, log);
                var val = Deserialize(r, valprop.PropertyType, false, context, log);
                lambdaAdder.DynamicInvoke(coll, key, val);
            }

            o = (IEnumerable)coll;

            // clean up
            ReadSemicolon(r, type, log);

            return(o);
        }
Esempio n. 4
0
        private static IEnumerable DeserializeList(TextReader r, Type type, ObjectGraphContext context, StringBuilder log)
        {
            IEnumerable o;
            int         size;
            var         sizeStr = r.ReadTo(':', log);

            if (!int.TryParse(sizeStr, out size))
            {
                throw new SerializationException("Expected integer, got \"" + sizeStr + "\" when parsing collection size.");
            }
            var coll = Activator.CreateInstance(type);

            context.Add(coll);
            var  adder = type.GetMethods().Single(m => m.Name == "Add" && m.GetParameters().Length == 1);
            Type itemType;

            if (typeof(DynamicDictionary).IsAssignableFrom(type))
            {
                itemType = typeof(KeyValuePair <object, object>);
            }
            else if (type.GetGenericArguments().Length == 2)
            {
                // HACK - assume it's a dictionary, no real way to test
                itemType = typeof(KeyValuePair <,>).MakeGenericType(type.GetGenericArguments());
            }
            else if (type.GetGenericArguments().Length == 1)
            {
                // HACK - assume it's a collection, no real way to test
                itemType = type.GetGenericArguments()[0];
            }
            else
            {
                // no generic type? probably a list of objects?
                itemType = typeof(object);
            }
            var      collParm = Expression.Parameter(type, "coll");
            var      objParm  = Expression.Parameter(itemType, "obj");
            Delegate lambdaAdder;

            if (ObjectGraphContext.CollectionAdders[type] == null)
            {
                // lambda has not been created yet, so create it
                try
                {
                    ObjectGraphContext.CollectionAdders[type] =
                        Expression.Lambda(Expression.Call(
                                              collParm,        // the collection to add to
                                              adder,           // the add method to call
                                              objParm),        // the object to add
                                          collParm, objParm).Compile();
                }
                catch (Exception ex)
                {
                    throw new SerializationException("Could not create lambda to add {0} items to {1}.".F(itemType, type), ex);
                }
            }

            // get lambda
            lambdaAdder = ObjectGraphContext.CollectionAdders[type];

            // load items and add them
            for (int i = 0; i < size; i++)
            {
                var item = Deserialize(r, itemType, false, context, log);
                lambdaAdder.DynamicInvoke(coll, item);
            }
            o = (IEnumerable)coll;

            // clean up
            ReadSemicolon(r, type, log);

            return(o);
        }
Esempio n. 5
0
        private static Array DeserializeArray(TextReader r, Type type, ObjectGraphContext context, StringBuilder log)
        {
            // arrays
            Array o;
            // read bounds or id number
            var fin = r.Read();

            while (fin != 0 && char.IsWhiteSpace((char)fin))
            {
                if (log != null)
                {
                    log.Append((char)fin);
                }
                fin = r.Read();
            }
            if (fin != 0 && log != null)
            {
                log.Append((char)fin);
            }
            if (fin == 'a')
            {
                var boundsStrs = r.ReadTo(':', log).Split(',');
                if (boundsStrs.Length < 1)
                {
                    throw new SerializationException("Arrays cannot have zero dimensions.");
                }

                if (boundsStrs.Length == 1)
                {
                    int min, max;
                    var bounds1Strs = boundsStrs[0].Split('_');
                    if (!int.TryParse(bounds1Strs[0], out min))
                    {
                        throw new SerializationException("Expected integer, got \"" + bounds1Strs[0] + "\" when parsing array bounds.");
                    }
                    if (!int.TryParse(bounds1Strs[1], out max))
                    {
                        throw new SerializationException("Expected integer, got \"" + bounds1Strs[1] + "\" when parsing array bounds.");
                    }
                    // HACK - figure out how to set min and max bounds, in case it matters (VB?)
                    var array = Array.CreateInstance(type.GetElementType(), max - min + 1);
                    for (int i = min; i <= max; i++)
                    {
                        array.SetValue(Deserialize(r, type.GetElementType(), false, context, log), i);
                    }
                    o = array;
                }
                else if (boundsStrs.Length == 2)
                {
                    int min1, max1, min2, max2;
                    var bounds1Strs = boundsStrs[0].Split('_');
                    var bounds2Strs = boundsStrs[1].Split('_');
                    if (!int.TryParse(bounds1Strs[0], out min1))
                    {
                        throw new SerializationException("Expected integer, got \"" + bounds1Strs[0] + "\" when parsing array bounds.");
                    }
                    if (!int.TryParse(bounds1Strs[1], out max1))
                    {
                        throw new SerializationException("Expected integer, got \"" + bounds1Strs[1] + "\" when parsing array bounds.");
                    }
                    if (!int.TryParse(bounds2Strs[0], out min2))
                    {
                        throw new SerializationException("Expected integer, got \"" + bounds2Strs[0] + "\" when parsing array bounds.");
                    }
                    if (!int.TryParse(bounds2Strs[1], out max2))
                    {
                        throw new SerializationException("Expected integer, got \"" + bounds2Strs[1] + "\" when parsing array bounds.");
                    }
                    // HACK - figure out how to set min and max bounds, in case it matters (VB?)
                    var array = Array.CreateInstance(type.GetElementType(), max1 - min1 + 1, max2 - min2 + 1);
                    for (int x = min1; x <= max1; x++)
                    {
                        for (int y = min2; y <= max2; y++)
                        {
                            array.SetValue(Deserialize(r, type.GetElementType(), false, context, log), x, y);
                        }
                    }
                    o = array;
                    context.Add(o);
                }
                else
                {
                    throw new SerializationException("Arrays with more than two dimensions are not supported.");
                }

                // clean up
                ReadSemicolon(r, type, log);
            }
            else if (fin == 'i')
            {
                // ID - need to find known object
                int    id;
                string s = r.ReadToEndOfLine(';', log);
                if (!int.TryParse(s, out id))
                {
                    throw new SerializationException("Expected integer, got \"" + s + "\" when parsing object ID.");
                }

                // do we have it?
                if (!context.KnownObjects.ContainsKey(type) || context.KnownObjects[type].Count <= id)
                {
                    throw new SerializationException("No known object of type " + type + " has an ID of " + id + ".");
                }

                // found it!
                o = (Array)context.KnownObjects[type][id];
            }
            else if (fin == 'n')
            {
                // null object!
                o = null;

                // clean up
                ReadSemicolon(r, type, log);
            }
            else
            {
                throw new SerializationException("Expected 'a'/'i'/'n', got '" + (char)fin + "' when parsing " + type + ".");
            }
            return(o);
        }