Files
dungeons/Assets/UltimateXR/Runtime/Scripts/Extensions/System/IO/BinaryReaderExt.cs
2024-08-06 21:58:35 +02:00

1162 lines
47 KiB
C#

// --------------------------------------------------------------------------------------------------------------------
// <copyright file="BinaryReaderExt.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using UltimateXR.Core.Math;
using UltimateXR.Core.Serialization;
using UltimateXR.Core.Unique;
using UltimateXR.Exceptions;
using UnityEngine;
namespace UltimateXR.Extensions.System.IO
{
/// <summary>
/// <see cref="BinaryReader" /> extensions.
/// </summary>
public static class BinaryReaderExt
{
#region Public Methods
/// <summary>
/// Reads a 32-bit integer in compressed format, using only the amount of bytes that are necessary.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>A 32-bit integer</returns>
/// <exception cref="FormatException">The compressed data is corrupt</exception>
public static int ReadCompressedInt32(this BinaryReader reader, int serializationVersion)
{
return (int)ReadCompressedUInt32(reader, serializationVersion);
}
/// <summary>
/// Reads a 32-bit unsigned integer in compressed format, using only the amount of bytes that are necessary.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>A 32-bit unsigned integer</returns>
/// <exception cref="FormatException">The compressed data is corrupt</exception>
public static uint ReadCompressedUInt32(this BinaryReader reader, int serializationVersion)
{
uint num1 = 0;
int num2 = 0;
while (num2 != 35)
{
byte num3 = reader.ReadByte();
num1 |= (uint)(num3 & sbyte.MaxValue) << num2;
num2 += 7;
if ((num3 & 128) == 0)
{
return num1;
}
}
throw new FormatException("ReadCompressedInt32()/ReadCompressedUInt32() found bad format");
}
/// <summary>
/// Reads a 64-bit integer in compressed format, using only the amount of bytes that are necessary.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>A 64-bit integer</returns>
/// <exception cref="FormatException">The compressed data is corrupt</exception>
public static long ReadCompressedInt64(this BinaryReader reader, int serializationVersion)
{
return (long)ReadCompressedUInt64(reader, serializationVersion);
}
/// <summary>
/// Reads a 64-bit unsigned integer in compressed format, using only the amount of bytes that are necessary.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>A 64-bit unsigned integer</returns>
/// <exception cref="FormatException">The compressed data is corrupt</exception>
public static ulong ReadCompressedUInt64(this BinaryReader reader, int serializationVersion)
{
ulong num1 = 0;
int num2 = 0;
while (num2 != 63)
{
byte num3 = reader.ReadByte();
num1 |= (ulong)(num3 & sbyte.MaxValue) << num2;
num2 += 7;
if ((num3 & 128) == 0)
{
return num1;
}
}
throw new FormatException("ReadCompressedInt64()/ReadCompressedUInt64() found bad format");
}
/// <summary>
/// Reads an enum value.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>Enum object</returns>
public static T ReadEnum<T>(this BinaryReader reader, int serializationVersion)
{
return (T)Enum.ToObject(typeof(T), reader.ReadCompressedInt32(serializationVersion));
}
/// <summary>
/// Reads a string written using <see cref="BinaryWriterExt.WriteStringWithNullCheck" />.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>String or null</returns>
public static string ReadStringWithNullCheck(this BinaryReader reader)
{
// Serialized as: null-check (bool), string
bool nullCheck = reader.ReadBoolean();
if (!nullCheck)
{
return null;
}
return reader.ReadString();
}
/// <summary>
/// Reads a type, which has been serialized as two strings: the full type name plus the assembly. If the type is from
/// the same assembly as UltimateXR, the assembly will be an empty string.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>The type</returns>
public static Type ReadType(this BinaryReader reader, int serializationVersion)
{
return reader.ReadType(serializationVersion, out string _, out string _);
}
/// <summary>
/// Reads a type, which has been serialized as two strings: the full type name plus the assembly. If the type is from
/// the same assembly as UltimateXR, the assembly will be an empty string.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <param name="typeName">Returns the type name</param>
/// <param name="assembly">Returns the type assembly or null/empty if the type is in the same assembly as UltimateXR</param>
/// <returns>The type</returns>
public static Type ReadType(this BinaryReader reader, int serializationVersion, out string typeName, out string assembly)
{
typeName = reader.ReadString();
if (typeName != string.Empty)
{
assembly = reader.ReadString();
return TypeExt.GetType(typeName, assembly);
}
assembly = string.Empty;
return null;
}
/// <summary>
/// Reads a Guid, which has been serialized as a 16 byte array.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>The Guid</returns>
public static Guid ReadGuid(this BinaryReader reader, int serializationVersion)
{
return new Guid(reader.ReadBytes(16));
}
/// <summary>
/// Reads a tuple.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>The tuple</returns>
public static (T1, T2) ReadTuple<T1, T2>(this BinaryReader reader, int serializationVersion)
{
return ((T1, T2))(reader.Read<T1>(serializationVersion), reader.Read<T2>(serializationVersion));
}
/// <summary>
/// Reads an array.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <typeparam name="T">The type of elements in the array</typeparam>
/// <returns>The array</returns>
/// <exception cref="ArgumentOutOfRangeException">A type is not supported</exception>
/// <exception cref="FormatException">The compressed data is corrupt</exception>
/// <exception cref="UxrComponentNotFoundException">An <see cref="IUxrUniqueId" /> was not found when deserializing</exception>
/// <exception cref="UxrSerializableClassNotFoundException">
/// A class that implements the <see cref="IUxrSerializable" />
/// interface was not found when deserializing
/// </exception>
public static T[] ReadArray<T>(this BinaryReader reader, int serializationVersion)
{
// Serialized as: null-check (bool), count (int32), elements
bool nullCheck = reader.ReadBoolean();
if (!nullCheck)
{
return null;
}
T[] array = new T[reader.ReadCompressedInt32(serializationVersion)];
for (int i = 0; i < array.Length; ++i)
{
array[i] = (T)reader.Read<T>(serializationVersion);
}
return array;
}
/// <summary>
/// Reads an array of objects where each element can be of a different type.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>The object array</returns>
/// <exception cref="ArgumentOutOfRangeException">A type is not supported</exception>
/// <exception cref="FormatException">The compressed data is corrupt</exception>
/// <exception cref="UxrComponentNotFoundException">An <see cref="IUxrUniqueId" /> was not found when deserializing</exception>
/// <exception cref="UxrSerializableClassNotFoundException">
/// A class that implements the <see cref="IUxrSerializable" />
/// interface was not found when deserializing
/// </exception>
public static object[] ReadObjectArray(this BinaryReader reader, int serializationVersion)
{
// Serialized as: null-check (bool), count (int32), elements
bool nullCheck = reader.ReadBoolean();
if (!nullCheck)
{
return null;
}
object[] array = new object[reader.ReadCompressedInt32(serializationVersion)];
Exception firstException = null;
for (int i = 0; i < array.Length; ++i)
{
try
{
array[i] = reader.ReadAnyVar(serializationVersion);
}
catch (Exception e)
{
if (firstException == null)
{
firstException = e;
}
}
}
if (firstException != null)
{
// This helps debugging UxrMethodInvokedSyncEventArgs. We keep deserializing event parameters even if there are errors.
throw firstException;
}
return array;
}
/// <summary>
/// Reads a list.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <typeparam name="T">The type of elements in the list</typeparam>
/// <returns>The list</returns>
/// <exception cref="ArgumentOutOfRangeException">A type is not supported</exception>
/// <exception cref="FormatException">The compressed data is corrupt</exception>
/// <exception cref="UxrComponentNotFoundException">An <see cref="IUxrUniqueId" /> was not found when deserializing</exception>
/// <exception cref="UxrSerializableClassNotFoundException">
/// A class that implements the <see cref="IUxrSerializable" />
/// interface was not found when deserializing
/// </exception>
public static List<T> ReadList<T>(this BinaryReader reader, int serializationVersion)
{
// Serialized as: null-check (bool), count (int32), elements
bool nullCheck = reader.ReadBoolean();
if (!nullCheck)
{
return null;
}
List<T> list = new List<T>();
int count = reader.ReadCompressedInt32(serializationVersion);
for (int i = 0; i < count; ++i)
{
list.Add((T)reader.Read<T>(serializationVersion));
}
return list;
}
/// <summary>
/// Reads a list of objects where each element can be of a different type.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>The list</returns>
/// <exception cref="ArgumentOutOfRangeException">A type is not supported</exception>
/// <exception cref="FormatException">The compressed data is corrupt</exception>
/// <exception cref="UxrComponentNotFoundException">An <see cref="IUxrUniqueId" /> was not found when deserializing</exception>
/// <exception cref="UxrSerializableClassNotFoundException">
/// A class that implements the <see cref="IUxrSerializable" />
/// interface was not found when deserializing
/// </exception>
public static List<object> ReadObjectList(this BinaryReader reader, int serializationVersion)
{
// Serialized as: null-check (bool), count (int32), elements
bool nullCheck = reader.ReadBoolean();
if (!nullCheck)
{
return null;
}
List<object> list = new List<object>();
int count = reader.ReadCompressedInt32(serializationVersion);
for (int i = 0; i < count; ++i)
{
list.Add(reader.ReadAnyVar(serializationVersion));
}
return list;
}
/// <summary>
/// Reads a dictionary.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>The dictionary</returns>
/// <exception cref="ArgumentOutOfRangeException">A type is not supported</exception>
/// <exception cref="FormatException">The compressed data is corrupt</exception>
/// <exception cref="UxrComponentNotFoundException">An <see cref="IUxrUniqueId" /> was not found when deserializing</exception>
/// <exception cref="UxrSerializableClassNotFoundException">
/// A class that implements the <see cref="IUxrSerializable" />
/// interface was not found when deserializing
/// </exception>
public static Dictionary<TKey, TValue> ReadDictionary<TKey, TValue>(this BinaryReader reader, int serializationVersion)
{
// Serialized as: null-check (bool), count (int32), elements
bool nullCheck = reader.ReadBoolean();
if (!nullCheck)
{
return null;
}
Dictionary<TKey, TValue> dictionary = new Dictionary<TKey, TValue>();
int count = reader.ReadCompressedInt32(serializationVersion);
for (int i = 0; i < count; ++i)
{
TKey key = (TKey)reader.Read<TKey>(serializationVersion);
TValue value = (TValue)reader.Read<TValue>(serializationVersion);
dictionary.Add(key, value);
}
return dictionary;
}
/// <summary>
/// Reads a HashSet.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <typeparam name="T">The type of elements in the HashSet</typeparam>
/// <returns>The hash set</returns>
/// <exception cref="ArgumentOutOfRangeException">A type is not supported</exception>
/// <exception cref="FormatException">The compressed data is corrupt</exception>
/// <exception cref="UxrComponentNotFoundException">An <see cref="IUxrUniqueId" /> was not found when deserializing</exception>
/// <exception cref="UxrSerializableClassNotFoundException">
/// A class that implements the <see cref="IUxrSerializable" />
/// interface was not found when deserializing
/// </exception>
public static HashSet<T> ReadHashSet<T>(this BinaryReader reader, int serializationVersion)
{
// Serialized as: null-check (bool), count (int32), elements
bool nullCheck = reader.ReadBoolean();
if (!nullCheck)
{
return null;
}
HashSet<T> hashSet = new HashSet<T>();
int count = reader.ReadCompressedInt32(serializationVersion);
for (int i = 0; i < count; ++i)
{
hashSet.Add((T)reader.Read<T>(serializationVersion));
}
return hashSet;
}
/// <summary>
/// Reads a hash set of objects where each element can be of a different type.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>The hash set</returns>
/// <exception cref="ArgumentOutOfRangeException">A type is not supported</exception>
/// <exception cref="FormatException">The compressed data is corrupt</exception>
/// <exception cref="UxrComponentNotFoundException">An <see cref="IUxrUniqueId" /> was not found when deserializing</exception>
/// <exception cref="UxrSerializableClassNotFoundException">
/// A class that implements the <see cref="IUxrSerializable" />
/// interface was not found when deserializing
/// </exception>
public static HashSet<object> ReadObjectHashSet(this BinaryReader reader, int serializationVersion)
{
// Serialized as: null-check (bool), count (int32), elements
bool nullCheck = reader.ReadBoolean();
if (!nullCheck)
{
return null;
}
HashSet<object> hashSet = new HashSet<object>();
int count = reader.ReadCompressedInt32(serializationVersion);
for (int i = 0; i < count; ++i)
{
hashSet.Add(reader.ReadAnyVar(serializationVersion));
}
return hashSet;
}
/// <summary>
/// Reads a <see cref="DateTime" />.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>DateTime</returns>
public static DateTime ReadDateTime(this BinaryReader reader, int serializationVersion)
{
// Read ticks (64 bits)
return new DateTime(reader.ReadCompressedInt64(serializationVersion));
}
/// <summary>
/// Reads a <see cref="TimeSpan" />.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>TimeSpan</returns>
public static TimeSpan ReadTimeSpan(this BinaryReader reader, int serializationVersion)
{
// Read ticks (64 bits)
return new TimeSpan(reader.ReadCompressedInt64(serializationVersion));
}
/// <summary>
/// Reads a <see cref="Vector2" />.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>Vector</returns>
public static Vector2 ReadVector2(this BinaryReader reader, int serializationVersion)
{
return new Vector2(reader.ReadSingle(), reader.ReadSingle());
}
/// <summary>
/// Reads a <see cref="Vector3" />.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>Vector</returns>
public static Vector3 ReadVector3(this BinaryReader reader, int serializationVersion)
{
return new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
}
/// <summary>
/// Reads a <see cref="Vector4" />.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>Vector</returns>
public static Vector4 ReadVector4(this BinaryReader reader, int serializationVersion)
{
return new Vector4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
}
/// <summary>
/// Reads a <see cref="Color" />.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>Color</returns>
public static Color ReadColor(this BinaryReader reader, int serializationVersion)
{
return new Color(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
}
/// <summary>
/// Reads a <see cref="Color32" />.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>Color32</returns>
public static Color32 ReadColor32(this BinaryReader reader, int serializationVersion)
{
return new Color32(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
}
/// <summary>
/// Reads a <see cref="Quaternion" />.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>Quaternion</returns>
public static Quaternion ReadQuaternion(this BinaryReader reader, int serializationVersion)
{
return new Quaternion(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
}
/// <summary>
/// Reads a <see cref="Matrix4x4" />.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>Matrix</returns>
public static Matrix4x4 ReadMatrix(this BinaryReader reader, int serializationVersion)
{
Matrix4x4 matrix;
matrix.m00 = reader.ReadSingle();
matrix.m10 = reader.ReadSingle();
matrix.m20 = reader.ReadSingle();
matrix.m30 = reader.ReadSingle();
matrix.m01 = reader.ReadSingle();
matrix.m11 = reader.ReadSingle();
matrix.m21 = reader.ReadSingle();
matrix.m31 = reader.ReadSingle();
matrix.m02 = reader.ReadSingle();
matrix.m12 = reader.ReadSingle();
matrix.m22 = reader.ReadSingle();
matrix.m32 = reader.ReadSingle();
matrix.m03 = reader.ReadSingle();
matrix.m13 = reader.ReadSingle();
matrix.m23 = reader.ReadSingle();
matrix.m33 = reader.ReadSingle();
return matrix;
}
/// <summary>
/// Reads a component that implements <see cref="IUxrUniqueId" />. Only the unique ID (string) will be read.
/// The component will be retrieved using the ID with <see cref="UxrUniqueIdImplementer.TryGetComponentById" />.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>Component that implements the <see cref="IUxrUniqueId" /> interface</returns>
/// <exception cref="UxrComponentNotFoundException">The given component could not be found using the Id</exception>
public static IUxrUniqueId ReadUniqueComponent(this BinaryReader reader, int serializationVersion)
{
// Serialized as: null-check (bool), Guid
bool nullCheck = reader.ReadBoolean();
if (!nullCheck)
{
return null;
}
Guid componentId = reader.ReadGuid(serializationVersion);
if (componentId == default)
{
return null;
}
if (UxrUniqueIdImplementer.TryGetComponentById(componentId, out IUxrUniqueId component))
{
return component;
}
throw new UxrComponentNotFoundException(componentId);
}
/// <summary>
/// Reads a component that implements <see cref="IUxrUniqueId" />. Only the unique ID (string) will be read.
/// The component will be retrieved using the ID with <see cref="UxrUniqueIdImplementer.TryGetComponentById" />.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>Component that implements the <see cref="IUxrUniqueId" /> interface</returns>
/// <exception cref="UxrComponentNotFoundException">The given component could not be found using the Id</exception>
public static T ReadUniqueComponent<T>(this BinaryReader reader, int serializationVersion) where T : Component, IUxrUniqueId
{
return ReadUniqueComponent(reader, serializationVersion) as T;
}
/// <summary>
/// Reads an object that implements the <see cref="IUxrSerializable" /> interface. It has support for null references.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>Object with the IUxrSerializable interface, which can be casted to the correct type</returns>
/// <exception cref="ArgumentOutOfRangeException">A type is not supported</exception>
/// <exception cref="FormatException">The compressed data is corrupt</exception>
/// <exception cref="UxrComponentNotFoundException">An <see cref="IUxrUniqueId" /> was not found when deserializing</exception>
/// <exception cref="UxrSerializableClassNotFoundException">
/// A class that implements the <see cref="IUxrSerializable" />
/// interface was not found when deserializing
/// </exception>
public static IUxrSerializable ReadUxrSerializable(this BinaryReader reader, int serializationVersion)
{
bool hasData = reader.ReadBoolean();
if (!hasData)
{
return null;
}
int version = reader.ReadCompressedInt32(serializationVersion);
Type type = reader.ReadType(serializationVersion, out string typeName, out string assemblyName);
object newObject = type != null ? FormatterServices.GetUninitializedObject(type) : null;
if (newObject == null)
{
throw new UxrSerializableClassNotFoundException(typeName, assemblyName, $"GetUninitializedObject({TypeExt.GetTypeString(typeName, assemblyName)}) returned null");
}
if (newObject is IUxrSerializable serializable)
{
serializable.Serialize(new UxrBinarySerializer(reader, serializationVersion), version);
return serializable;
}
throw new UxrSerializableClassNotFoundException(typeName, assemblyName, $"Object {typeName} does not implement {nameof(IUxrSerializable)} interface");
}
/// <summary>
/// Reads an object that implements the <see cref="IUxrSerializable" /> interface. It has support for null references.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>Object with the IUxrSerializable interface, which can be casted to the correct type</returns>
/// <exception cref="ArgumentOutOfRangeException">A type is not supported</exception>
/// <exception cref="FormatException">The compressed data is corrupt</exception>
/// <exception cref="UxrComponentNotFoundException">An <see cref="IUxrUniqueId" /> was not found when deserializing</exception>
/// <exception cref="UxrSerializableClassNotFoundException">
/// A class that implements the <see cref="IUxrSerializable" />
/// interface was not found when deserializing
/// </exception>
/// <exception cref="InvalidCastException">
/// Failed to cast the value to <see cref="IUxrSerializable"/>.
/// </exception>
public static T ReadUxrSerializable<T>(this BinaryReader reader, int serializationVersion) where T : IUxrSerializable
{
IUxrSerializable serializable = ReadUxrSerializable(reader, serializationVersion);
if (serializable is T typedSerializable)
{
return typedSerializable;
}
throw new InvalidCastException($"Failed to cast {typeof(T).Name} to {nameof(IUxrSerializable)}");
}
/// <summary>
/// Reads an <see cref="UxrAxis" /> value.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <returns>Axis value</returns>
/// <exception cref="ArgumentOutOfRangeException">A type is not supported</exception>
/// <exception cref="FormatException">The compressed data is corrupt</exception>
public static UxrAxis ReadAxis(this BinaryReader reader, int serializationVersion)
{
return ReadCompressedInt32(reader, serializationVersion);
}
/// <summary>
/// Reads an <see cref="object" /> supported by <see cref="UxrVarType" />. This is used together with
/// <see cref="BinaryWriterExt.WriteAnyVar" /> to serialize/deserialize variables whose type are unknown at compile
/// time.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <param name="varType">Returns the type of the object found, or <see cref="UxrVarType.Unknown" /></param>
/// <returns>
/// Object or null. Null can be both because the object is unsupported or the object itself is null. Check
/// <paramref name="varType" /> to tell between the two cases
/// </returns>
/// <exception cref="ArgumentOutOfRangeException">A type is not supported</exception>
/// <exception cref="FormatException">The compressed data is corrupt</exception>
/// <exception cref="UxrComponentNotFoundException">An <see cref="IUxrUniqueId" /> was not found when deserializing</exception>
/// <exception cref="UxrSerializableClassNotFoundException">
/// A class that implements the <see cref="IUxrSerializable" />
/// interface was not found when deserializing
/// </exception>
/// <exception cref="InvalidCastException">
/// Failed to cast the value to <see cref="IUxrSerializable"/>.
/// </exception>
public static object ReadAnyVar(this BinaryReader reader, int serializationVersion)
{
return reader.ReadAnyVar(serializationVersion, out UxrVarType _);
}
/// <summary>
/// Reads an <see cref="object" /> supported by <see cref="UxrVarType" />. This is used together with
/// <see cref="BinaryWriterExt.WriteAnyVar" /> to serialize/deserialize variables whose type are unknown at compile
/// time.
/// </summary>
/// <param name="reader">Reader</param>
/// <param name="serializationVersion">The serialization version, to provide backwards compatibility</param>
/// <param name="varType">Returns the type of the object found, or <see cref="UxrVarType.Unknown" /></param>
/// <returns>
/// Object or null. Null can be both because the object is unknown or the object itself is null. Check
/// <paramref name="varType" /> to tell between the two cases
/// </returns>
/// <exception cref="ArgumentOutOfRangeException">A type is not supported</exception>
/// <exception cref="FormatException">The compressed data is corrupt</exception>
/// <exception cref="UxrComponentNotFoundException">An <see cref="IUxrUniqueId" /> was not found when deserializing</exception>
/// <exception cref="UxrSerializableClassNotFoundException">
/// A class that implements the <see cref="IUxrSerializable" />
/// interface was not found when deserializing
/// </exception>
/// <exception cref="InvalidCastException">
/// Failed to cast the value to <see cref="IUxrSerializable"/>.
/// </exception>
public static object ReadAnyVar(this BinaryReader reader, int serializationVersion, out UxrVarType varType)
{
varType = (UxrVarType)reader.ReadByte();
if (varType == UxrVarType.Unknown)
{
return null;
}
if (varType is UxrVarType.Bool)
{
return reader.ReadBoolean();
}
if (varType is UxrVarType.SignedByte)
{
return reader.ReadSByte();
}
if (varType is UxrVarType.Byte)
{
return reader.ReadByte();
}
if (varType is UxrVarType.Char)
{
return reader.ReadChar();
}
if (varType is UxrVarType.Int)
{
return reader.ReadCompressedInt32(serializationVersion);
}
if (varType is UxrVarType.UnsignedInt)
{
return reader.ReadCompressedUInt32(serializationVersion);
}
if (varType is UxrVarType.Long)
{
return reader.ReadCompressedInt64(serializationVersion);
}
if (varType is UxrVarType.UnsignedLong)
{
return reader.ReadCompressedUInt64(serializationVersion);
}
if (varType is UxrVarType.Float)
{
return reader.ReadSingle();
}
if (varType is UxrVarType.Double)
{
return reader.ReadDouble();
}
if (varType is UxrVarType.Decimal)
{
return reader.ReadDecimal();
}
if (varType is UxrVarType.String)
{
return reader.ReadString();
}
if (varType is UxrVarType.Enum)
{
Type enumType = reader.ReadType(serializationVersion);
return typeof(BinaryReaderExt).GetMethod(nameof(ReadEnum)).MakeGenericMethod(enumType).Invoke(reader, new object[] { reader, serializationVersion });
}
if (varType is UxrVarType.Type)
{
return reader.ReadType(serializationVersion);
}
if (varType is UxrVarType.Guid)
{
return reader.ReadGuid(serializationVersion);
}
if (varType is UxrVarType.Tuple)
{
Type typeItem1 = reader.ReadType(serializationVersion);
Type typeItem2 = reader.ReadType(serializationVersion);
return typeof(BinaryReaderExt).GetMethod(nameof(ReadTuple)).MakeGenericMethod(typeItem1, typeItem2).Invoke(reader, new object[] { reader, serializationVersion });
}
if (varType is UxrVarType.Array)
{
Type elementType = reader.ReadType(serializationVersion);
return typeof(BinaryReaderExt).GetMethod(nameof(ReadArray)).MakeGenericMethod(elementType).Invoke(reader, new object[] { reader, serializationVersion });
}
if (varType is UxrVarType.ObjectArray)
{
return reader.ReadObjectArray(serializationVersion);
}
if (varType is UxrVarType.List)
{
Type elementType = reader.ReadType(serializationVersion);
return typeof(BinaryReaderExt).GetMethod(nameof(ReadList)).MakeGenericMethod(elementType).Invoke(reader, new object[] { reader, serializationVersion });
}
if (varType is UxrVarType.ObjectList)
{
return reader.ReadObjectList(serializationVersion);
}
if (varType is UxrVarType.Dictionary)
{
Type keyType = reader.ReadType(serializationVersion);
Type elementType = reader.ReadType(serializationVersion);
return typeof(BinaryReaderExt).GetMethod(nameof(ReadDictionary)).MakeGenericMethod(keyType, elementType).Invoke(reader, new object[] { reader, serializationVersion });
}
if (varType is UxrVarType.HashSet)
{
Type elementType = reader.ReadType(serializationVersion);
return typeof(BinaryReaderExt).GetMethod(nameof(ReadHashSet)).MakeGenericMethod(elementType).Invoke(reader, new object[] { reader, serializationVersion });
}
if (varType is UxrVarType.ObjectHashSet)
{
return reader.ReadObjectHashSet(serializationVersion);
}
if (varType is UxrVarType.DateTime)
{
return reader.ReadDateTime(serializationVersion);
}
if (varType is UxrVarType.TimeSpan)
{
return reader.ReadTimeSpan(serializationVersion);
}
if (varType is UxrVarType.Vector2)
{
return reader.ReadVector2(serializationVersion);
}
if (varType is UxrVarType.Vector3)
{
return reader.ReadVector3(serializationVersion);
}
if (varType is UxrVarType.Vector4)
{
return reader.ReadVector4(serializationVersion);
}
if (varType is UxrVarType.Color)
{
return reader.ReadColor(serializationVersion);
}
if (varType is UxrVarType.Color32)
{
return reader.ReadColor32(serializationVersion);
}
if (varType is UxrVarType.Quaternion)
{
return reader.ReadQuaternion(serializationVersion);
}
if (varType is UxrVarType.Matrix4x4)
{
return reader.ReadMatrix(serializationVersion);
}
if (varType is UxrVarType.IUxrUnique)
{
return reader.ReadUniqueComponent(serializationVersion);
}
if (varType is UxrVarType.IUxrSerializable)
{
return reader.ReadUxrSerializable(serializationVersion);
}
if (varType is UxrVarType.UxrAxis)
{
return reader.ReadAxis(serializationVersion);
}
throw new ArgumentOutOfRangeException(nameof(varType), varType, $"Deserializing unknown {nameof(UxrVarType)} ({varType})");
}
#endregion
#region Private Methods
/// <summary>
/// Reads an object supported by <see cref="UxrVarType" />.
/// </summary>
/// <param name="reader">Reader</param>
/// <typeparam name="T">The type of the object</typeparam>
/// <returns>The object</returns>
/// <exception cref="ArgumentOutOfRangeException">A type is not supported</exception>
/// <exception cref="FormatException">The compressed data is corrupt</exception>
/// <exception cref="UxrComponentNotFoundException">An <see cref="IUxrUniqueId" /> was not found when deserializing</exception>
/// <exception cref="UxrSerializableClassNotFoundException">
/// A class that implements the <see cref="IUxrSerializable" />
/// interface was not found when deserializing
/// </exception>
/// <exception cref="InvalidCastException">
/// Failed to cast the value to <see cref="IUxrSerializable"/>.
/// </exception>
private static object Read<T>(this BinaryReader reader, int serializationVersion)
{
Type type = typeof(T);
if (type == typeof(bool))
{
return reader.ReadBoolean();
}
if (type == typeof(sbyte))
{
return reader.ReadSByte();
}
if (type == typeof(byte))
{
return reader.ReadByte();
}
if (type == typeof(char))
{
return reader.ReadChar();
}
if (type == typeof(int))
{
return reader.ReadCompressedInt32(serializationVersion);
}
if (type == typeof(uint))
{
return reader.ReadCompressedUInt32(serializationVersion);
}
if (type == typeof(long))
{
return reader.ReadCompressedInt64(serializationVersion);
}
if (type == typeof(ulong))
{
return reader.ReadCompressedUInt64(serializationVersion);
}
if (type == typeof(float))
{
return reader.ReadSingle();
}
if (type == typeof(double))
{
return reader.ReadDouble();
}
if (type == typeof(decimal))
{
return reader.ReadDecimal();
}
if (type == typeof(string))
{
return reader.ReadString();
}
if (type.IsEnum)
{
return reader.ReadEnum<T>(serializationVersion);
}
if (type == typeof(Type))
{
return reader.ReadType(serializationVersion);
}
if (type == typeof(Guid))
{
return reader.ReadGuid(serializationVersion);
}
if (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(Tuple<,>) || type.GetGenericTypeDefinition() == typeof(ValueTuple<,>)))
{
Type typeItem1 = type.GetGenericArguments()[0];
Type typeItem2 = type.GetGenericArguments()[1];
return typeof(BinaryReaderExt).GetMethod(nameof(ReadTuple)).MakeGenericMethod(typeItem1, typeItem2).Invoke(reader, new object[] { reader, serializationVersion });
}
if (type.IsArray)
{
if (type.GetElementType() == typeof(object))
{
return reader.ReadObjectArray(serializationVersion);
}
return reader.ReadArray<T>(serializationVersion);
}
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))
{
Type elementType = type.GetElementType();
if (elementType == typeof(object))
{
return reader.ReadObjectList(serializationVersion);
}
typeof(BinaryReaderExt).GetMethod(nameof(ReadList)).MakeGenericMethod(elementType).Invoke(reader, new object[] { reader, serializationVersion });
}
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>))
{
Type keyType = type.GetGenericArguments()[0];
Type valueType = type.GetGenericArguments()[1];
return typeof(BinaryReaderExt).GetMethod(nameof(ReadDictionary)).MakeGenericMethod(keyType, valueType).Invoke(reader, new object[] { reader, serializationVersion });
}
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(HashSet<>))
{
Type elementType = type.GetElementType();
if (elementType == typeof(object))
{
return reader.ReadObjectHashSet(serializationVersion);
}
typeof(BinaryReaderExt).GetMethod(nameof(ReadHashSet)).MakeGenericMethod(elementType).Invoke(reader, new object[] { reader, serializationVersion });
}
if (type == typeof(Vector2))
{
return reader.ReadVector2(serializationVersion);
}
if (type == typeof(Vector3))
{
return reader.ReadVector3(serializationVersion);
}
if (type == typeof(Vector4))
{
return reader.ReadVector4(serializationVersion);
}
if (type == typeof(Color))
{
return reader.ReadColor(serializationVersion);
}
if (type == typeof(Color32))
{
return reader.ReadColor32(serializationVersion);
}
if (type == typeof(Quaternion))
{
return reader.ReadQuaternion(serializationVersion);
}
if (type == typeof(Matrix4x4))
{
return reader.ReadMatrix(serializationVersion);
}
if (type == typeof(Matrix4x4))
{
return reader.ReadMatrix(serializationVersion);
}
if (typeof(IUxrUniqueId).IsAssignableFrom(type))
{
return reader.ReadUniqueComponent(serializationVersion);
}
if (typeof(IUxrSerializable).IsAssignableFrom(type))
{
return reader.ReadUxrSerializable(serializationVersion);
}
if (type == typeof(UxrAxis))
{
return reader.ReadAxis(serializationVersion);
}
throw new ArgumentOutOfRangeException(nameof(T), typeof(T).FullName, $"Deserializing to unknown target type ({typeof(T).FullName}");
}
#endregion
}
}