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(); } } }