Example #1
0
        public static void WriteTypeMetaInfo(IStreamWriter writer, CollectionItems collection)
        {
            writer.WriteUInt8(ValueItem.TypeMetaInfo);
            writer.WriteUInt8(CollectionTypeDescr);

            Type type = collection.RuntimeType;

            writer.WriteString(type.Assembly.GetName().Name);

            writer.WriteString(type.FullName);

            //writer.WriteBool(collection.IsArray);

            //if (collection.IsArray)
            //{

            //}
        }
Example #2
0
        internal static IValueItem ReadTypeMetaInfo(IStreamReader reader, uint typeId, ISerializeContext ctx)
        {
            byte metaTypeVersion = reader.ReadUInt8();

            string assemblyName;
            string typeFullName;
            Type   type;

            if (metaTypeVersion == SingleTypeDescr)
            {
                assemblyName = reader.ReadString();
                typeFullName = reader.ReadString();

                if (!TypeService.TryGetTypeByName(typeFullName, out type, ctx.Serializer.CustomLookupAssemblies))
                {
                    if (ctx.Serializer.AutoCreateMissingTypes)
                    {
                        return(AutoCreateMissingDeserializeType(typeId, assemblyName, typeFullName, reader, ctx));
                    }
                    else
                    {
                        throw new TypeAccessException($"Type {typeFullName} not found!");
                    }
                }

                IValueItem resultItem = ctx.GetByType(type);

                if (resultItem is ITypeStructure)
                {
                    ITypeStructure result = (ITypeStructure)resultItem;

                    short itemCount = reader.ReadInt16();

                    if (result.TypeId == typeId)
                    {
                        // internal type is equal remote type
                        for (int i = 0; i < itemCount; i++)
                        {
                            SkipPropertyMetaInfo(reader);
                        }

                        return(result);
                    }
                    else
                    {
                        // differences between local type and remote type

                        // read actual structure and try map to old/new structure
                        ComplexStructure tolerantLayoutStructure = ComplexStructure.CreateTolerantLayoutStructure(type, ctx);

                        for (int i = 0; i < itemCount; i++)
                        {
                            ItemType itemType       = (ItemType)reader.ReadInt16(); // ItemType Enum
                            uint     propertyTypeId = reader.ReadUInt32();          // TypeId (Type Hash)
                            string   propertyName   = reader.ReadString();          // Property Name
                            bool     isNullable     = reader.ReadBool();            // Nullable Flag

                            IValueItem nameMatchingItem = result.Items.Where(item => item.Name == propertyName).FirstOrDefault();

                            if (nameMatchingItem != null)
                            {
                                bool typeMatch       = itemType == nameMatchingItem.Type;
                                bool typeIdMatch     = propertyTypeId == nameMatchingItem.TypeId;
                                bool nullableMatch   = isNullable == nameMatchingItem.IsNullable;
                                bool fromNotNullable = !isNullable && nameMatchingItem.IsNullable;

                                if (typeMatch &&
                                    typeIdMatch &&
                                    nullableMatch)
                                {
                                    // Property has exactly the same attributes > no conversion required
                                    tolerantLayoutStructure.AddTolerantLayoutProperty(ctx, propertyName);
                                }
                                else if (typeMatch &&
                                         typeIdMatch &&
                                         !nullableMatch &&
                                         fromNotNullable)
                                {
                                    // Property changed only from not nullable to nullable
                                    tolerantLayoutStructure.AddTolerantLayoutConverterProperty(nameMatchingItem, ctx, propertyName, itemType, propertyTypeId, isNullable, v => v);
                                }
                                else if (!typeMatch &&
                                         !typeIdMatch &&
                                         (nullableMatch || fromNotNullable))
                                {
                                    // Only property type changed
                                    // Check if type can be converted without loosing data
                                    Func <object, object> converter = null;
                                    if (itemType == ItemType.Int32 &&
                                        nameMatchingItem.Type == ItemType.Int64)
                                    {
                                        // Read incoming Int32 and convert to local Int64 property
                                        converter = v => (long)(int)v;
                                    }
                                    else if (itemType == ItemType.Int16 &&
                                             nameMatchingItem.Type == ItemType.Int32)
                                    {
                                        // Read incoming Int16 and convert to local Int32 property
                                        converter = v => (int)(short)v;
                                    }
                                    else if (itemType == ItemType.Byte &&
                                             nameMatchingItem.Type == ItemType.Int16)
                                    {
                                        // Read incoming Byte and convert to local Int16 property
                                        converter = v => (short)(byte)v;
                                    }
                                    else if (itemType == ItemType.Double &&
                                             nameMatchingItem.Type == ItemType.Decimal)
                                    {
                                        // Read incoming Double and convert to local Decimal property
                                        converter = v => (decimal)(double)v;
                                    }
                                    else if (itemType == ItemType.Char &&
                                             nameMatchingItem.Type == ItemType.String)
                                    {
                                        // Read incoming Char and convert to local String property
                                        converter = v => new string(new char[] { (char)v });
                                    }

                                    if (converter != null)
                                    {
                                        tolerantLayoutStructure.AddTolerantLayoutConverterProperty(nameMatchingItem, ctx, propertyName, itemType, propertyTypeId, isNullable, converter);
                                    }
                                }
                            }
                            else
                            {
                                // no name matching property found (removed, renamed or old local version) > create dummy item
                                tolerantLayoutStructure.AddTolerantLayoutDummyProperty(ctx, propertyName, itemType, propertyTypeId, isNullable);
                            }
                        }

                        tolerantLayoutStructure.FinalizeTolerantLayoutStructure();
                        if (typeId == tolerantLayoutStructure.TypeId)
                        {
                            // Tolerant mapping was successful
                            // Register only type ID in global cache
                            BinarySerializer.RegisterTolerantTypeMapping(tolerantLayoutStructure);

                            return(tolerantLayoutStructure);
                        }
                        else
                        {
                            // Can't map old/new structure to incoming type meta data
                            throw new FormatException($"The incoming binary format does not match the loaded type {type.FullName}! An tolerant mapping was not possible. Please update the remote or local interface assemblies. Expected Type Id: {result.TypeId}; Received Type Id: {typeId}");
                        }
                    }
                }
                else if (resultItem is ITypePrefix)
                {
                    // Only type prefix - e.g. enum
                    ITypePrefix result = (ITypePrefix)resultItem;

                    short itemCount = reader.ReadInt16();

                    if (result.TypeId == typeId)
                    {
                        // internal type is equal remote type
                        for (int i = 0; i < itemCount; i++)
                        {
                            SkipPropertyMetaInfo(reader);
                        }

                        return(result);
                    }
                    else
                    {
                        throw new FormatException($"The incoming binary format does not match the loaded type {type.FullName}! An tolerant mapping was not possible. Please update the remote or local interface assemblies. Expected Type Id: {result.TypeId}; Received Type Id: {typeId}");
                    }
                }
                else
                {
                    return(resultItem);
                }
            }
            else if (metaTypeVersion == CollectionTypeDescr)
            {
                assemblyName = reader.ReadString();
                typeFullName = reader.ReadString();

                //todo: load assembly if required
                if (TypeService.TryGetTypeByName(typeFullName, out type))
                {
                    CollectionItems result = (CollectionItems)ctx.GetByType(type);

                    if (result.TypeId == typeId)
                    {
                        return(result);
                    }
                    else
                    {
                        // differences between local type and remote type
                        //todo: implement
                        throw new NotImplementedException($"Support for different binary layout is not implemented yet! Local Type ID: {result.TypeId}; Remote Type ID: {typeId}");
                    }
                }
                else
                {
                    throw new TypeAccessException($"Type {typeFullName} not found!");
                }
            }
            else
            {
                throw new NotSupportedException($"Type meta information version {metaTypeVersion} not supported!");
            }
        }