ln.objects/serialization/binary/BinaryDeserializer.cs

247 lines
8.0 KiB
C#

using ln.type;
using System;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;
namespace ln.objects.serialization.binary
{
public class BinaryDeserializer : Deserializer
{
public override bool DeserializeObject(byte[] serializedBytes, ref object o)
{
MemoryStream ms = new MemoryStream(serializedBytes);
if (!Object.ReferenceEquals(null,o) && (serializedBytes[0] == 'S'))
{
ms.ReadByte();
String typeName = (string)Deserialize(ms);
DeserializeStructured(ms, o.GetType(), o);
}
else
{
o = Deserialize(ms);
}
return true;
}
public override bool TryGetType(byte[] serializedBytes, out Type type) => TryGetType(new MemoryStream(serializedBytes), out type);
public bool TryGetType(Stream stream, out Type type)
{
int tc;
switch (tc = stream.ReadByte())
{
case -1:
throw new EndOfStreamException();
case '0':
type = null;
break;
case 'P':
return TryGetPrimitiveType(stream, out type);
case 'R':
case 'S':
case 'E':
type = Type.GetType(Deserialize(stream) as string);
break;
case 'A':
type = Type.GetType(Deserialize(stream) as string).MakeArrayType();
break;
case 'B':
type = typeof(byte[]);
break;
case 'G':
type = typeof(Guid);
break;
default:
type = null;
return false;
}
return true;
}
public bool TryGetPrimitiveType(Stream stream, out Type type)
{
int tc;
switch (tc = stream.ReadByte())
{
case -1:
throw new EndOfStreamException();
case 'I':
type = typeof(int);
break;
case 'i':
type = typeof(uint);
break;
case 'B':
type = typeof(byte);
break;
case 'C':
type = typeof(char);
break;
case 'S':
type = typeof(short);
break;
case 's':
type = typeof(ushort);
break;
case 'L':
type = typeof(long);
break;
case 'l':
type = typeof(ulong);
break;
case 'F':
type = typeof(float);
break;
case 'D':
type = typeof(double);
break;
case 'b':
type = typeof(bool);
break;
case 'T':
type = typeof(string);
break;
default:
type = null;
return false;
}
return true;
}
object Deserialize(Stream stream)
{
int tc;
switch (tc = stream.ReadByte())
{
case -1:
throw new EndOfStreamException();
case '0':
return null;
case 'P':
return DeserializePrimitive(stream);
case 'R':
return DeserializeReference(stream);
case 'S':
return DeserializeStructured(stream);
case 'E':
return DeserializeEnum(stream);
case 'A':
return DeserializeArray(stream);
case 'B':
return DeserializeByteArray(stream);
case 'G':
return DeserializeGuid(stream);
default:
throw new NotSupportedException(String.Format("Unsupported type code: {0}", (char)tc));
}
}
object DeserializePrimitive(Stream stream)
{
int tc;
switch (tc = stream.ReadByte())
{
case -1:
throw new EndOfStreamException();
case 'I':
return stream.ReadInteger();
case 'i':
return stream.ReadUInteger();
case 'B':
return (byte)stream.ReadByte();
case 'C':
return (char)stream.ReadShort();
case 'S':
return stream.ReadShort();
case 's':
return stream.ReadUShort();
case 'L':
return stream.ReadLong();
case 'l':
return stream.ReadULong();
case 'F':
return stream.ReadFloat();
case 'D':
return stream.ReadDouble();
case 'b':
return stream.ReadByte() != 0;
case 'T':
int tl = stream.ReadInteger();
byte[] tbytes = stream.ReadBytes(tl);
return Encoding.UTF8.GetString(tbytes);
default:
throw new NotSupportedException(String.Format("Unsupported primitive type code: {0}", (char)tc));
}
}
object DeserializeGuid(Stream stream) => new Guid(stream.ReadBytes(16));
object DeserializeEnum(Stream stream)
{
Type eType = Type.GetType(Deserialize(stream) as string);
object value = Deserialize(stream);
if (value is int nvalue)
return Enum.ToObject(eType, nvalue);
else if (value is string svalue)
return Enum.Parse(eType, svalue);
else
throw new NotSupportedException("Unsupported ENUM repressentation found");
}
object DeserializeByteArray(Stream stream)
{
int length = stream.ReadInteger();
return stream.ReadBytes(length);
}
object DeserializeArray(Stream stream)
{
Type etype = Type.GetType(Deserialize(stream) as string);
int length = stream.ReadInteger();
Array array = Array.CreateInstance(etype, length);
for (int n = 0; n < array.Length; n++)
array.SetValue(Deserialize(stream), n);
return array;
}
object DeserializeStructured(Stream stream)
{
String typeName = (string)Deserialize(stream);
Type type = Type.GetType(typeName);
object o = type.IsValueType ? Activator.CreateInstance(type) : Activator.CreateInstance(type, true);
DeserializeStructured(stream, type, o);
return o;
}
void DeserializeStructured(Stream stream, Type type, object o)
{
int nFields = stream.ReadInteger();
for (int n=0;n<nFields;n++)
{
FieldInfo fieldInfo = type.GetField(Deserialize(stream) as string,BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
fieldInfo.SetValue(o, Deserialize(stream));
}
}
object DeserializeReference(Stream stream)
{
Type type = Type.GetType(Deserialize(stream) as string);
object reference = Deserialize(stream);
if (TryLookupObject(reference, type, out object o))
return o;
throw new SerializationException(String.Format("Could not lookup reference {0}", reference));
}
}
}