You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Zero/ZeroLevel/Services/Serialization/MemoryStreamReader.cs

345 lines
10 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
namespace ZeroLevel.Services.Serialization
{
/// <summary>
/// Обертка над MemoryStream для чтения, с проверкой выхода за пределы потока
/// </summary>
public sealed class MemoryStreamReader
: IBinaryReader
{
private readonly MemoryStream _stream;
/// <summary>
/// Конструктор
/// </summary>
/// <param name="data">Данные для чтения</param>
public MemoryStreamReader(byte[] data)
{
if (data == null)
throw new ArgumentNullException(nameof(data));
_stream = new MemoryStream(data);
}
/// <summary>
/// Чтение флага
/// </summary>
public bool ReadBoolean()
{
if (CheckOutOfRange(_stream, 1))
throw new OutOfMemoryException("Array index out of bounds");
return BitConverter.ToBoolean(new byte[1] { ReadByte() }, 0);
}
/// <summary>
/// Чтение байта
/// </summary>
public byte ReadByte()
{
if (CheckOutOfRange(_stream, 1))
throw new OutOfMemoryException("Array index out of bounds");
return (byte)_stream.ReadByte();
}
/// <summary>
/// Чтение байт-массива
/// </summary>
/// <returns></returns>
public byte[] ReadBytes()
{
var length = BitConverter.ToInt32(ReadBuffer(4), 0);
if (length == 0) return new byte[0];
return ReadBuffer(length);
}
/// <summary>
/// Чтение целого 32-хбитного числа (4 байта)
/// </summary>
public Int32 ReadInt32()
{
var buffer = ReadBuffer(4);
return BitConverter.ToInt32(buffer, 0);
}
public decimal ReadDecimal()
{
var buffer = ReadBuffer(4);
return BitConverter.ToInt32(buffer, 0);
}
/// <summary>
/// Чтение целого 64-хбитного числа (8 байт)
/// </summary>
public Int64 ReadLong()
{
var buffer = ReadBuffer(8);
return BitConverter.ToInt64(buffer, 0);
}
public TimeSpan ReadTimeSpan()
{
return new TimeSpan(ReadLong());
}
public double ReadDouble()
{
var buffer = ReadBuffer(8);
return BitConverter.ToDouble(buffer, 0);
}
/// <summary>
/// Чтение строки (4 байта на длину + Length байт)
/// </summary>
public string ReadString()
{
var length = BitConverter.ToInt32(ReadBuffer(4), 0);
if (length == 0) return null;
var buffer = ReadBuffer(length);
return Encoding.UTF8.GetString(buffer);
}
/// <summary>
/// Чтение GUID (16 байт)
/// </summary>
public Guid ReadGuid()
{
var buffer = ReadBuffer(16);
return new Guid(buffer);
}
/// <summary>
/// Чтение байт-пакета (читается размер из указанного количества байт и затем сам пакет прочитанного размера)
/// </summary>
public byte[] ReadBuffer(int count)
{
if (count == 0) return null;
if (CheckOutOfRange(_stream, count))
throw new OutOfMemoryException("Array index out of bounds");
var buffer = new byte[count];
var readedCount = _stream.Read(buffer, 0, count);
if (count != readedCount)
throw new InvalidOperationException(string.Format("The stream returned less data ({0} bytes) than expected ({1} bytes)", count, readedCount));
return buffer;
}
/// <summary>
/// Чтение даты времени
/// </summary>
/// <returns></returns>
public DateTime? ReadDateTime()
{
var is_null = ReadByte();
if (is_null == 0) return null;
var buffer = ReadBuffer(8);
long deserialized = BitConverter.ToInt64(buffer, 0);
return DateTime.FromBinary(deserialized);
}
public IPAddress ReadIP()
{
var addr = ReadLong();
return new IPAddress(addr);
}
public IPEndPoint ReadIPEndpoint()
{
var addr = ReadLong();
var port = ReadInt32();
return new IPEndPoint(addr, port);
}
/// <summary>
/// Проверка не выходит ли чтение данных за пределы потока
/// </summary>
bool CheckOutOfRange(Stream stream, int offset)
{
return (stream.Position + offset) > stream.Length;
}
#region Extensions
public List<T> ReadCollection<T>()
where T : IBinarySerializable, new()
{
int count = ReadInt32();
var collection = new List<T>(count);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
var item = new T();
item.Deserialize(this);
collection.Add(item);
}
}
return collection;
}
public T ReadCompatible<T>()
{
return MessageSerializer.DeserializeCompatible<T>(this);
}
public T Read<T>() where T : IBinarySerializable
{
byte type = ReadByte();
if (type == 0) return default(T);
var item = (T)Activator.CreateInstance<T>();
item.Deserialize(this);
return item;
}
public List<string> ReadStringCollection()
{
int count = ReadInt32();
var collection = new List<string>(count);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
collection.Add(ReadString());
}
}
return collection;
}
public List<IPAddress> ReadIPCollection()
{
int count = ReadInt32();
var collection = new List<IPAddress>(count);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
collection.Add(ReadIP());
}
}
return collection;
}
public List<IPEndPoint> ReadIPEndPointCollection()
{
int count = ReadInt32();
var collection = new List<IPEndPoint>(count);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
collection.Add(ReadIPEndpoint());
}
}
return collection;
}
public List<Guid> ReadGuidCollection()
{
int count = ReadInt32();
var collection = new List<Guid>(count);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
collection.Add(ReadGuid());
}
}
return collection;
}
public List<DateTime> ReadDateTimeCollection()
{
int count = ReadInt32();
var collection = new List<DateTime>(count);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
collection.Add(ReadDateTime() ?? DateTime.MinValue);
}
}
return collection;
}
public List<Int64> ReadInt64Collection()
{
int count = ReadInt32();
var collection = new List<Int64>(count);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
collection.Add(ReadLong());
}
}
return collection;
}
public List<Int32> ReadInt32Collection()
{
int count = ReadInt32();
var collection = new List<Int32>(count);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
collection.Add(ReadInt32());
}
}
return collection;
}
public List<Double> ReadDoubleCollection()
{
int count = ReadInt32();
var collection = new List<Double>(count);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
collection.Add(ReadDouble());
}
}
return collection;
}
public List<bool> ReadBooleanCollection()
{
int count = ReadInt32();
var collection = new List<bool>(count);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
collection.Add(ReadBoolean());
}
}
return collection;
}
public List<byte> ReadByteCollection()
{
int count = ReadInt32();
var collection = new List<byte>(count);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
collection.Add(ReadByte());
}
}
return collection;
}
public List<byte[]> ReadByteArrayCollection()
{
int count = ReadInt32();
var collection = new List<byte[]>(count);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
collection.Add(ReadBytes());
}
}
return collection;
}
#endregion
/// <summary>
/// Очистка
/// </summary>
public void Dispose()
{
_stream.Dispose();
}
}
}

Powered by TurnKey Linux.