public object Deserialize(BinaryReader reader)
{
if (reader.ReadInt32() != magic)
throw new SerializationException("The data cannot be read by FastSerializer (unknown magic value)");
DeserializationContext context = new DeserializationContext();
context.Reader = reader;
context.Objects = new object[reader.ReadInt32()];
context.Types = new Type[reader.ReadInt32()];
string[] assemblyNames = new string[reader.ReadInt32()];
int fixedInstanceCount = reader.ReadInt32();
if (fixedInstanceCount != 0) {
if (this.FixedInstances == null || this.FixedInstances.Length != fixedInstanceCount)
throw new SerializationException("Number of fixed instances doesn't match");
for (int i = 0; i < fixedInstanceCount; i++) {
context.Objects[i + 1] = this.FixedInstances[i];
}
}
for (int i = 0; i < assemblyNames.Length; i++) {
assemblyNames[i] = reader.ReadString();
}
int stringTypeID = -1;
for (int i = 0; i < context.Types.Length; i++) {
byte typeKind = reader.ReadByte();
switch (typeKind) {
case Type_ReferenceType:
case Type_ValueType:
int assemblyID;
if (assemblyNames.Length <= ushort.MaxValue)
assemblyID = reader.ReadUInt16();
else
assemblyID = reader.ReadInt32();
string assemblyName = assemblyNames[assemblyID];
string typeName = reader.ReadString();
Type type;
if (SerializationBinder != null) {
type = SerializationBinder.BindToType(assemblyName, typeName);
} else {
type = Assembly.Load(assemblyName).GetType(typeName);
}
if (type == null)
throw new SerializationException("Could not find '" + typeName + "' in '" + assemblyName + "'");
if (typeKind == Type_ValueType && !type.IsValueType)
throw new SerializationException("Expected '" + typeName + "' to be a value type, but it is reference type");
if (typeKind == Type_ReferenceType && type.IsValueType)
throw new SerializationException("Expected '" + typeName + "' to be a reference type, but it is value type");
context.Types[i] = type;
if (type == typeof(string))
stringTypeID = i;
break;
case Type_SZArray:
context.Types[i] = context.Types[context.ReadTypeID()].MakeArrayType();
break;
case Type_ParameterizedType:
Type genericType = context.Types[context.ReadTypeID()];
int typeParameterCount = genericType.GetGenericArguments().Length;
Type[] typeArguments = new Type[typeParameterCount];
for (int j = 0; j < typeArguments.Length; j++) {
typeArguments[j] = context.Types[context.ReadTypeID()];
}
context.Types[i] = genericType.MakeGenericType(typeArguments);
break;
default:
throw new SerializationException("Unknown type kind");
}
}
context.DeserializeTypeDescriptions();
int[] typeIDByObjectID = new int[context.Objects.Length];
for (int i = 1 + fixedInstanceCount; i < context.Objects.Length; i++) {
int typeID = context.ReadTypeID();
object instance;
if (typeID == stringTypeID) {
instance = reader.ReadString();
} else {
Type type = context.Types[typeID];
if (type.IsArray) {
int length = reader.ReadInt32();
instance = Array.CreateInstance(type.GetElementType(), length);
} else {
instance = FormatterServices.GetUninitializedObject(type);
}
}
context.Objects[i] = instance;
typeIDByObjectID[i] = typeID;
}
List<CustomDeserialization> customDeserializatons = new List<CustomDeserialization>();
ObjectReader[] objectReaders = new ObjectReader[context.Types.Length]; // index: type ID
for (int i = 1 + fixedInstanceCount; i < context.Objects.Length; i++) {
object instance = context.Objects[i];
int typeID = typeIDByObjectID[i];
Log("0x{2:x6} Read #{0}: {1}", i, context.Types[typeID].Name, reader.BaseStream.Position);
ISerializable serializable = instance as ISerializable;
if (serializable != null) {
Type type = context.Types[typeID];
SerializationInfo info = new SerializationInfo(type, formatterConverter);
int count = reader.ReadInt32();
for (int j = 0; j < count; j++) {
string name = reader.ReadString();
object val = context.ReadObject();
info.AddValue(name, val);
}
CustomDeserializationAction action = GetCustomDeserializationAction(type);
customDeserializatons.Add(new CustomDeserialization(instance, info, action));
} else {
ObjectReader objectReader = objectReaders[typeID];
if (objectReader == null) {
objectReader = GetReader(context.Types[typeID]);
objectReaders[typeID] = objectReader;
}
objectReader(context, instance);
}
}
Log("File was read successfully, now running {0} custom deserializations...", customDeserializatons.Count);
foreach (CustomDeserialization customDeserializaton in customDeserializatons) {
customDeserializaton.Run(streamingContext);
}
for (int i = 1 + fixedInstanceCount; i < context.Objects.Length; i++) {
IDeserializationCallback dc = context.Objects[i] as IDeserializationCallback;
if (dc != null)
dc.OnDeserialization(null);
}
return context.ReadObject();
}