2019-01-24 08:43:03 +00:00
|
|
|
// 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
|
|
|
|
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.IO;
|
|
|
|
using System.Runtime.Serialization;
|
|
|
|
using System.Runtime.Serialization.Formatters;
|
|
|
|
using System.Runtime.Serialization.Formatters.Binary;
|
|
|
|
using System.Text;
|
2019-02-28 04:31:40 +00:00
|
|
|
|
2018-04-13 09:19:50 +00:00
|
|
|
// ReSharper disable ConditionIsAlwaysTrueOrFalse (we're allowing nulls to be passed to the writer where the underlying class doesn't).
|
|
|
|
// ReSharper disable HeuristicUnreachableCode
|
|
|
|
|
|
|
|
namespace osu.Game.IO.Legacy
|
|
|
|
{
|
|
|
|
/// <summary> SerializationWriter. Extends BinaryWriter to add additional data types,
|
|
|
|
/// handle null strings and simplify use with ISerializable. </summary>
|
|
|
|
public class SerializationWriter : BinaryWriter
|
|
|
|
{
|
2021-06-23 06:10:03 +00:00
|
|
|
public SerializationWriter(Stream s, bool leaveOpen = false)
|
|
|
|
: base(s, Encoding.UTF8, leaveOpen)
|
2018-04-13 09:19:50 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary> Static method to initialise the writer with a suitable MemoryStream. </summary>
|
|
|
|
public static SerializationWriter GetWriter()
|
|
|
|
{
|
|
|
|
MemoryStream ms = new MemoryStream(1024);
|
|
|
|
return new SerializationWriter(ms);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary> Writes a string to the buffer. Overrides the base implementation so it can cope with nulls </summary>
|
|
|
|
public override void Write(string str)
|
|
|
|
{
|
|
|
|
if (str == null)
|
|
|
|
{
|
|
|
|
Write((byte)ObjType.nullType);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Write((byte)ObjType.stringType);
|
|
|
|
base.Write(str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary> Writes a byte array to the buffer. Overrides the base implementation to
|
|
|
|
/// send the length of the array which is needed when it is retrieved </summary>
|
|
|
|
public override void Write(byte[] b)
|
|
|
|
{
|
|
|
|
if (b == null)
|
|
|
|
{
|
|
|
|
Write(-1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int len = b.Length;
|
|
|
|
Write(len);
|
|
|
|
if (len > 0) base.Write(b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary> Writes a char array to the buffer. Overrides the base implementation to
|
|
|
|
/// sends the length of the array which is needed when it is read. </summary>
|
|
|
|
public override void Write(char[] c)
|
|
|
|
{
|
|
|
|
if (c == null)
|
|
|
|
{
|
|
|
|
Write(-1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int len = c.Length;
|
|
|
|
Write(len);
|
|
|
|
if (len > 0) base.Write(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Writes DateTime to the buffer.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="dt"></param>
|
|
|
|
public void Write(DateTime dt)
|
|
|
|
{
|
|
|
|
Write(dt.ToUniversalTime().Ticks);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary> Writes a generic ICollection (such as an IList(T)) to the buffer.</summary>
|
|
|
|
public void Write<T>(List<T> c) where T : ILegacySerializable
|
|
|
|
{
|
|
|
|
if (c == null)
|
|
|
|
{
|
|
|
|
Write(-1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int count = c.Count;
|
|
|
|
Write(count);
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
c[i].WriteToStream(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary> Writes a generic IDictionary to the buffer. </summary>
|
2019-12-10 13:04:26 +00:00
|
|
|
public void Write<TKey, TValue>(IDictionary<TKey, TValue> d)
|
2018-04-13 09:19:50 +00:00
|
|
|
{
|
|
|
|
if (d == null)
|
|
|
|
{
|
|
|
|
Write(-1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Write(d.Count);
|
2019-04-01 03:16:05 +00:00
|
|
|
|
2019-12-10 13:04:26 +00:00
|
|
|
foreach (KeyValuePair<TKey, TValue> kvp in d)
|
2018-04-13 09:19:50 +00:00
|
|
|
{
|
|
|
|
WriteObject(kvp.Key);
|
|
|
|
WriteObject(kvp.Value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary> Writes an arbitrary object to the buffer. Useful where we have something of type "object"
|
|
|
|
/// and don't know how to treat it. This works out the best method to use to write to the buffer. </summary>
|
|
|
|
public void WriteObject(object obj)
|
|
|
|
{
|
|
|
|
if (obj == null)
|
|
|
|
{
|
|
|
|
Write((byte)ObjType.nullType);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-01-27 13:28:28 +00:00
|
|
|
switch (obj)
|
2018-04-13 09:19:50 +00:00
|
|
|
{
|
2020-01-27 13:28:28 +00:00
|
|
|
case bool boolObj:
|
2018-04-13 09:19:50 +00:00
|
|
|
Write((byte)ObjType.boolType);
|
2020-01-27 13:28:28 +00:00
|
|
|
Write(boolObj);
|
2018-04-13 09:19:50 +00:00
|
|
|
break;
|
|
|
|
|
2020-01-27 13:28:28 +00:00
|
|
|
case byte byteObj:
|
2018-04-13 09:19:50 +00:00
|
|
|
Write((byte)ObjType.byteType);
|
2020-01-27 13:28:28 +00:00
|
|
|
Write(byteObj);
|
2018-04-13 09:19:50 +00:00
|
|
|
break;
|
|
|
|
|
2020-01-27 13:28:28 +00:00
|
|
|
case ushort ushortObj:
|
2018-04-13 09:19:50 +00:00
|
|
|
Write((byte)ObjType.uint16Type);
|
2020-01-27 13:28:28 +00:00
|
|
|
Write(ushortObj);
|
2018-04-13 09:19:50 +00:00
|
|
|
break;
|
|
|
|
|
2020-01-27 13:28:28 +00:00
|
|
|
case uint uintObj:
|
2018-04-13 09:19:50 +00:00
|
|
|
Write((byte)ObjType.uint32Type);
|
2020-01-27 13:28:28 +00:00
|
|
|
Write(uintObj);
|
2018-04-13 09:19:50 +00:00
|
|
|
break;
|
|
|
|
|
2020-01-27 13:28:28 +00:00
|
|
|
case ulong ulongObj:
|
2018-04-13 09:19:50 +00:00
|
|
|
Write((byte)ObjType.uint64Type);
|
2020-01-27 13:28:28 +00:00
|
|
|
Write(ulongObj);
|
2018-04-13 09:19:50 +00:00
|
|
|
break;
|
|
|
|
|
2020-01-27 13:28:28 +00:00
|
|
|
case sbyte sbyteObj:
|
2018-04-13 09:19:50 +00:00
|
|
|
Write((byte)ObjType.sbyteType);
|
2020-01-27 13:28:28 +00:00
|
|
|
Write(sbyteObj);
|
2018-04-13 09:19:50 +00:00
|
|
|
break;
|
|
|
|
|
2020-01-27 13:28:28 +00:00
|
|
|
case short shortObj:
|
2018-04-13 09:19:50 +00:00
|
|
|
Write((byte)ObjType.int16Type);
|
2020-01-27 13:28:28 +00:00
|
|
|
Write(shortObj);
|
2018-04-13 09:19:50 +00:00
|
|
|
break;
|
|
|
|
|
2020-01-27 13:28:28 +00:00
|
|
|
case int intObj:
|
2018-04-13 09:19:50 +00:00
|
|
|
Write((byte)ObjType.int32Type);
|
2020-01-27 13:28:28 +00:00
|
|
|
Write(intObj);
|
2018-04-13 09:19:50 +00:00
|
|
|
break;
|
|
|
|
|
2020-01-27 13:28:28 +00:00
|
|
|
case long longObj:
|
2018-04-13 09:19:50 +00:00
|
|
|
Write((byte)ObjType.int64Type);
|
2020-01-27 13:28:28 +00:00
|
|
|
Write(longObj);
|
2018-04-13 09:19:50 +00:00
|
|
|
break;
|
|
|
|
|
2020-01-27 13:28:28 +00:00
|
|
|
case char charObj:
|
2018-04-13 09:19:50 +00:00
|
|
|
Write((byte)ObjType.charType);
|
2020-01-27 13:28:28 +00:00
|
|
|
base.Write(charObj);
|
2018-04-13 09:19:50 +00:00
|
|
|
break;
|
|
|
|
|
2020-01-27 13:28:28 +00:00
|
|
|
case string stringObj:
|
2018-04-13 09:19:50 +00:00
|
|
|
Write((byte)ObjType.stringType);
|
2020-01-27 13:28:28 +00:00
|
|
|
base.Write(stringObj);
|
2018-04-13 09:19:50 +00:00
|
|
|
break;
|
|
|
|
|
2020-01-27 13:28:28 +00:00
|
|
|
case float floatObj:
|
2018-04-13 09:19:50 +00:00
|
|
|
Write((byte)ObjType.singleType);
|
2020-01-27 13:28:28 +00:00
|
|
|
Write(floatObj);
|
2018-04-13 09:19:50 +00:00
|
|
|
break;
|
|
|
|
|
2020-01-27 13:28:28 +00:00
|
|
|
case double doubleObj:
|
2018-04-13 09:19:50 +00:00
|
|
|
Write((byte)ObjType.doubleType);
|
2020-01-27 13:28:28 +00:00
|
|
|
Write(doubleObj);
|
2018-04-13 09:19:50 +00:00
|
|
|
break;
|
|
|
|
|
2020-01-27 13:28:28 +00:00
|
|
|
case decimal decimalObj:
|
2018-04-13 09:19:50 +00:00
|
|
|
Write((byte)ObjType.decimalType);
|
2020-01-27 13:28:28 +00:00
|
|
|
Write(decimalObj);
|
2018-04-13 09:19:50 +00:00
|
|
|
break;
|
|
|
|
|
2020-01-27 13:28:28 +00:00
|
|
|
case DateTime dateTimeObj:
|
2018-04-13 09:19:50 +00:00
|
|
|
Write((byte)ObjType.dateTimeType);
|
2020-01-27 13:28:28 +00:00
|
|
|
Write(dateTimeObj);
|
2018-04-13 09:19:50 +00:00
|
|
|
break;
|
|
|
|
|
2020-01-27 13:28:28 +00:00
|
|
|
case byte[] byteArray:
|
2018-04-13 09:19:50 +00:00
|
|
|
Write((byte)ObjType.byteArrayType);
|
2020-01-27 13:28:28 +00:00
|
|
|
base.Write(byteArray);
|
2018-04-13 09:19:50 +00:00
|
|
|
break;
|
|
|
|
|
2020-01-27 13:28:28 +00:00
|
|
|
case char[] charArray:
|
2018-04-13 09:19:50 +00:00
|
|
|
Write((byte)ObjType.charArrayType);
|
2020-01-27 13:28:28 +00:00
|
|
|
base.Write(charArray);
|
2018-04-13 09:19:50 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
Write((byte)ObjType.otherType);
|
|
|
|
BinaryFormatter b = new BinaryFormatter
|
|
|
|
{
|
2019-02-28 04:31:40 +00:00
|
|
|
// AssemblyFormat = FormatterAssemblyStyle.Simple,
|
2018-04-13 09:19:50 +00:00
|
|
|
TypeFormat = FormatterTypeStyle.TypesWhenNeeded
|
|
|
|
};
|
|
|
|
b.Serialize(BaseStream, obj);
|
|
|
|
break;
|
|
|
|
} // switch
|
|
|
|
} // if obj==null
|
|
|
|
} // WriteObject
|
|
|
|
|
|
|
|
/// <summary> Adds the SerializationWriter buffer to the SerializationInfo at the end of GetObjectData(). </summary>
|
|
|
|
public void AddToInfo(SerializationInfo info)
|
|
|
|
{
|
|
|
|
byte[] b = ((MemoryStream)BaseStream).ToArray();
|
|
|
|
info.AddValue("X", b, typeof(byte[]));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void WriteRawBytes(byte[] b)
|
|
|
|
{
|
|
|
|
base.Write(b);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void WriteByteArray(byte[] b)
|
|
|
|
{
|
|
|
|
if (b == null)
|
|
|
|
{
|
|
|
|
Write(-1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int len = b.Length;
|
|
|
|
Write(len);
|
|
|
|
if (len > 0) base.Write(b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void WriteUtf8(string str)
|
|
|
|
{
|
|
|
|
WriteRawBytes(Encoding.UTF8.GetBytes(str));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|