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