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

#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
}
}