1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-21 17:23:05 +08:00
osu-lazer/osu.Game/IO/Legacy/SerializationReader.cs

210 lines
5.8 KiB
C#
Raw Normal View History

// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
2018-04-13 17:19:50 +08:00
2022-06-17 15:37:17 +08:00
#nullable disable
2018-04-13 17:19:50 +08:00
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace osu.Game.IO.Legacy
{
/// <summary> SerializationReader. Extends BinaryReader to add additional data types,
/// handle null strings and simplify use with ISerializable. </summary>
public class SerializationReader : BinaryReader
{
private readonly Stream stream;
public SerializationReader(Stream s)
: base(s, Encoding.UTF8)
{
stream = s;
}
public int RemainingBytes => (int)(stream.Length - stream.Position);
/// <summary> Reads a string from the buffer. Overrides the base implementation so it can cope with nulls. </summary>
public override string ReadString()
{
// ReSharper disable once AssignNullToNotNullAttribute
2019-01-24 16:46:09 +08:00
if (ReadByte() == 0) return null;
2019-02-28 12:31:40 +08:00
2018-04-13 17:19:50 +08:00
return base.ReadString();
}
/// <summary> Reads a byte array from the buffer, handling nulls and the array length. </summary>
public byte[] ReadByteArray()
{
int len = ReadInt32();
if (len > 0) return ReadBytes(len);
if (len < 0) return null;
2019-02-28 12:31:40 +08:00
2018-04-13 17:19:50 +08:00
return Array.Empty<byte>();
}
/// <summary> Reads a char array from the buffer, handling nulls and the array length. </summary>
public char[] ReadCharArray()
{
int len = ReadInt32();
if (len > 0) return ReadChars(len);
if (len < 0) return null;
2019-02-28 12:31:40 +08:00
2018-04-13 17:19:50 +08:00
return Array.Empty<char>();
}
/// <summary> Reads a DateTime from the buffer. </summary>
public DateTime ReadDateTime()
{
long ticks = ReadInt64();
if (ticks < 0) throw new IOException("Bad ticks count read!");
2019-02-28 12:31:40 +08:00
2018-04-13 17:19:50 +08:00
return new DateTime(ticks, DateTimeKind.Utc);
}
/// <summary> Reads a generic list from the buffer. </summary>
public IList<T> ReadBList<T>(bool skipErrors = false) where T : ILegacySerializable, new()
{
int count = ReadInt32();
if (count < 0) return null;
2019-02-28 12:31:40 +08:00
2018-04-13 17:19:50 +08:00
IList<T> d = new List<T>(count);
SerializationReader sr = new SerializationReader(BaseStream);
for (int i = 0; i < count; i++)
{
T obj = new T();
2019-04-01 11:16:05 +08:00
2018-04-13 17:19:50 +08:00
try
{
obj.ReadFromStream(sr);
}
catch (Exception)
{
if (skipErrors)
continue;
2019-02-28 12:31:40 +08:00
2018-04-13 17:19:50 +08:00
throw;
}
d.Add(obj);
}
return d;
}
/// <summary> Reads a generic list from the buffer. </summary>
public IList<T> ReadList<T>()
{
int count = ReadInt32();
if (count < 0) return null;
2019-02-28 12:31:40 +08:00
2018-04-13 17:19:50 +08:00
IList<T> d = new List<T>(count);
for (int i = 0; i < count; i++) d.Add((T)ReadObject());
return d;
}
/// <summary> Reads a generic Dictionary from the buffer. </summary>
public IDictionary<TKey, TValue> ReadDictionary<TKey, TValue>()
2018-04-13 17:19:50 +08:00
{
int count = ReadInt32();
if (count < 0) return null;
2019-02-28 12:31:40 +08:00
IDictionary<TKey, TValue> d = new Dictionary<TKey, TValue>();
for (int i = 0; i < count; i++) d[(TKey)ReadObject()] = (TValue)ReadObject();
2018-04-13 17:19:50 +08:00
return d;
}
/// <summary> Reads an object which was added to the buffer by WriteObject. </summary>
public object ReadObject()
{
ObjType t = (ObjType)ReadByte();
2019-04-01 11:16:05 +08:00
2018-04-13 17:19:50 +08:00
switch (t)
{
case ObjType.BoolType:
2018-04-13 17:19:50 +08:00
return ReadBoolean();
2019-04-01 11:16:05 +08:00
case ObjType.ByteType:
2018-04-13 17:19:50 +08:00
return ReadByte();
2019-04-01 11:16:05 +08:00
case ObjType.UInt16Type:
2018-04-13 17:19:50 +08:00
return ReadUInt16();
2019-04-01 11:16:05 +08:00
case ObjType.UInt32Type:
2018-04-13 17:19:50 +08:00
return ReadUInt32();
2019-04-01 11:16:05 +08:00
case ObjType.UInt64Type:
2018-04-13 17:19:50 +08:00
return ReadUInt64();
2019-04-01 11:16:05 +08:00
case ObjType.SByteType:
2018-04-13 17:19:50 +08:00
return ReadSByte();
2019-04-01 11:16:05 +08:00
case ObjType.Int16Type:
2018-04-13 17:19:50 +08:00
return ReadInt16();
2019-04-01 11:16:05 +08:00
case ObjType.Int32Type:
2018-04-13 17:19:50 +08:00
return ReadInt32();
2019-04-01 11:16:05 +08:00
case ObjType.Int64Type:
2018-04-13 17:19:50 +08:00
return ReadInt64();
2019-04-01 11:16:05 +08:00
case ObjType.CharType:
2018-04-13 17:19:50 +08:00
return ReadChar();
2019-04-01 11:16:05 +08:00
case ObjType.StringType:
2018-04-13 17:19:50 +08:00
return base.ReadString();
2019-04-01 11:16:05 +08:00
case ObjType.SingleType:
2018-04-13 17:19:50 +08:00
return ReadSingle();
2019-04-01 11:16:05 +08:00
case ObjType.DoubleType:
2018-04-13 17:19:50 +08:00
return ReadDouble();
2019-04-01 11:16:05 +08:00
case ObjType.DecimalType:
2018-04-13 17:19:50 +08:00
return ReadDecimal();
2019-04-01 11:16:05 +08:00
case ObjType.DateTimeType:
2018-04-13 17:19:50 +08:00
return ReadDateTime();
2019-04-01 11:16:05 +08:00
case ObjType.ByteArrayType:
2018-04-13 17:19:50 +08:00
return ReadByteArray();
2019-04-01 11:16:05 +08:00
case ObjType.CharArrayType:
2018-04-13 17:19:50 +08:00
return ReadCharArray();
2019-04-01 11:16:05 +08:00
case ObjType.OtherType:
2022-04-12 20:28:14 +08:00
throw new IOException("Deserialization of arbitrary type is not supported.");
2019-04-01 11:16:05 +08:00
2018-04-13 17:19:50 +08:00
default:
return null;
}
}
}
public enum ObjType : byte
{
NullType,
BoolType,
ByteType,
UInt16Type,
UInt32Type,
UInt64Type,
SByteType,
Int16Type,
Int32Type,
Int64Type,
CharType,
StringType,
SingleType,
DoubleType,
DecimalType,
DateTimeType,
ByteArrayType,
CharArrayType,
OtherType,
LegacySerializableType
2018-04-13 17:19:50 +08:00
}
}