public override object Read(Reader reader, int tag)
        {
            if (tag >= '0' && tag <= '9')
            {
                return(digitObject[tag - '0']);
            }
            var stream = reader.Stream;

            switch (tag)
            {
            case TagInteger:
                return(ValueReader.ReadInt(stream));

            case TagString:
                return(ReferenceReader.ReadString(reader));

            case TagBytes:
                return(ReferenceReader.ReadBytes(reader));

            case TagTrue:
                return(trueObject);

            case TagFalse:
                return(falseObject);

            case TagEmpty:
                return("");

            case TagObject:
                return(Read(reader));

            case TagRef:
                return(reader.ReadReference());

            case TagDate:
                return(ReferenceReader.ReadDateTime(reader));

            case TagTime:
                return(ReferenceReader.ReadTime(reader));

            case TagGuid:
                return(ReferenceReader.ReadGuid(reader));

            case TagLong:
                switch (reader.LongType)
                {
                case LongType.Int64:
                    return(ValueReader.ReadLong(stream));

                case LongType.UInt64:
                    return((ulong)ValueReader.ReadLong(stream));

                default:
                    return(ValueReader.ReadBigInteger(stream));
                }

            case TagDouble:
                switch (reader.RealType)
                {
                case RealType.Single:
                    return(ValueReader.ReadSingle(stream));

                case RealType.Decimal:
                    return(ValueReader.ReadDecimal(stream));

                default:
                    return(ValueReader.ReadDouble(stream));
                }

            case TagNaN:
                switch (reader.RealType)
                {
                case RealType.Single:
                    return(float.NaN);

                default:
                    return(double.NaN);
                }

            case TagInfinity:
                switch (reader.RealType)
                {
                case RealType.Single:
                    return(ValueReader.ReadSingleInfinity(stream));

                default:
                    return(ValueReader.ReadInfinity(stream));
                }

            case TagUTF8Char:
                switch (reader.CharType)
                {
                case CharType.Char:
                    return(ValueReader.ReadChar(stream));

                default:
                    return(ValueReader.ReadUTF8Char(stream));
                }

            case TagList:
                switch (reader.ListType)
                {
                case ListType.Array:
                    return(ReferenceReader.ReadArray <object>(reader));

                case ListType.ArrayList:
                    return(ListDeserializer <ArrayList> .Read(reader));

                default:
                    return(CollectionDeserializer <List <object>, object> .Read(reader));
                }

            case TagMap:
                switch (reader.DictType)
                {
                case DictType.Dictionary:
                    return(DictionaryDeserializer <Dictionary <object, object>, object, object> .Read(reader));

                case DictType.ExpandoObject:
                    return(ExpandoObjectDeserializer.Read(reader));

                case DictType.Hashtable:
                    return(DictionaryDeserializer <Hashtable> .Read(reader));

                default:
                    return(DictionaryDeserializer <NullableKeyDictionary <object, object>, object, object> .Read(reader));
                }

            case TagError:
                return(new Exception(reader.Deserialize <string>()));

            default:
                return(base.Read(reader, tag));
            }
        }
        private static object DeserializeInternal(string name, Type type, object defaultvalue, IniDictionary ini, string groupName, bool rootObject, IniCollectionSettings collectionSettings)
        {
            string fullname = groupName;

            if (!rootObject)
            {
                if (!string.IsNullOrEmpty(fullname))
                {
                    fullname += '.';
                }
                fullname += name;
            }
            if (!ini.ContainsKey(groupName))
            {
                return(defaultvalue);
            }
            Dictionary <string, string> group = ini[groupName];

            if (!type.IsComplexType())
            {
                if (group.ContainsKey(name))
                {
                    object converted = type.ConvertFromString(group[name]);
                    group.Remove(name);
                    if (converted != null)
                    {
                        return(converted);
                    }
                }
                return(defaultvalue);
            }
            Type generictype;

            if (type.IsArray)
            {
                Type valuetype = type.GetElementType();
                int  maxind    = int.MinValue;
                if (!IsComplexType(valuetype))
                {
                    switch (collectionSettings.Mode)
                    {
                    case IniCollectionMode.Normal:
                        foreach (IniNameValue item in group)
                        {
                            if (item.Key.StartsWith(name + "[", StringComparison.Ordinal))
                            {
                                int key = int.Parse(item.Key.Substring(name.Length + 1, item.Key.Length - (name.Length + 2)));
                                maxind = Math.Max(key, maxind);
                            }
                        }
                        break;

                    case IniCollectionMode.IndexOnly:
                        foreach (IniNameValue item in group)
                        {
                            int key;
                            if (int.TryParse(item.Key, out key))
                            {
                                maxind = Math.Max(key, maxind);
                            }
                        }
                        break;

                    case IniCollectionMode.NoSquareBrackets:
                        foreach (IniNameValue item in group)
                        {
                            if (item.Key.StartsWith(name, StringComparison.Ordinal))
                            {
                                int key;
                                if (int.TryParse(item.Key.Substring(name.Length), out key))
                                {
                                    maxind = Math.Max(key, maxind);
                                }
                            }
                        }
                        break;

                    case IniCollectionMode.SingleLine:
                        string[] items = group[name].Split(new[] { collectionSettings.Format }, StringSplitOptions.None);
                        Array    _obj  = Array.CreateInstance(valuetype, items.Length);
                        for (int i = 0; i < items.Length; i++)
                        {
                            _obj.SetValue(valuetype.ConvertFromString(items[i]), i);
                        }
                        group.Remove(name);
                        break;
                    }
                }
                else
                {
                    switch (collectionSettings.Mode)
                    {
                    case IniCollectionMode.Normal:
                        foreach (IniNameGroup item in ini)
                        {
                            if (item.Key.StartsWith(fullname + "[", StringComparison.Ordinal))
                            {
                                int key = int.Parse(item.Key.Substring(fullname.Length + 1, item.Key.Length - (fullname.Length + 2)));
                                maxind = Math.Max(key, maxind);
                            }
                        }
                        break;

                    case IniCollectionMode.IndexOnly:
                        foreach (IniNameGroup item in ini)
                        {
                            int key;
                            if (int.TryParse(item.Key, out key))
                            {
                                maxind = Math.Max(key, maxind);
                            }
                        }
                        break;

                    case IniCollectionMode.NoSquareBrackets:
                        foreach (IniNameGroup item in ini)
                        {
                            if (item.Key.StartsWith(fullname, StringComparison.Ordinal))
                            {
                                int key = int.Parse(item.Key.Substring(fullname.Length));
                                maxind = Math.Max(key, maxind);
                            }
                        }
                        break;

                    case IniCollectionMode.SingleLine:
                        throw new InvalidOperationException("Cannot deserialize type " + valuetype + " with IniCollectionMode.SingleLine!");
                    }
                }
                if (maxind == int.MinValue)
                {
                    return(Array.CreateInstance(valuetype, 0));
                }
                int   length = maxind + 1 - (collectionSettings.Mode == IniCollectionMode.SingleLine ? 0 : collectionSettings.StartIndex);
                Array obj    = Array.CreateInstance(valuetype, length);
                if (!IsComplexType(valuetype))
                {
                    switch (collectionSettings.Mode)
                    {
                    case IniCollectionMode.Normal:
                        for (int i = 0; i < length; i++)
                        {
                            if (group.ContainsKey(name + "[" + (i + collectionSettings.StartIndex).ToString() + "]"))
                            {
                                obj.SetValue(valuetype.ConvertFromString(group[name + "[" + (i + collectionSettings.StartIndex).ToString() + "]"]), i);
                                group.Remove(name + "[" + (i + collectionSettings.StartIndex).ToString() + "]");
                            }
                            else
                            {
                                obj.SetValue(valuetype.GetDefaultValue(), i);
                            }
                        }
                        break;

                    case IniCollectionMode.IndexOnly:
                        for (int i = 0; i < length; i++)
                        {
                            if (group.ContainsKey((i + collectionSettings.StartIndex).ToString()))
                            {
                                obj.SetValue(valuetype.ConvertFromString(group[(i + collectionSettings.StartIndex).ToString()]), i);
                                group.Remove((i + collectionSettings.StartIndex).ToString());
                            }
                            else
                            {
                                obj.SetValue(valuetype.GetDefaultValue(), i);
                            }
                        }
                        break;

                    case IniCollectionMode.NoSquareBrackets:
                        for (int i = 0; i < length; i++)
                        {
                            if (group.ContainsKey(name + (i + collectionSettings.StartIndex).ToString()))
                            {
                                obj.SetValue(valuetype.ConvertFromString(group[name + (i + collectionSettings.StartIndex).ToString()]), i);
                                group.Remove(name + (i + collectionSettings.StartIndex).ToString());
                            }
                            else
                            {
                                obj.SetValue(valuetype.GetDefaultValue(), i);
                            }
                        }
                        break;
                    }
                }
                else
                {
                    switch (collectionSettings.Mode)
                    {
                    case IniCollectionMode.Normal:
                        for (int i = 0; i < length; i++)
                        {
                            obj.SetValue(DeserializeInternal("value", valuetype, valuetype.GetDefaultValue(), ini, fullname + "[" + (i + collectionSettings.StartIndex).ToString() + "]", true, defaultCollectionSettings), i);
                        }
                        break;

                    case IniCollectionMode.IndexOnly:
                        for (int i = 0; i < length; i++)
                        {
                            obj.SetValue(DeserializeInternal("value", valuetype, valuetype.GetDefaultValue(), ini, (i + collectionSettings.StartIndex).ToString(), true, defaultCollectionSettings), i);
                        }
                        break;

                    case IniCollectionMode.NoSquareBrackets:
                        for (int i = 0; i < length; i++)
                        {
                            obj.SetValue(DeserializeInternal("value", valuetype, valuetype.GetDefaultValue(), ini, fullname + (i + collectionSettings.StartIndex).ToString(), true, defaultCollectionSettings), i);
                        }
                        break;
                    }
                }
                return(obj);
            }
            if (ImplementsGenericDefinition(type, typeof(IList <>), out generictype))
            {
                object obj       = Activator.CreateInstance(type);
                Type   valuetype = generictype.GetGenericArguments()[0];
                CollectionDeserializer deserializer = (CollectionDeserializer)Activator.CreateInstance(typeof(ListDeserializer <>).MakeGenericType(valuetype));
                deserializer.Deserialize(obj, group, groupName, collectionSettings, name, ini, fullname);
                return(obj);
            }
            if (type.ImplementsGenericDefinition(typeof(IDictionary <,>), out generictype))
            {
                object obj       = Activator.CreateInstance(type);
                Type   keytype   = generictype.GetGenericArguments()[0];
                Type   valuetype = generictype.GetGenericArguments()[1];
                if (keytype.IsComplexType())
                {
                    return(obj);
                }
                CollectionDeserializer deserializer = (CollectionDeserializer)Activator.CreateInstance(typeof(DictionaryDeserializer <,>).MakeGenericType(keytype, valuetype));
                deserializer.Deserialize(obj, group, groupName, collectionSettings, name, ini, fullname);
                return(obj);
            }
            object     result     = Activator.CreateInstance(type);
            MemberInfo collection = null;

            foreach (MemberInfo member in type.GetMembers(BindingFlags.Public | BindingFlags.Instance))
            {
                if (Attribute.GetCustomAttribute(member, typeof(IniIgnoreAttribute), true) != null)
                {
                    continue;
                }
                string membername = member.Name;
                if (Attribute.GetCustomAttribute(member, typeof(IniNameAttribute), true) != null)
                {
                    membername = ((IniNameAttribute)Attribute.GetCustomAttribute(member, typeof(IniNameAttribute), true)).Name;
                }
                IniCollectionSettings  colset  = defaultCollectionSettings;
                IniCollectionAttribute colattr = (IniCollectionAttribute)Attribute.GetCustomAttribute(member, typeof(IniCollectionAttribute), true);
                if (colattr != null)
                {
                    colset = colattr.Settings;
                }
                switch (member.MemberType)
                {
                case MemberTypes.Field:
                    FieldInfo field = (FieldInfo)member;
                    if (colset.Mode == IniCollectionMode.IndexOnly && typeof(ICollection).IsAssignableFrom(field.FieldType))
                    {
                        if (collection != null)
                        {
                            throw new Exception("IniCollectionMode.IndexOnly cannot be used on multiple members of a Type.");
                        }
                        collection = member;
                        continue;
                    }
                    object defval = field.FieldType.GetDefaultValue();
                    DefaultValueAttribute defattr = (DefaultValueAttribute)Attribute.GetCustomAttribute(member, typeof(DefaultValueAttribute), true);
                    if (defattr != null)
                    {
                        defval = defattr.Value;
                    }
                    field.SetValue(result, DeserializeInternal(membername, field.FieldType, defval, ini, fullname, false, colset));
                    break;

                case MemberTypes.Property:
                    PropertyInfo property = (PropertyInfo)member;
                    if (property.GetIndexParameters().Length > 0)
                    {
                        continue;
                    }
                    if (colset.Mode == IniCollectionMode.IndexOnly && typeof(ICollection).IsAssignableFrom(property.PropertyType))
                    {
                        if (collection != null)
                        {
                            throw new Exception("IniCollectionMode.IndexOnly cannot be used on multiple members of a Type.");
                        }
                        collection = member;
                        continue;
                    }
                    defval  = property.PropertyType.GetDefaultValue();
                    defattr = (DefaultValueAttribute)Attribute.GetCustomAttribute(member, typeof(DefaultValueAttribute), true);
                    if (defattr != null)
                    {
                        defval = defattr.Value;
                    }
                    object     propval   = DeserializeInternal(membername, property.PropertyType, defval, ini, fullname, false, colset);
                    MethodInfo setmethod = property.GetSetMethod();
                    if (setmethod == null)
                    {
                        continue;
                    }
                    setmethod.Invoke(result, new object[] { propval });
                    break;
                }
            }
            if (collection != null)
            {
                switch (collection.MemberType)
                {
                case MemberTypes.Field:
                    FieldInfo field = (FieldInfo)collection;
                    field.SetValue(result, DeserializeInternal(collection.Name, field.FieldType, field.FieldType.GetDefaultValue(), ini, fullname, false, ((IniCollectionAttribute)Attribute.GetCustomAttribute(collection, typeof(IniCollectionAttribute), true)).Settings));
                    break;

                case MemberTypes.Property:
                    PropertyInfo property  = (PropertyInfo)collection;
                    object       propval   = DeserializeInternal(collection.Name, property.PropertyType, property.PropertyType.GetDefaultValue(), ini, fullname, false, ((IniCollectionAttribute)Attribute.GetCustomAttribute(collection, typeof(IniCollectionAttribute), true)).Settings);
                    MethodInfo   setmethod = property.GetSetMethod();
                    if (setmethod == null)
                    {
                        break;
                    }
                    setmethod.Invoke(result, new object[] { propval });
                    break;
                }
            }
            ini.Remove(rootObject ? string.Empty : name);
            return(result);
        }
Example #3
0
        private static object DeserializeInternal(string name, Type type, object defaultvalue, Dictionary <string, Dictionary <string, string> > ini, string groupName, bool rootObject, bool usecollectionname)
        {
            string fullname = groupName;

            if (!rootObject)
            {
                if (!string.IsNullOrEmpty(fullname))
                {
                    fullname += '.';
                }
                fullname += name;
            }
            if (!ini.ContainsKey(groupName))
            {
                return(defaultvalue);
            }
            Dictionary <string, string> group = ini[groupName];

            if (!type.IsComplexType())
            {
                if (group.ContainsKey(name))
                {
                    object converted = type.ConvertFromString(group[name]);
                    group.Remove(name);
                    if (converted != null)
                    {
                        return(converted);
                    }
                }
                return(defaultvalue);
            }
            if (type.IsArray)
            {
                Type valuetype = type.GetElementType();
                int  maxind    = -1;
                if (!IsComplexType(valuetype))
                {
                    foreach (KeyValuePair <string, string> item in group)
                    {
                        if (!usecollectionname)
                        {
                            if (int.TryParse(item.Key, out int key))
                            {
                                maxind = Math.Max(key, maxind);
                            }
                        }
                        else if (item.Key.StartsWith(name + "["))
                        {
                            int key = int.Parse(item.Key.Substring(name.Length + 1, item.Key.Length - (name.Length + 2)));
                            maxind = Math.Max(key, maxind);
                        }
                    }
                }
                else
                {
                    foreach (KeyValuePair <string, Dictionary <string, string> > item in ini)
                    {
                        if (!usecollectionname)
                        {
                            if (int.TryParse(item.Key, out int key))
                            {
                                maxind = Math.Max(key, maxind);
                            }
                        }
                        else if (item.Key.StartsWith(fullname + "["))
                        {
                            int key = int.Parse(item.Key.Substring(fullname.Length + 1, item.Key.Length - (fullname.Length + 2)));
                            maxind = Math.Max(key, maxind);
                        }
                    }
                }
                maxind++;
                Array obj = Array.CreateInstance(valuetype, maxind);
                if (!IsComplexType(valuetype))
                {
                    for (int i = 0; i < maxind; i++)
                    {
                        if (group.ContainsKey(usecollectionname ? name + "[" + i + "]" : i.ToString()))
                        {
                            obj.SetValue(ConvertFromString(valuetype, group[usecollectionname ? name + "[" + i + "]" : i.ToString()]), i);
                            group.Remove(usecollectionname ? name + "[" + i + "]" : i.ToString());
                        }
                        else
                        {
                            obj.SetValue(valuetype.GetDefaultValue(), i);
                        }
                    }
                }
                else
                {
                    for (int i = 0; i < maxind; i++)
                    {
                        obj.SetValue(DeserializeInternal("value", valuetype, valuetype.GetDefaultValue(), ini, usecollectionname ? fullname + "[" + i + "]" : i.ToString(), true, true), i);
                    }
                }
                return(obj);
            }
            if (ImplementsGenericDefinition(type, typeof(IList <>), out Type generictype))
            {
                object obj       = Activator.CreateInstance(type);
                Type   valuetype = generictype.GetGenericArguments()[0];
                CollectionDeserializer deserializer = (CollectionDeserializer)Activator.CreateInstance(typeof(ListDeserializer <>).MakeGenericType(valuetype));
                deserializer.Deserialize(obj, group, groupName, usecollectionname, name, ini, fullname);
                return(obj);
            }
            if (type.ImplementsGenericDefinition(typeof(IDictionary <,>), out generictype))
            {
                object obj       = Activator.CreateInstance(type);
                Type   keytype   = generictype.GetGenericArguments()[0];
                Type   valuetype = generictype.GetGenericArguments()[1];
                if (keytype.IsComplexType())
                {
                    return(obj);
                }
                CollectionDeserializer deserializer = (CollectionDeserializer)Activator.CreateInstance(typeof(DictionaryDeserializer <,>).MakeGenericType(keytype, valuetype));
                deserializer.Deserialize(obj, group, groupName, usecollectionname, name, ini, fullname);
                return(obj);
            }
            object     result     = Activator.CreateInstance(type);
            MemberInfo collection = null;

            foreach (MemberInfo member in type.GetMembers(BindingFlags.Public | BindingFlags.Instance))
            {
                if (Attribute.GetCustomAttribute(member, typeof(IniIgnoreAttribute), true) != null)
                {
                    continue;
                }
                string membername = member.Name;
                if (Attribute.GetCustomAttribute(member, typeof(IniNameAttribute), true) != null)
                {
                    membername = ((IniNameAttribute)Attribute.GetCustomAttribute(member, typeof(IniNameAttribute), true)).Name;
                }
                bool collectionattr = Attribute.GetCustomAttribute(member, typeof(IniCollectionAttribute), true) != null;
                switch (member.MemberType)
                {
                case MemberTypes.Field:
                    FieldInfo field = (FieldInfo)member;
                    if (collectionattr && typeof(ICollection).IsAssignableFrom(field.FieldType))
                    {
                        if (collection != null)
                        {
                            throw new Exception("IniCollectionAttribute cannot be used on multiple members of a Type.");
                        }
                        collection = member;
                        continue;
                    }
                    object defval = field.FieldType.GetDefaultValue();
                    DefaultValueAttribute defattr = (DefaultValueAttribute)Attribute.GetCustomAttribute(member, typeof(DefaultValueAttribute), true);
                    if (defattr != null)
                    {
                        defval = defattr.Value;
                    }
                    field.SetValue(result, DeserializeInternal(membername, field.FieldType, defval, ini, fullname, false, true));
                    break;

                case MemberTypes.Property:
                    PropertyInfo property = (PropertyInfo)member;
                    if (property.GetIndexParameters().Length > 0)
                    {
                        continue;
                    }
                    if (collectionattr && typeof(ICollection).IsAssignableFrom(property.PropertyType))
                    {
                        if (collection != null)
                        {
                            throw new Exception("IniCollectionAttribute cannot be used on multiple members of a Type.");
                        }
                        collection = member;
                        continue;
                    }
                    defval  = property.PropertyType.GetDefaultValue();
                    defattr = (DefaultValueAttribute)Attribute.GetCustomAttribute(member, typeof(DefaultValueAttribute), true);
                    if (defattr != null)
                    {
                        defval = defattr.Value;
                    }
                    object     propval   = DeserializeInternal(membername, property.PropertyType, defval, ini, fullname, false, true);
                    MethodInfo setmethod = property.GetSetMethod();
                    if (setmethod == null)
                    {
                        continue;
                    }
                    setmethod.Invoke(result, new object[] { propval });
                    break;
                }
            }
            if (collection != null)
            {
                switch (collection.MemberType)
                {
                case MemberTypes.Field:
                    FieldInfo field = (FieldInfo)collection;
                    field.SetValue(result, DeserializeInternal(collection.Name, field.FieldType, field.FieldType.GetDefaultValue(), ini, fullname, false, false));
                    break;

                case MemberTypes.Property:
                    PropertyInfo property  = (PropertyInfo)collection;
                    object       propval   = DeserializeInternal(collection.Name, property.PropertyType, property.PropertyType.GetDefaultValue(), ini, fullname, false, false);
                    MethodInfo   setmethod = property.GetSetMethod();
                    if (setmethod == null)
                    {
                        break;
                    }
                    setmethod.Invoke(result, new object[] { propval });
                    break;
                }
            }
            ini.Remove(rootObject ? string.Empty : name);
            return(result);
        }