2017-02-28 19:14:48 +08:00
|
|
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
|
|
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
|
|
|
|
|
|
|
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;
|
2017-03-09 14:52:40 +08:00
|
|
|
// ReSharper disable ConditionIsAlwaysTrueOrFalse (we're allowing nulls to be passed to the writer where the underlying class doesn't).
|
|
|
|
// ReSharper disable HeuristicUnreachableCode
|
2017-02-28 19:14:48 +08:00
|
|
|
|
|
|
|
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
|
|
|
|
{
|
|
|
|
public SerializationWriter(Stream s)
|
|
|
|
: base(s, Encoding.UTF8)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-09 13:24:16 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Writes DateTime to the buffer.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="dt"></param>
|
2017-02-28 19:14:48 +08:00
|
|
|
public void Write(DateTime dt)
|
|
|
|
{
|
|
|
|
Write(dt.ToUniversalTime().Ticks);
|
|
|
|
}
|
|
|
|
|
2017-03-09 13:24:16 +08:00
|
|
|
/// <summary> Writes a generic ICollection (such as an IList(T)) to the buffer.</summary>
|
2017-02-28 19:14:48 +08:00
|
|
|
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>
|
|
|
|
public void Write<T, U>(IDictionary<T, U> d)
|
|
|
|
{
|
|
|
|
if (d == null)
|
|
|
|
{
|
|
|
|
Write(-1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Write(d.Count);
|
|
|
|
foreach (KeyValuePair<T, U> kvp in d)
|
|
|
|
{
|
|
|
|
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
|
|
|
|
{
|
|
|
|
switch (obj.GetType().Name)
|
|
|
|
{
|
|
|
|
case "Boolean":
|
|
|
|
Write((byte)ObjType.boolType);
|
|
|
|
Write((bool)obj);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "Byte":
|
|
|
|
Write((byte)ObjType.byteType);
|
|
|
|
Write((byte)obj);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "UInt16":
|
|
|
|
Write((byte)ObjType.uint16Type);
|
|
|
|
Write((ushort)obj);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "UInt32":
|
|
|
|
Write((byte)ObjType.uint32Type);
|
|
|
|
Write((uint)obj);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "UInt64":
|
|
|
|
Write((byte)ObjType.uint64Type);
|
|
|
|
Write((ulong)obj);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "SByte":
|
|
|
|
Write((byte)ObjType.sbyteType);
|
|
|
|
Write((sbyte)obj);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "Int16":
|
|
|
|
Write((byte)ObjType.int16Type);
|
|
|
|
Write((short)obj);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "Int32":
|
|
|
|
Write((byte)ObjType.int32Type);
|
|
|
|
Write((int)obj);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "Int64":
|
|
|
|
Write((byte)ObjType.int64Type);
|
|
|
|
Write((long)obj);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "Char":
|
|
|
|
Write((byte)ObjType.charType);
|
|
|
|
base.Write((char)obj);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "String":
|
|
|
|
Write((byte)ObjType.stringType);
|
|
|
|
base.Write((string)obj);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "Single":
|
|
|
|
Write((byte)ObjType.singleType);
|
|
|
|
Write((float)obj);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "Double":
|
|
|
|
Write((byte)ObjType.doubleType);
|
|
|
|
Write((double)obj);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "Decimal":
|
|
|
|
Write((byte)ObjType.decimalType);
|
|
|
|
Write((decimal)obj);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "DateTime":
|
|
|
|
Write((byte)ObjType.dateTimeType);
|
|
|
|
Write((DateTime)obj);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "Byte[]":
|
|
|
|
Write((byte)ObjType.byteArrayType);
|
|
|
|
base.Write((byte[])obj);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "Char[]":
|
|
|
|
Write((byte)ObjType.charArrayType);
|
|
|
|
base.Write((char[])obj);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
Write((byte)ObjType.otherType);
|
2017-03-09 13:24:16 +08:00
|
|
|
BinaryFormatter b = new BinaryFormatter
|
|
|
|
{
|
|
|
|
AssemblyFormat = FormatterAssemblyStyle.Simple,
|
|
|
|
TypeFormat = FormatterTypeStyle.TypesWhenNeeded
|
|
|
|
};
|
2017-02-28 19:14:48 +08:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|