using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using UnityEngine;
namespace UnityEngine.AddressableAssets.Utility
{
internal static class SerializationUtilities
{
internal enum ObjectType
{
AsciiString,
UnicodeString,
UInt16,
UInt32,
Int32,
Hash128,
Type,
JsonObject
}
internal static int ReadInt32FromByteArray(byte[] data, int offset)
{
return data[offset] | (data[offset + 1] << 8) | (data[offset + 2] << 16) | (data[offset + 3] << 24);
}
internal static int WriteInt32ToByteArray(byte[] data, int val, int offset)
{
data[offset] = (byte)(val & 0xFF);
data[offset + 1] = (byte)((val >> 8) & 0xFF);
data[offset + 2] = (byte)((val >> 16) & 0xFF);
data[offset + 3] = (byte)((val >> 24) & 0xFF);
return offset + 4;
}
/*
internal static ushort ReadUInt16FromByteArray(byte[] data, int offset)
{
return (ushort)(data[offset] | (data[offset + 1] << 8));
}
internal static int WriteUInt16ToByteArray(byte[] data, ushort val, int offset)
{
data[offset] = (byte)(val & 0xFF);
data[offset + 1] = (byte)((val >> 8) & 0xFF);
return offset + 2;
}*/
///
/// Deserializes an object from an array at a specified index. Supported types are ASCIIString, UnicodeString, UInt16, UInt32, Int32, Hash128, JsonObject
///
/// The array of bytes for the object. The first byte is the ObjectType. The rest depends on the type.
/// The index of the first byte of the data.
/// The deserialized object.
internal static object ReadObjectFromByteArray(byte[] keyData, int dataIndex)
{
try
{
ObjectType keyType = (ObjectType)keyData[dataIndex];
dataIndex++;
switch (keyType)
{
case ObjectType.UnicodeString:
{
var dataLength = BitConverter.ToInt32(keyData, dataIndex);
return Encoding.Unicode.GetString(keyData, dataIndex + 4, dataLength);
}
case ObjectType.AsciiString:
{
var dataLength = BitConverter.ToInt32(keyData, dataIndex);
return Encoding.ASCII.GetString(keyData, dataIndex + 4, dataLength);
}
case ObjectType.UInt16: return BitConverter.ToUInt16(keyData, dataIndex);
case ObjectType.UInt32: return BitConverter.ToUInt32(keyData, dataIndex);
case ObjectType.Int32: return BitConverter.ToInt32(keyData, dataIndex);
case ObjectType.Hash128: return Hash128.Parse(Encoding.ASCII.GetString(keyData, dataIndex + 1, keyData[dataIndex]));
case ObjectType.Type: return Type.GetTypeFromCLSID(new Guid(Encoding.ASCII.GetString(keyData, dataIndex + 1, keyData[dataIndex])));
case ObjectType.JsonObject:
{
int assemblyNameLength = keyData[dataIndex];
dataIndex++;
string assemblyName = Encoding.ASCII.GetString(keyData, dataIndex, assemblyNameLength);
dataIndex += assemblyNameLength;
int classNameLength = keyData[dataIndex];
dataIndex++;
string className = Encoding.ASCII.GetString(keyData, dataIndex, classNameLength);
dataIndex += classNameLength;
int jsonLength = BitConverter.ToInt32(keyData, dataIndex);
dataIndex += 4;
string jsonText = Encoding.Unicode.GetString(keyData, dataIndex, jsonLength);
var assembly = Assembly.Load(assemblyName);
var t = assembly.GetType(className);
return JsonUtility.FromJson(jsonText, t);
}
}
}
catch (Exception ex)
{
Debug.LogException(ex);
}
return null;
}
///
/// Write an object to a byte array
///
/// The object to write.
/// The list of bytes to write to.
/// The number of bytes written.
internal static int WriteObjectToByteList(object obj, List buffer)
{
var objectType = obj.GetType();
if (objectType == typeof(string))
{
string str = obj as string;
if (str == null)
str = string.Empty;
byte[] tmp = Encoding.Unicode.GetBytes(str);
byte[] tmp2 = Encoding.ASCII.GetBytes(str);
if (Encoding.Unicode.GetString(tmp) == Encoding.ASCII.GetString(tmp2))
{
buffer.Add((byte)ObjectType.AsciiString);
buffer.AddRange(BitConverter.GetBytes(tmp2.Length));
buffer.AddRange(tmp2);
return tmp2.Length + 5;
}
buffer.Add((byte)ObjectType.UnicodeString);
buffer.AddRange(BitConverter.GetBytes(tmp.Length));
buffer.AddRange(tmp);
return tmp.Length + 5;
}
if (objectType == typeof(UInt32))
{
byte[] tmp = BitConverter.GetBytes((UInt32)obj);
buffer.Add((byte)ObjectType.UInt32);
buffer.AddRange(tmp);
return tmp.Length + 1;
}
if (objectType == typeof(UInt16))
{
byte[] tmp = BitConverter.GetBytes((UInt16)obj);
buffer.Add((byte)ObjectType.UInt16);
buffer.AddRange(tmp);
return tmp.Length + 1;
}
if (objectType == typeof(Int32))
{
byte[] tmp = BitConverter.GetBytes((Int32)obj);
buffer.Add((byte)ObjectType.Int32);
buffer.AddRange(tmp);
return tmp.Length + 1;
}
if (objectType == typeof(int))
{
byte[] tmp = BitConverter.GetBytes((UInt32)obj);
buffer.Add((byte)ObjectType.UInt32);
buffer.AddRange(tmp);
return tmp.Length + 1;
}
if (objectType == typeof(Hash128))
{
var guid = (Hash128)obj;
byte[] tmp = Encoding.ASCII.GetBytes(guid.ToString());
buffer.Add((byte)ObjectType.Hash128);
buffer.Add((byte)tmp.Length);
buffer.AddRange(tmp);
return tmp.Length + 2;
}
if (objectType == typeof(Type))
{
byte[] tmp = objectType.GUID.ToByteArray();
buffer.Add((byte)ObjectType.Type);
buffer.Add((byte)tmp.Length);
buffer.AddRange(tmp);
return tmp.Length + 2;
}
var attrs = objectType.GetCustomAttributes(typeof(SerializableAttribute), true);
if (attrs.Length == 0)
return 0;
int length = 0;
buffer.Add((byte)ObjectType.JsonObject);
length++;
//write assembly name
byte[] tmpAssemblyName = Encoding.ASCII.GetBytes(objectType.Assembly.FullName);
buffer.Add((byte)tmpAssemblyName.Length);
length++;
buffer.AddRange(tmpAssemblyName);
length += tmpAssemblyName.Length;
//write class name
var objName = objectType.FullName;
if (objName == null)
objName = string.Empty;
byte[] tmpClassName = Encoding.ASCII.GetBytes(objName);
buffer.Add((byte)tmpClassName.Length);
length++;
buffer.AddRange(tmpClassName);
length += tmpClassName.Length;
//write json data
byte[] tmpJson = Encoding.Unicode.GetBytes(JsonUtility.ToJson(obj));
buffer.AddRange(BitConverter.GetBytes(tmpJson.Length));
length += 4;
buffer.AddRange(tmpJson);
length += tmpJson.Length;
return length;
}
}
}