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