You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
428 lines
16 KiB
428 lines
16 KiB
#if UNITY_2019_1_OR_NEWER
|
|
using ILRuntime.CLR.Method;
|
|
using ILRuntime.CLR.Utils;
|
|
using ILRuntime.Runtime.Intepreter;
|
|
using ILRuntime.Runtime.Stack;
|
|
#endif
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
|
|
namespace BinarySerialize
|
|
{
|
|
public static class BinSerialize
|
|
{
|
|
#region Serialize
|
|
public static void Serialize(Stream stream,object param,uint rawTag)
|
|
{
|
|
if (param != null)
|
|
{
|
|
Type type = Helper.GetTypeByObject(param);
|
|
if (true /*rawTag > 0*/)
|
|
{
|
|
type = Helper.GetILRunTimeType(type);
|
|
if (Helper.base_exporters_table.ContainsKey(type))
|
|
{
|
|
Helper.base_exporters_table[type](stream, param, rawTag);
|
|
}
|
|
else if (param is Enum)
|
|
{
|
|
var enumValType = Enum.GetUnderlyingType(type);
|
|
if (Helper.base_exporters_table.ContainsKey(enumValType))
|
|
{
|
|
Helper.base_exporters_table[enumValType](stream, param, rawTag);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (type.IsGenericType || type.IsArray)
|
|
{
|
|
//if (param is IDictionary) 暂时不支持map
|
|
//SerializeDic(stream,(System.Collections.IDictionary)param, type, rawTag);
|
|
//else
|
|
if (param is IList || /*type.Name.Contains("Stack`1") || type.Name.Contains("Queue`1") ||*/ type.IsArray)
|
|
SerializeList(stream, (System.Collections.IEnumerable)param, type, rawTag);
|
|
else
|
|
throw new Exception("Serialize.serialize 未定义的类型1:" + type.ToString());
|
|
|
|
}
|
|
else if (type.IsClass)
|
|
{
|
|
Helper.AddTypeProperties(type);
|
|
if (rawTag > 0)
|
|
{
|
|
ProtocolParser.WriteUInt64(stream, (ulong)rawTag);
|
|
}
|
|
var msField = new MemoryStream();
|
|
msField.SetLength(0);
|
|
SerializeClass(msField, param, type);
|
|
uint length11 = (uint)msField.Length;
|
|
ProtocolParser.WriteUInt32(stream, length11);
|
|
msField.WriteTo(stream);
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("Serialize.serialize 未定义的类型2:" + type.ToString());
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("Serialize.serialize rawTag error::" + type.ToString());
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void SerializeClass(Stream stream,object obj, Type type)
|
|
{
|
|
if (obj == null) return;
|
|
Helper.AddTypeProperties(type);
|
|
IList<PropertyMetadata> props = Helper.type_properties[type];
|
|
foreach (PropertyMetadata p_data in props)
|
|
{
|
|
if (p_data.IsField)
|
|
{
|
|
Serialize(stream,((FieldInfo) p_data.Info).GetValue(obj), p_data.rawTag);
|
|
}
|
|
else
|
|
{
|
|
PropertyInfo p_info = (PropertyInfo)p_data.Info;
|
|
if (p_info.CanRead)
|
|
{
|
|
Serialize(stream,p_info.GetValue(obj, null), p_data.rawTag);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void SerializeList(Stream stream,System.Collections.IEnumerable param,Type type,uint rawTag)
|
|
{
|
|
if (param != null)
|
|
{
|
|
Helper.AddArrayMetadata(type);
|
|
ArrayMetadata t_data = Helper.array_metadata[type];
|
|
Type elem_type;
|
|
if (!t_data.IsArray && !t_data.IsList)
|
|
{
|
|
throw new Exception(string.Format("Type {0} can't act as an array", type));
|
|
}
|
|
if (!t_data.IsArray)
|
|
{
|
|
elem_type = t_data.ElementType;
|
|
}
|
|
else
|
|
{
|
|
elem_type = type.GetElementType();
|
|
}
|
|
if (!elem_type.IsClass)//元素不是类类型
|
|
{
|
|
ProtocolParser.WriteUInt32(stream,rawTag);
|
|
var msField = new MemoryStream();
|
|
msField.SetLength(0);
|
|
foreach (var item in param)
|
|
{
|
|
Serialize(msField, item, 0);
|
|
}
|
|
uint length11 = (uint)msField.Length;
|
|
ProtocolParser.WriteUInt32(stream, length11);
|
|
msField.WriteTo(stream);
|
|
}
|
|
else
|
|
{
|
|
foreach (var item in param)
|
|
{
|
|
Serialize(stream, item, rawTag);
|
|
}
|
|
}
|
|
|
|
}
|
|
return;
|
|
}
|
|
public static byte[] Serialize(object obj)
|
|
{
|
|
if (obj != null)
|
|
{
|
|
MemoryStream stream = new MemoryStream();
|
|
var type = Helper.GetTypeByObject(obj);
|
|
SerializeClass(stream, obj, type);
|
|
return stream.ToArray();
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Deserialize
|
|
|
|
public static T Deserialize<T>(byte[] arr)
|
|
{
|
|
//PositionStream stream = new PositionStream(arr);
|
|
MemoryStream stream = new MemoryStream(arr);
|
|
return (T)DeserializeClass(typeof(T), stream);
|
|
}
|
|
|
|
private static object Deserialize(Stream stream,Type type)
|
|
{
|
|
object obj = null;
|
|
type = Helper.GetILRunTimeType(type);
|
|
if (Helper.base_importers_table.ContainsKey(type))
|
|
{
|
|
obj = Helper.base_importers_table[type](stream);
|
|
}
|
|
else if (type.BaseType == typeof(Enum))
|
|
{
|
|
var numType = Helper.GetILRunTimeType(Enum.GetUnderlyingType(type));
|
|
if (Helper.base_importers_table.ContainsKey(numType))
|
|
{
|
|
obj = Helper.base_importers_table[numType](stream);
|
|
}
|
|
}
|
|
else if (type.IsGenericType || type.IsClass || type.IsArray)
|
|
{
|
|
if (type.Name.Contains("List`1"))
|
|
{
|
|
//obj = DeserializeList(type, stream);
|
|
throw new Exception("Serialize.Deserialize 未定义的类型:" + type.ToString());
|
|
}
|
|
/*else if (type.Name.Contains("Dictionary`2"))
|
|
{
|
|
obj = DeserializeDic(type, stream);
|
|
}
|
|
else if (type.Name.Contains("Queue`1"))
|
|
{
|
|
obj = DeserializeQueue(type, data);
|
|
}
|
|
else if (type.Name.Contains("Stack`1"))
|
|
{
|
|
obj = DeserializeStack(type, data);
|
|
}*/
|
|
else if (type.IsClass)
|
|
{
|
|
long limit = ProtocolParser.ReadUInt32(stream);
|
|
obj = DeserializeClass(type, stream, limit);
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("Serialize.Deserialize 未定义的类型:" + type.ToString());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("Serialize.Deserialize 未定义的类型:" + type.ToString());
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
public static object DeserializeClass(Type type, Stream stream, long limit = -1)
|
|
{
|
|
object instance = null;
|
|
Helper.AddObjectMetadata(type);
|
|
ObjectMetadata t_data = Helper.object_metadata[type];
|
|
#if UNITY_2019_1_OR_NEWER
|
|
if (type is ILRuntime.Reflection.ILRuntimeType)
|
|
instance = ((ILRuntime.Reflection.ILRuntimeType)type).ILType.Instantiate();
|
|
else
|
|
instance = Activator.CreateInstance(type);
|
|
#else
|
|
instance = Activator.CreateInstance(type);
|
|
#endif
|
|
Dictionary<uint, IList> object_list = new Dictionary<uint, IList>();
|
|
Dictionary<uint, Type> object_type = new Dictionary<uint, Type>();
|
|
ObjectMetadata props = Helper.object_metadata[type];
|
|
limit += stream.Position;
|
|
while (true)
|
|
{
|
|
if (limit > 0 && stream.Position >= limit)
|
|
{
|
|
if (stream.Position == limit)
|
|
break;
|
|
else
|
|
throw new ProtocolBufferException("Read past max limit");
|
|
}
|
|
int keyByte = stream.ReadByte();
|
|
if (keyByte == -1)
|
|
break;
|
|
var key = ProtocolParser.ReadKey((byte)keyByte, stream);
|
|
var tag = key.Field;
|
|
if (tag == 0)
|
|
{
|
|
if (limit > 0)
|
|
{
|
|
ProtocolParser.SkipKey(stream, key);
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (props.tag_type.ContainsKey(tag))
|
|
{
|
|
bool isList = false;
|
|
var v = props.tag_type[tag];
|
|
if (v.Type.IsGenericType && v.Type.Name.Contains("List`1"))//list
|
|
{
|
|
Type elementType = null;
|
|
IList list = null;
|
|
if (!object_list.ContainsKey(tag))
|
|
{
|
|
elementType = typeof(int);
|
|
list = CreateIListByType(v.Type, ref elementType);
|
|
object_list.Add(tag, list);
|
|
object_type.Add(tag,elementType);
|
|
}
|
|
list = object_list[tag];
|
|
elementType = object_type[tag];
|
|
//版本问题,List<int> 作为 Wire.LengthDelimited 成为数组
|
|
if (!elementType.IsClass && key.WireType == Wire.LengthDelimited)
|
|
{
|
|
long length = ProtocolParser.ReadUInt32(stream) + stream.Position;
|
|
while (true)
|
|
{
|
|
if (stream.Position >= length)
|
|
{
|
|
if (stream.Position == length)
|
|
break;
|
|
else
|
|
throw new ProtocolBufferException("Read past max limit list");
|
|
}
|
|
DeserializeList(stream, ref list, ref elementType);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DeserializeList(stream, ref list, ref elementType);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (v.IsField)
|
|
{
|
|
var info = (FieldInfo)v.Info;
|
|
var num = Deserialize(stream, v.Type);
|
|
info.SetValue(instance, num);
|
|
}
|
|
else
|
|
{
|
|
PropertyInfo p_info = (PropertyInfo)v.Info;
|
|
if (p_info.CanRead)
|
|
{
|
|
var num = Deserialize(stream, v.Type);
|
|
if (p_info.CanWrite)
|
|
{
|
|
p_info.SetValue(instance, num);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new ProtocolBufferException("something went wrong in the stream,Invalid tag: "+tag);
|
|
}
|
|
}
|
|
foreach (var v in object_list)
|
|
{
|
|
var tag = v.Key;
|
|
var t = props.tag_type[tag];
|
|
if (t.IsField)
|
|
{
|
|
((FieldInfo)t.Info).SetValue(instance, v.Value);
|
|
}
|
|
else
|
|
{
|
|
PropertyInfo p_info = (PropertyInfo)t.Info;
|
|
if (p_info.CanWrite)
|
|
{
|
|
p_info.SetValue(instance, v.Value);
|
|
}
|
|
}
|
|
}
|
|
return instance;
|
|
}
|
|
|
|
private static IList CreateIListByType(Type type, ref Type elem_type)
|
|
{
|
|
IList list = null;
|
|
Helper.AddArrayMetadata(type);
|
|
ArrayMetadata t_data = Helper.array_metadata[type];
|
|
if (!t_data.IsArray && !t_data.IsList)
|
|
{
|
|
throw new Exception(string.Format("Type {0} can't act as an array", type));
|
|
}
|
|
if (!t_data.IsArray)
|
|
{
|
|
list = (IList)Activator.CreateInstance(type);
|
|
elem_type = t_data.ElementType;
|
|
}
|
|
else
|
|
{
|
|
list = new ArrayList();
|
|
elem_type = type.GetElementType();
|
|
}
|
|
|
|
return list;
|
|
}
|
|
private static void DeserializeList(Stream stream,ref IList list, ref Type elem_type)
|
|
{
|
|
var rt = Helper.GetILRunTimeType(elem_type);
|
|
var item = Deserialize(stream, rt);
|
|
#if UNITY_2019_1_OR_NEWER
|
|
if (elem_type is ILRuntime.Reflection.ILRuntimeType && ((ILRuntime.Reflection.ILRuntimeType)elem_type).ILType.IsEnum)
|
|
{
|
|
item = (int)item;
|
|
}
|
|
else
|
|
{
|
|
item = rt.CheckCLRTypes(item);
|
|
}
|
|
#else
|
|
if (elem_type.BaseType == typeof(Enum))
|
|
{
|
|
item = (int) item;
|
|
}
|
|
#endif
|
|
list.Add(item);
|
|
|
|
return;
|
|
}
|
|
#endregion
|
|
#if UNITY_2019_1_OR_NEWER
|
|
public unsafe static void RegisterILRuntimeCLRRedirection(ILRuntime.Runtime.Enviorment.AppDomain appdomain)
|
|
{
|
|
foreach (var i in typeof(BinSerialize).GetMethods())
|
|
{
|
|
if (i.Name == "Deserialize" && i.IsGenericMethodDefinition)//泛型需要注册
|
|
{
|
|
var param = i.GetParameters();
|
|
if (param[0].ParameterType == typeof(byte[]))
|
|
{
|
|
appdomain.RegisterCLRMethodRedirection(i, ByteToObject);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public unsafe static StackObject* ByteToObject(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
|
|
{
|
|
ILRuntime.Runtime.Enviorment.AppDomain __domain = intp.AppDomain;
|
|
StackObject* ptr_of_this_method;
|
|
StackObject* __ret = ILIntepreter.Minus(esp, 1);
|
|
ptr_of_this_method = ILIntepreter.Minus(esp, 1);
|
|
byte[] json = (byte[])typeof(byte[]).CheckCLRTypes(StackObject.ToObject(ptr_of_this_method, __domain, mStack));
|
|
intp.Free(ptr_of_this_method);
|
|
var type = method.GenericArguments[0].ReflectionType;
|
|
MemoryStream stream = new MemoryStream(json);
|
|
var result_of_this_method = DeserializeClass(type, stream);
|
|
|
|
return ILIntepreter.PushObject(__ret, mStack, result_of_this_method);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|