/// <summary>
        /// Reads an object's data from the specified binary reader and creates a new instance of that object with the given data. For user-defined types, a new object of the specified type is returned without any fields initialized. For arrays, a new object with the correct rank lengths is returned. For strings and primitives, an object with the correct value is returned.
        /// </summary>
        /// <param name="context">The current deserialization context, with data about the current object graph and known types.</param>
        /// <param name="reader">The binary reader to utilize.</param>
        /// <param name="type">The type of the object to create.</param>
        /// <returns>The created object.</returns>
        protected virtual object ReadAndCreateObject(PowerDeserializationContext context, BinaryReader reader, Type type)
        {
            CheckTypeAllowance(type);
            object toReturn;

            if (type == typeof(string))
            {
                toReturn = reader.ReadString();
            }
            else if (type == typeof(Type))
            {
                toReturn = TypeResolver.ReadTypeID(reader);
            }
            else if (type.IsPrimitive)
            {
                toReturn = ReadPrimitiveObject(reader, type);
            }
            else if (type.IsArray)
            {
                byte  rankSize = reader.ReadByte();
                int[] ranks    = new int[rankSize];
                for (int i = 0; i < rankSize; i++)
                {
                    ranks[i] = reader.ReadInt32();
                }
                toReturn = Array.CreateInstance(type.GetElementType(), ranks);
            }
            else
            {
                toReturn = FormatterServices.GetUninitializedObject(type);
            }
            context.RegisterNextObject(toReturn);
            return(toReturn);
        }
 /// <summary>
 /// Deserializes the given object, populating its fields by reading its object references and primitive data from the given binary reader.
 /// </summary>
 /// <param name="context">The current deserialization context, with data about the current object graph and known types.</param>
 /// <param name="reader">The binary reader to utilize.</param>
 /// <param name="obj">The object whose fields should be populated.</param>
 /// <param name="type">The type of the deserialized object.</param>
 protected virtual void DeserializeObject(PowerDeserializationContext context, BinaryReader reader, object obj, Type type)
 {
     if (type.IsArray)
     {
         Array array = (Array)obj;
         int[] ranks = new int[array.Rank];
         for (int i = 0; i < array.Rank; i++)
         {
             ranks[i] = array.GetLength(i);
         }
         Type elementType = type.GetElementType();
         CheckTypeAllowance(elementType);
         if (elementType.IsPrimitive)
         {
             ReadFlattenedPrimitiveArray(reader, array, 0, ranks, new int[array.Rank], elementType);
         }
         else if (elementType.IsValueType)
         {
             ReadFlattenedValueTypeArray(context, reader, array, 0, ranks, new int[array.Rank], elementType);
         }
         else
         {
             ReadFlattenedArray(context, reader, array, 0, ranks, new int[array.Rank]);
         }
     }
     else if (type.IsPrimitive || obj is Type)
     {
     }
     else
     {
         DeserializeReferenceType(context, reader, obj, type);
     }
 }
        /// <summary>
        /// Deserializes an object from a byte array.
        /// </summary>
        /// <param name="data">The byte-based representation of the object.</param>
        /// <returns>The deserialized object.</returns>
        public virtual object Deserialize(byte[] data)
        {
            using (MemoryStream stream = new MemoryStream(data))
            {
                using (BinaryReader reader = new BinaryReader(stream))
                {
                    PowerDeserializationContext context = CreateDeserializationContext();
                    int dataLength = data.Length - 4;
                    stream.Position = dataLength;
                    int typeSize = reader.ReadInt32();
                    stream.Position = data.Length - typeSize - 4;

                    List <Type> knownTypes = new List <Type>();
                    while (reader.BaseStream.Position < dataLength)
                    {
                        knownTypes.Add(TypeResolver.ReadTypeID(reader));
                    }
                    stream.Position       = 0;
                    context.IncludedTypes = knownTypes;

                    object obj = ReadAndCreateObject(context, reader, knownTypes[0]);
                    if (obj is NullRepresentative)
                    {
                        obj = null;
                    }
                    for (int i = 1; i < context.ObjectGraph.Count; i++)
                    {
                        DeserializeObject(context, reader, context.ObjectGraph[i], context.ObjectGraph[i].GetType());
                    }

                    return(ProcessObjectGraph(context));
                }
            }
        }
 private void ReadFlattenedArray(PowerDeserializationContext context, BinaryReader reader, Array array, int index, int[] ranks, int[] currentRanks)
 {
     if (index < ranks.Length)
     {
         for (int i = 0; i < ranks[index]; i++)
         {
             ReadFlattenedArray(context, reader, array, index + 1, ranks, currentRanks);
             currentRanks[index]++;
         }
     }
     else
     {
         array.SetValue(ReadObjectReference(context, reader), currentRanks);
     }
 }
 private void ReadFlattenedValueTypeArray(PowerDeserializationContext context, BinaryReader reader, Array array, int index, int[] ranks, int[] currentRanks, Type type)
 {
     if (index < ranks.Length)
     {
         for (int i = 0; i < ranks[index]; i++)
         {
             ReadFlattenedValueTypeArray(context, reader, array, index + 1, ranks, currentRanks, type);
             currentRanks[index]++;
         }
     }
     else
     {
         object obj = FormatterServices.GetUninitializedObject(type);
         DeserializeReferenceType(context, reader, obj, type);
         array.SetValue(obj, currentRanks);
     }
 }
        /// <summary>
        /// Reads an object reference from the given binary reader. If the object has not been referenced before, a new object of the specified type is instantiated.
        /// </summary>
        /// <param name="context">The current deserialization context, with data about the current object graph and known types.</param>
        /// <param name="reader">The binary reader to utilize.</param>
        /// <returns>The referenced object.</returns>
        protected virtual object ReadObjectReference(PowerDeserializationContext context, BinaryReader reader)
        {
            ushort id = reader.ReadUInt16();

            if (id == 0)
            {
                return(null);
            }
            else if (context.HasObject(id))
            {
                return(context.GetObject(id));
            }
            else
            {
                return(ReadAndCreateObject(context, reader, context.GetTypeFromID(reader.ReadUInt16())));
            }
        }
 private void DeserializeReferenceType(PowerDeserializationContext context, BinaryReader reader, object obj, Type type)
 {
     foreach (FieldInfo info in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
     {
         if (info.FieldType.IsPrimitive)
         {
             CheckTypeAllowance(info.FieldType);
             info.SetValue(obj, ReadPrimitiveObject(reader, info.FieldType));
         }
         else if (info.FieldType.IsValueType)
         {
             CheckTypeAllowance(info.FieldType);
             object field = FormatterServices.GetUninitializedObject(info.FieldType);
             DeserializeReferenceType(context, reader, field, info.FieldType);
             info.SetValue(obj, field);
         }
         else
         {
             info.SetValue(obj, ReadObjectReference(context, reader));
         }
     }
 }
 /// <summary>
 /// Processes the generated object graph, makes any last-minute changes if necessary, and returns the deserialized object.
 /// </summary>
 /// <param name="context">The current deserialization context.</param>
 /// <returns>The final deserialized object.</returns>
 protected virtual object ProcessObjectGraph(PowerDeserializationContext context)
 {
     return(context.ObjectGraph[1]);
 }