247 lines
8.0 KiB
C#
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));
|
|
}
|
|
|
|
}
|
|
}
|