/// <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]); }