Unity Udexreal开发插件包
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.

675 lines
28 KiB

//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Reflection;
using System.Text;
namespace TouchSocket.Core
{
/// <summary>
/// 快速二进制序列化。
/// </summary>
public static class FastBinaryFormatter
{
static FastBinaryFormatter()
{
AddFastBinaryConverter<Version, VersionFastBinaryConverter>();
}
private static readonly ConcurrentDictionary<Type, SerializObject> m_instanceCache = new ConcurrentDictionary<Type, SerializObject>();
/// <summary>
/// 添加转换器。
/// </summary>
public static void AddFastBinaryConverter<TType, TConverter>() where TConverter : IFastBinaryConverter, new()
{
AddFastBinaryConverter(typeof(TType), (IFastBinaryConverter)Activator.CreateInstance(typeof(TConverter)));
}
/// <summary>
/// 添加转换器。
/// </summary>
/// <typeparam name="TType"></typeparam>
/// <param name="converter"></param>
public static void AddFastBinaryConverter<TType>(IFastBinaryConverter converter)
{
AddFastBinaryConverter(typeof(TType), converter);
}
/// <summary>
/// 添加转换器。
/// </summary>
/// <param name="type"></param>
/// <param name="converter"></param>
public static void AddFastBinaryConverter(Type type, IFastBinaryConverter converter)
{
m_instanceCache.AddOrUpdate(type, new SerializObject(type) { Converter = converter }, (k, v) => v);
}
#region Serialize
/// <summary>
/// 序列化对象
/// </summary>
/// <param name="byteBlock">流</param>
/// <param name="graph">对象</param>
public static void Serialize<T>(ByteBlock byteBlock, T graph)
{
byteBlock.Position = 1;
SerializeObject(byteBlock, graph);
byteBlock.Buffer[0] = 1;
byteBlock.SetLength(byteBlock.Position);
}
private static int SerializeClass<T>(ByteBlock stream, T obj, Type type)
{
int len = 0;
if (obj != null)
{
SerializObject serializObject = GetOrAddInstance(type);
for (int i = 0; i < serializObject.MemberInfos.Length; i++)
{
MemberInfo memberInfo = serializObject.MemberInfos[i];
byte[] propertyBytes = Encoding.UTF8.GetBytes(memberInfo.Name);
if (propertyBytes.Length > byte.MaxValue)
{
throw new Exception($"属性名:{memberInfo.Name}超长");
}
stream.Write((byte)propertyBytes.Length);
stream.Write(propertyBytes, 0, propertyBytes.Length);
len += propertyBytes.Length + 1;
//len += SerializeObject(stream, property.GetValue(obj));
len += SerializeObject(stream, serializObject.MemberAccessor.GetValue(obj, memberInfo.Name));
}
//foreach (PropertyInfo property in serializObject.Properties)
//{
//}
//foreach (FieldInfo fieldInfo in serializObject.FieldInfos)
//{
// byte[] propertyBytes = Encoding.UTF8.GetBytes(fieldInfo.Name);
// if (propertyBytes.Length > byte.MaxValue)
// {
// throw new Exception($"属性名:{fieldInfo.Name}超长");
// }
// byte lenBytes = (byte)propertyBytes.Length;
// stream.Write(lenBytes);
// stream.Write(propertyBytes, 0, propertyBytes.Length);
// len += propertyBytes.Length + 1;
// len += SerializeObject(stream, fieldInfo.GetValue(obj));
//}
}
return len;
}
private static int SerializeDictionary(ByteBlock stream, IEnumerable param)
{
int len = 0;
if (param != null)
{
long oldPosition = stream.Position;
stream.Position += 4;
len += 4;
uint paramLen = 0;
foreach (dynamic item in param)
{
len += SerializeObject(stream, item.Key);
len += SerializeObject(stream, item.Value);
paramLen++;
}
long newPosition = stream.Position;
stream.Position = oldPosition;
stream.Write(TouchSocketBitConverter.Default.GetBytes(paramLen));
stream.Position = newPosition;
}
return len;
}
private static int SerializeIListOrArray(ByteBlock stream, IEnumerable param)
{
int len = 0;
if (param != null)
{
long oldPosition = stream.Position;
stream.Position += 4;
len += 4;
uint paramLen = 0;
foreach (object item in param)
{
paramLen++;
len += SerializeObject(stream, item);
}
long newPosition = stream.Position;
stream.Position = oldPosition;
stream.Write(TouchSocketBitConverter.Default.GetBytes(paramLen));
stream.Position = newPosition;
}
return len;
}
private static int SerializeObject<T>(ByteBlock byteBlock, T graph)
{
int len = 0;
byte[] data = null;
long startPosition = byteBlock.Position;
long endPosition;
if (graph != null)
{
Type type = graph.GetType();
if (type.IsPrimitive)
{
switch (graph)
{
case byte value:
{
data = new byte[] { value };
break;
}
case sbyte value:
{
data = TouchSocketBitConverter.Default.GetBytes(value);
break;
}
case bool value:
{
data = TouchSocketBitConverter.Default.GetBytes(value);
break;
}
case short value:
{
data = TouchSocketBitConverter.Default.GetBytes(value);
break;
}
case ushort value:
{
data = TouchSocketBitConverter.Default.GetBytes(value);
break;
}
case int value:
{
data = TouchSocketBitConverter.Default.GetBytes(value);
break;
}
case uint value:
{
data = TouchSocketBitConverter.Default.GetBytes(value);
break;
}
case long value:
{
data = TouchSocketBitConverter.Default.GetBytes(value);
break;
}
case ulong value:
{
data = TouchSocketBitConverter.Default.GetBytes(value);
break;
}
case float value:
{
data = TouchSocketBitConverter.Default.GetBytes(value);
break;
}
case double value:
{
data = TouchSocketBitConverter.Default.GetBytes(value);
break;
}
case char value:
{
data = TouchSocketBitConverter.Default.GetBytes(value);
break;
}
default:
{
throw new Exception("未知基础类型");
}
}
}
else
{
switch (graph)
{
case string value:
{
data = Encoding.UTF8.GetBytes(value);
break;
}
case DateTime value:
{
data = TouchSocketBitConverter.Default.GetBytes(value.Ticks);
break;
}
case Enum _:
{
var enumValType = Enum.GetUnderlyingType(type);
if (enumValType == TouchSocketCoreUtility.byteType)
{
data = new byte[] { Convert.ToByte(graph) };
}
else if (enumValType == TouchSocketCoreUtility.shortType)
{
data = TouchSocketBitConverter.Default.GetBytes(Convert.ToInt16(graph));
}
else if (enumValType == TouchSocketCoreUtility.intType)
{
data = TouchSocketBitConverter.Default.GetBytes(Convert.ToInt32(graph));
}
else
{
data = TouchSocketBitConverter.Default.GetBytes(Convert.ToInt64(graph));
}
break;
}
case byte[] value:
{
data = value;
break;
}
default:
{
byteBlock.Position += 4;
var serializeObj = GetOrAddInstance(type);
if (serializeObj.Converter != null)
{
len += serializeObj.Converter.Write(byteBlock, graph);
}
else
{
switch (serializeObj.InstanceType)
{
case InstanceType.List:
len += SerializeIListOrArray(byteBlock, (IEnumerable)graph);
break;
case InstanceType.Array:
len += SerializeIListOrArray(byteBlock, (IEnumerable)graph);
break;
case InstanceType.Dictionary:
len += SerializeDictionary(byteBlock, (IEnumerable)graph);
break;
default:
case InstanceType.Class:
len += SerializeClass(byteBlock, graph, type);
break;
}
}
break;
}
}
}
if (data != null)
{
len = data.Length;
endPosition = len + startPosition + 4;
}
else
{
endPosition = byteBlock.Position;
}
}
else
{
endPosition = startPosition + 4;
}
byte[] lenBuffer = TouchSocketBitConverter.Default.GetBytes(len);
byteBlock.Position = startPosition;
byteBlock.Write(lenBuffer, 0, lenBuffer.Length);
if (data != null)
{
byteBlock.Write(data, 0, data.Length);
}
byteBlock.Position = endPosition;
return len + 4;
}
#endregion Serialize
#region Deserialize
/// <summary>
/// 反序列化
/// </summary>
/// <param name="data"></param>
/// <param name="offset"></param>
/// <param name="type"></param>
/// <returns></returns>
public static object Deserialize(byte[] data, int offset, Type type)
{
if (data[offset] != 1)
{
throw new Exception("Fast反序列化数据流解析错误。");
}
offset += 1;
return Deserialize(type, data, ref offset);
}
private static object Deserialize(Type type, byte[] datas, ref int offset)
{
bool nullable = type.IsNullableType();
if (nullable)
{
type = type.GenericTypeArguments[0];
}
dynamic obj;
int len = TouchSocketBitConverter.Default.ToInt32(datas, offset);
offset += 4;
if (len > 0)
{
if (type == TouchSocketCoreUtility.stringType)
{
obj = Encoding.UTF8.GetString(datas, offset, len);
}
else if (type == TouchSocketCoreUtility.byteType)
{
obj = datas[offset];
}
else if (type == TouchSocketCoreUtility.sbyteType)
{
obj = (sbyte)(TouchSocketBitConverter.Default.ToInt16(datas, offset));
}
else if (type == TouchSocketCoreUtility.boolType)
{
obj = (TouchSocketBitConverter.Default.ToBoolean(datas, offset));
}
else if (type == TouchSocketCoreUtility.shortType)
{
obj = (TouchSocketBitConverter.Default.ToInt16(datas, offset));
}
else if (type == TouchSocketCoreUtility.ushortType)
{
obj = (TouchSocketBitConverter.Default.ToUInt16(datas, offset));
}
else if (type == TouchSocketCoreUtility.intType)
{
obj = (TouchSocketBitConverter.Default.ToInt32(datas, offset));
}
else if (type == TouchSocketCoreUtility.uintType)
{
obj = (TouchSocketBitConverter.Default.ToUInt32(datas, offset));
}
else if (type == TouchSocketCoreUtility.longType)
{
obj = (TouchSocketBitConverter.Default.ToInt64(datas, offset));
}
else if (type == TouchSocketCoreUtility.ulongType)
{
obj = (TouchSocketBitConverter.Default.ToUInt64(datas, offset));
}
else if (type == TouchSocketCoreUtility.floatType)
{
obj = (TouchSocketBitConverter.Default.ToSingle(datas, offset));
}
else if (type == TouchSocketCoreUtility.doubleType)
{
obj = (TouchSocketBitConverter.Default.ToDouble(datas, offset));
}
else if (type == TouchSocketCoreUtility.decimalType)
{
obj = (TouchSocketBitConverter.Default.ToDouble(datas, offset));
}
else if (type == TouchSocketCoreUtility.charType)
{
obj = (TouchSocketBitConverter.Default.ToChar(datas, offset));
}
else if (type == TouchSocketCoreUtility.dateTimeType)
{
obj = (new DateTime(TouchSocketBitConverter.Default.ToInt64(datas, offset)));
}
else if (type.BaseType == typeof(Enum))
{
Type enumType = Enum.GetUnderlyingType(type);
if (enumType == typeof(byte))
{
obj = Enum.ToObject(type, datas[offset]);
}
else if (enumType == typeof(short))
{
obj = Enum.ToObject(type, TouchSocketBitConverter.Default.ToInt16(datas, offset));
}
else if (enumType == typeof(int))
{
obj = Enum.ToObject(type, TouchSocketBitConverter.Default.ToInt32(datas, offset));
}
else
{
obj = Enum.ToObject(type, TouchSocketBitConverter.Default.ToInt64(datas, offset));
}
}
else if (type == TouchSocketCoreUtility.bytesType)
{
byte[] data = new byte[len];
Buffer.BlockCopy(datas, offset, data, 0, len);
obj = data;
}
else if (type.IsClass || type.IsStruct())
{
var serializeObj = GetOrAddInstance(type);
if (serializeObj.Converter != null)
{
obj = serializeObj.Converter.Read(datas, offset, len);
}
else
{
obj = DeserializeClass(type, datas, offset, len);
}
}
else
{
throw new Exception("未定义的类型:" + type.ToString());
}
}
else
{
if (nullable)
{
obj = null;
}
else
{
obj = type.GetDefault();
}
}
offset += len;
return obj;
}
private static object DeserializeClass(Type type, byte[] datas, int offset, int length)
{
SerializObject serializObject = GetOrAddInstance(type);
object instance;
switch (serializObject.InstanceType)
{
case InstanceType.Class:
{
instance = serializObject.GetNewInstance();
int index = offset;
while (offset - index < length && (length >= 4))
{
int len = datas[offset];
string propertyName = Encoding.UTF8.GetString(datas, offset + 1, len);
offset += len + 1;
if (serializObject.IsStruct)
{
if (serializObject.PropertiesDic.ContainsKey(propertyName))
{
PropertyInfo property = serializObject.PropertiesDic[propertyName];
object obj = Deserialize(property.PropertyType, datas, ref offset);
property.SetValue(instance, obj);
}
else if (serializObject.FieldInfosDic.ContainsKey(propertyName))
{
FieldInfo property = serializObject.FieldInfosDic[propertyName];
object obj = Deserialize(property.FieldType, datas, ref offset);
property.SetValue(instance, obj);
}
else
{
int pLen = TouchSocketBitConverter.Default.ToInt32(datas, offset);
offset += 4;
offset += pLen;
}
}
else
{
if (serializObject.PropertiesDic.TryGetValue(propertyName, out PropertyInfo property))
{
object obj = Deserialize(property.PropertyType, datas, ref offset);
serializObject.MemberAccessor.SetValue(instance, property.Name, obj);
}
else if (serializObject.FieldInfosDic.TryGetValue(propertyName, out FieldInfo fieldInfo))
{
object obj = Deserialize(fieldInfo.FieldType, datas, ref offset);
serializObject.MemberAccessor.SetValue(instance, fieldInfo.Name, obj);
}
else
{
int pLen = TouchSocketBitConverter.Default.ToInt32(datas, offset);
offset += 4;
offset += pLen;
}
}
}
break;
}
case InstanceType.List:
{
instance = serializObject.GetNewInstance();
if (length > 0)
{
uint paramLen = TouchSocketBitConverter.Default.ToUInt32(datas, offset);
offset += 4;
for (uint i = 0; i < paramLen; i++)
{
object obj = Deserialize(serializObject.ArgTypes[0], datas, ref offset);
serializObject.AddMethod.Invoke(instance, new object[] { obj });
}
}
else
{
instance = null;
}
break;
}
case InstanceType.Array:
{
if (length > 0)
{
uint paramLen = TouchSocketBitConverter.Default.ToUInt32(datas, offset);
Array array = Array.CreateInstance(serializObject.ArrayType, paramLen);
offset += 4;
for (uint i = 0; i < paramLen; i++)
{
object obj = Deserialize(serializObject.ArrayType, datas, ref offset);
array.SetValue(obj, i);
}
instance = array;
}
else
{
instance = null;
}
break;
}
case InstanceType.Dictionary:
{
instance = serializObject.GetNewInstance();
if (length > 0)
{
uint paramLen = TouchSocketBitConverter.Default.ToUInt32(datas, offset);
offset += 4;
for (uint i = 0; i < paramLen; i++)
{
object key = Deserialize(serializObject.ArgTypes[0], datas, ref offset);
object value = Deserialize(serializObject.ArgTypes[1], datas, ref offset);
if (key != null)
{
serializObject.AddMethod.Invoke(instance, new object[] { key, value });
}
}
//uint paramLen = TouchSocketBitConverter.Default.ToUInt32(datas, offset);
//offset += 4;
//for (uint i = 0; i < paramLen; i++)
//{
// offset += 4;
// offset += datas[offset] + 1;
// object key = this.Deserialize(instanceObject.ArgTypes[0], datas, ref offset);
// offset += datas[offset] + 1;
// object value = this.Deserialize(instanceObject.ArgTypes[1], datas, ref offset);
// if (key != null)
// {
// instanceObject.AddMethod.Invoke(instance, new object[] { key, value });
// }
//}
}
else
{
instance = null;
}
break;
}
default:
instance = null;
break;
}
return instance;
}
#endregion Deserialize
private static SerializObject GetOrAddInstance(Type type)
{
if (m_instanceCache.TryGetValue(type, out SerializObject instance))
{
return instance;
}
if (type.IsArray)//数组
{
SerializObject instanceObject = new SerializObject(type);
m_instanceCache.TryAdd(type, instanceObject);
return instanceObject;
}
else if (type.IsClass || type.IsStruct())
{
if (type.IsNullableType())
{
type = type.GetGenericArguments()[0];
}
SerializObject instanceObject = new SerializObject(type);
m_instanceCache.TryAdd(type, instanceObject);
return instanceObject;
}
return null;
}
}
}