osu/osu.Game/IO/Legacy/SerializationReader.cs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

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 09:19:50 +00:00
2022-06-17 07:37:17 +00:00
#nullable disable
2017-02-28 11:14:48 +00:00
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
2018-04-13 09:19:50 +00:00
2017-02-28 11:14:48 +00:00
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;
2018-04-13 09:19:50 +00:00
2017-02-28 11:14:48 +00:00
public SerializationReader(Stream s)
: base(s, Encoding.UTF8)
{
stream = s;
}
2018-04-13 09:19:50 +00:00
2017-02-28 11:14:48 +00:00
public int RemainingBytes => (int)(stream.Length - stream.Position);
2018-04-13 09:19:50 +00:00
2017-02-28 11:14:48 +00:00
/// <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 08:46:09 +00:00
if (ReadByte() == 0) return null;
2019-02-28 04:31:40 +00:00
2017-02-28 11:14:48 +00:00
return base.ReadString();
}
2018-04-13 09:19:50 +00:00
2017-02-28 11:14:48 +00:00
/// <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 04:31:40 +00:00
2017-09-23 19:45:46 +00:00
return Array.Empty<byte>();
2017-02-28 11:14:48 +00:00
}
2018-04-13 09:19:50 +00:00
2017-02-28 11:14:48 +00:00
/// <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 04:31:40 +00:00
2017-09-23 19:45:46 +00:00
return Array.Empty<char>();
2017-02-28 11:14:48 +00:00
}
2018-04-13 09:19:50 +00:00
2017-02-28 11:14:48 +00:00
/// <summary> Reads a DateTime from the buffer. </summary>
public DateTime ReadDateTime()
{
long ticks = ReadInt64();
2017-05-16 13:23:14 +00:00
if (ticks < 0) throw new IOException("Bad ticks count read!");
2019-02-28 04:31:40 +00:00
2017-02-28 11:14:48 +00:00
return new DateTime(ticks, DateTimeKind.Utc);
}
2018-04-13 09:19:50 +00:00
2017-02-28 11:14:48 +00:00
/// <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 04:31:40 +00:00
2017-02-28 11:14:48 +00:00
IList<T> d = new List<T>(count);
2018-04-13 09:19:50 +00:00
2017-02-28 11:14:48 +00:00
SerializationReader sr = new SerializationReader(BaseStream);
2018-04-13 09:19:50 +00:00
2017-02-28 11:14:48 +00:00
for (int i = 0; i < count; i++)
{
T obj = new T();
2019-04-01 03:16:05 +00:00
2017-02-28 11:14:48 +00:00
try
{
obj.ReadFromStream(sr);
}
catch (Exception)
{
if (skipErrors)
continue;
2019-02-28 04:31:40 +00:00
2017-02-28 11:14:48 +00:00
throw;
}
2018-04-13 09:19:50 +00:00
2017-02-28 11:14:48 +00:00
d.Add(obj);
}
2018-04-13 09:19:50 +00:00
2017-02-28 11:14:48 +00:00
return d;
}
2018-04-13 09:19:50 +00:00
2017-02-28 11:14:48 +00:00
/// <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 04:31:40 +00:00
2017-02-28 11:14:48 +00:00
IList<T> d = new List<T>(count);
for (int i = 0; i < count; i++) d.Add((T)ReadObject());
return d;
}
2018-04-13 09:19:50 +00:00
2017-02-28 11:14:48 +00:00
/// <summary> Reads a generic Dictionary from the buffer. </summary>
public IDictionary<TKey, TValue> ReadDictionary<TKey, TValue>()
2017-02-28 11:14:48 +00:00
{
int count = ReadInt32();
if (count < 0) return null;
2019-02-28 04:31:40 +00:00
IDictionary<TKey, TValue> d = new Dictionary<TKey, TValue>();
for (int i = 0; i < count; i++) d[(TKey)ReadObject()] = (TValue)ReadObject();
2017-02-28 11:14:48 +00:00
return d;
}
2018-04-13 09:19:50 +00:00
2017-02-28 11:14:48 +00:00
/// <summary> Reads an object which was added to the buffer by WriteObject. </summary>
public object ReadObject()
{
ObjType t = (ObjType)ReadByte();
2019-04-01 03:16:05 +00:00
2017-02-28 11:14:48 +00:00
switch (t)
{
case ObjType.boolType:
return ReadBoolean();
2019-04-01 03:16:05 +00:00
2017-02-28 11:14:48 +00:00
case ObjType.byteType:
return ReadByte();
2019-04-01 03:16:05 +00:00
2017-02-28 11:14:48 +00:00
case ObjType.uint16Type:
return ReadUInt16();
2019-04-01 03:16:05 +00:00
2017-02-28 11:14:48 +00:00
case ObjType.uint32Type:
return ReadUInt32();
2019-04-01 03:16:05 +00:00
2017-02-28 11:14:48 +00:00
case ObjType.uint64Type:
return ReadUInt64();
2019-04-01 03:16:05 +00:00
2017-02-28 11:14:48 +00:00
case ObjType.sbyteType:
return ReadSByte();
2019-04-01 03:16:05 +00:00
2017-02-28 11:14:48 +00:00
case ObjType.int16Type:
return ReadInt16();
2019-04-01 03:16:05 +00:00
2017-02-28 11:14:48 +00:00
case ObjType.int32Type:
return ReadInt32();
2019-04-01 03:16:05 +00:00
2017-02-28 11:14:48 +00:00
case ObjType.int64Type:
return ReadInt64();
2019-04-01 03:16:05 +00:00
2017-02-28 11:14:48 +00:00
case ObjType.charType:
return ReadChar();
2019-04-01 03:16:05 +00:00
2017-02-28 11:14:48 +00:00
case ObjType.stringType:
return base.ReadString();
2019-04-01 03:16:05 +00:00
2017-02-28 11:14:48 +00:00
case ObjType.singleType:
return ReadSingle();
2019-04-01 03:16:05 +00:00
2017-02-28 11:14:48 +00:00
case ObjType.doubleType:
return ReadDouble();
2019-04-01 03:16:05 +00:00
2017-02-28 11:14:48 +00:00
case ObjType.decimalType:
return ReadDecimal();
2019-04-01 03:16:05 +00:00
2017-02-28 11:14:48 +00:00
case ObjType.dateTimeType:
return ReadDateTime();
2019-04-01 03:16:05 +00:00
2017-02-28 11:14:48 +00:00
case ObjType.byteArrayType:
return ReadByteArray();
2019-04-01 03:16:05 +00:00
2017-02-28 11:14:48 +00:00
case ObjType.charArrayType:
return ReadCharArray();
2019-04-01 03:16:05 +00:00
2017-02-28 11:14:48 +00:00
case ObjType.otherType:
2022-04-12 12:28:14 +00:00
throw new IOException("Deserialization of arbitrary type is not supported.");
2019-04-01 03:16:05 +00:00
2017-02-28 11:14:48 +00:00
default:
return null;
}
}
}
2018-04-13 09:19:50 +00:00
2017-02-28 11:14:48 +00:00
public enum ObjType : byte
{
nullType,
boolType,
byteType,
uint16Type,
uint32Type,
uint64Type,
sbyteType,
int16Type,
int32Type,
int64Type,
charType,
stringType,
singleType,
doubleType,
decimalType,
dateTimeType,
byteArrayType,
charArrayType,
otherType,
ILegacySerializableType
}
}