using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Net; using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; using ZeroLevel.Services.Extensions; using ZeroLevel.Services.Memory; namespace ZeroLevel.Services.Serialization { /// /// A wrapper over a MemoryStream for reading, with a check for overflow /// public partial class MemoryStreamReader : IBinaryReader { private readonly IViewAccessor _accessor; private bool _reverseByteOrder = false; public void ReverseByteOrder(bool use_reverse_byte_order) { _reverseByteOrder = use_reverse_byte_order; } /// /// End of stream /// public bool EOS => _accessor.EOV; public MemoryStreamReader(byte[] data) { if (data == null) throw new ArgumentNullException(nameof(data)); _accessor = new StreamVewAccessor(new MemoryStream(data)); } public MemoryStreamReader(Stream stream) { if (stream == null) throw new ArgumentNullException(nameof(stream)); _accessor = new StreamVewAccessor(stream); } public MemoryStreamReader(MemoryStreamReader reader) { if (reader == null) throw new ArgumentNullException(nameof(reader)); _accessor = reader._accessor; } public MemoryStreamReader(IViewAccessor accessor) { if (accessor == null) throw new ArgumentNullException(nameof(accessor)); _accessor = accessor; } public long Position => _accessor.Position; public void SetPosition(long position) => _accessor.Seek(position); /// /// Flag reading /// public bool ReadBoolean() { return BitConverter.ToBoolean(new byte[1] { ReadByte() }, 0); } /// /// Reading byte /// public byte ReadByte() { var buffer = ReadBuffer(1); return buffer[0]; } public char ReadChar() { var buffer = ReadBuffer(2); return BitConverter.ToChar(buffer, 0); } /// /// Reading bytes /// /// public byte[] ReadBytes() { var length = BitConverter.ToInt32(ReadBuffer(4), 0); if (length == 0) return new byte[0]; return ReadBuffer(length); } public short ReadShort() { var buffer = ReadBuffer(2); return BitConverter.ToInt16(buffer, 0); } public ushort ReadUShort() { var buffer = ReadBuffer(2); return BitConverter.ToUInt16(buffer, 0); } /// /// Read 32-bit integer (4 bytes) /// public Int32 ReadInt32() { var buffer = ReadBuffer(4); return BitConverter.ToInt32(buffer, 0); } public UInt32 ReadUInt32() { var buffer = ReadBuffer(4); return BitConverter.ToUInt32(buffer, 0); } public decimal ReadDecimal() { var arr = ReadBuffer(16); var p1 = BitConverter.ToInt32(arr, 0); var p2 = BitConverter.ToInt32(arr, 4); var p3 = BitConverter.ToInt32(arr, 8); var p4 = BitConverter.ToInt32(arr, 12); return BitConverterExt.ToDecimal(new int[] { p1, p2, p3, p4 }); } /// /// Read integer 64-bit number (8 bytes) /// public Int64 ReadLong() { var buffer = ReadBuffer(8); return BitConverter.ToInt64(buffer, 0); } public UInt64 ReadULong() { var buffer = ReadBuffer(8); return BitConverter.ToUInt64(buffer, 0); } public TimeSpan ReadTimeSpan() { return new TimeSpan(ReadLong()); } public float ReadFloat() { var buffer = ReadBuffer(4); return BitConverter.ToSingle(buffer, 0); } public double ReadDouble() { var buffer = ReadBuffer(8); return BitConverter.ToDouble(buffer, 0); } /// /// Read string (4 bytes per length + Length bytes) /// public string ReadString() { var length = BitConverter.ToInt32(ReadBuffer(4), 0); if (length == 0) return null; var buffer = ReadBuffer(length); return Encoding.UTF8.GetString(buffer); } /// /// Read GUID (16 bytes) /// public Guid ReadGuid() { var buffer = ReadBuffer(16); return new Guid(buffer); } /// /// Reading byte-package (read the size of the specified number of bytes, and then the packet itself read size) /// public byte[] ReadBuffer(int count) { if (CheckOutOfRange(count)) throw new OutOfMemoryException("Array index out of bounds"); var buffer = _accessor.ReadBuffer(count).Result; if (_reverseByteOrder && count > 1) { byte b; for (int i = 0; i < (count >> 1); i++) { b = buffer[i]; buffer[i] = buffer[count - i - 1]; buffer[count - i - 1] = b; } } return buffer; } public bool TryReadBuffer(int count, out byte[] buffer) { if (CheckOutOfRange(count)) { buffer = null; return false; } try { buffer = _accessor.ReadBuffer(count).Result; if (_reverseByteOrder && count > 1) { byte b; for (int i = 0; i < (count >> 1); i++) { b = buffer[i]; buffer[i] = buffer[count - i - 1]; buffer[count - i - 1] = b; } } } catch (Exception ex) { Log.SystemError(ex, $"[MemoryStreamReader.TryReadBuffer] Fault read {count} bytes"); buffer = null; return false; } return true; } /// /// Reading the datetime /// /// 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 exists = ReadByte(); if (exists == 1) { var addr = ReadBytes(); return new IPAddress(addr); } return null; } public IPEndPoint ReadIPEndpoint() { var exists = ReadByte(); if (exists == 1) { var addr = ReadIP(); var port = ReadInt32(); return new IPEndPoint(addr, port); } return null; } /// /// Check if data reading is outside the stream /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool CheckOutOfRange(int offset) => _accessor.CheckOutOfRange(offset); #region Extensions #region Collections private List ReadList(Func read) { int count = ReadInt32(); var collection = new List(count); if (count > 0) { for (int i = 0; i < count; i++) { collection.Add(read.Invoke()); } } return collection; } public List ReadCollection() where T : IBinarySerializable, new() => ReadList(() => { var item = new T(); item.Deserialize(this); return item; }); public List ReadStringCollection() => ReadList(ReadString); public List ReadIPCollection() => ReadList(ReadIP); public List ReadIPEndPointCollection() => ReadList(ReadIPEndpoint); public List ReadGuidCollection() => ReadList(ReadGuid); public List ReadDateTimeCollection() => ReadList(ReadDateTime); public List ReadInt64Collection() => ReadList(ReadLong); public List ReadInt32Collection() => ReadList(ReadInt32); public List ReadUInt64Collection() => ReadList(ReadULong); public List ReadUInt32Collection() => ReadList(ReadUInt32); public List ReadCharCollection() => ReadList(ReadChar); public List ReadShortCollection() => ReadList(ReadShort); public List ReadUShortCollection() => ReadList(ReadUShort); public List ReadFloatCollection() => ReadList(ReadFloat); public List ReadDoubleCollection() => ReadList(ReadDouble); public List ReadBooleanCollection() => ReadList(ReadBoolean); public List ReadByteCollection() => ReadList(ReadByte); public List ReadByteArrayCollection() => ReadList(ReadBytes); public List ReadDecimalCollection() => ReadList(ReadDecimal); public List ReadTimeSpanCollection() => ReadList(ReadTimeSpan); #endregion #region Collections lazy private IEnumerable ReadEnumerable(Func read) { int count = ReadInt32(); if (count > 0) { for (int i = 0; i < count; i++) { yield return read.Invoke(); } } } public IEnumerable ReadCollectionLazy() where T : IBinarySerializable, new() => ReadEnumerable(() => { var item = new T(); item.Deserialize(this); return item; }); public IEnumerable ReadStringCollectionLazy() => ReadEnumerable(ReadString); public IEnumerable ReadIPCollectionLazy() => ReadEnumerable(ReadIP); public IEnumerable ReadIPEndPointCollectionLazy() => ReadEnumerable(ReadIPEndpoint); public IEnumerable ReadGuidCollectionLazy() => ReadEnumerable(ReadGuid); public IEnumerable ReadDateTimeCollectionLazy() => ReadEnumerable(ReadDateTime); public IEnumerable ReadInt64CollectionLazy() => ReadEnumerable(ReadLong); public IEnumerable ReadInt32CollectionLazy() => ReadEnumerable(ReadInt32); public IEnumerable ReadUInt64CollectionLazy() => ReadEnumerable(ReadULong); public IEnumerable ReadUInt32CollectionLazy() => ReadEnumerable(ReadUInt32); public IEnumerable ReadCharCollectionLazy() => ReadEnumerable(ReadChar); public IEnumerable ReadShortCollectionLazy() => ReadEnumerable(ReadShort); public IEnumerable ReadUShortCollectionLazy() => ReadEnumerable(ReadUShort); public IEnumerable ReadFloatCollectionLazy() => ReadEnumerable(ReadFloat); public IEnumerable ReadDoubleCollectionLazy() => ReadEnumerable(ReadDouble); public IEnumerable ReadBooleanCollectionLazy() => ReadEnumerable(ReadBoolean); public IEnumerable ReadByteCollectionLazy() => ReadEnumerable(ReadByte); public IEnumerable ReadByteArrayCollectionLazy() => ReadEnumerable(ReadBytes); public IEnumerable ReadDecimalCollectionLazy() => ReadEnumerable(ReadDecimal); public IEnumerable ReadTimeSpanCollectionLazy() => ReadEnumerable(ReadTimeSpan); #endregion #region Arrays private T[] ReadArray(Func read) { int count = ReadInt32(); var array = new T[count]; if (count > 0) { for (int i = 0; i < count; i++) { array[i] = read.Invoke(); } } return array; } public T[] ReadArray() where T : IBinarySerializable, new() => ReadArray(() => { var item = new T(); item.Deserialize(this); return item; }); public string[] ReadStringArray() => ReadArray(ReadString); public IPAddress[] ReadIPArray() => ReadArray(ReadIP); public IPEndPoint[] ReadIPEndPointArray() => ReadArray(ReadIPEndpoint); public Guid[] ReadGuidArray() => ReadArray(ReadGuid); public DateTime?[] ReadDateTimeArray() => ReadArray(ReadDateTime); public Int64[] ReadInt64Array() => ReadArray(ReadLong); public Int32[] ReadInt32Array() => ReadArray(ReadInt32); public UInt64[] ReadUInt64Array() => ReadArray(ReadULong); public UInt32[] ReadUInt32Array() => ReadArray(ReadUInt32); public char[] ReadCharArray() => ReadArray(ReadChar); public short[] ReadShortArray() => ReadArray(ReadShort); public ushort[] ReadUShortArray() => ReadArray(ReadUShort); public float[] ReadFloatArray() => ReadArray(ReadFloat); public Double[] ReadDoubleArray() => ReadArray(ReadDouble); public bool[] ReadBooleanArray() => ReadArray(ReadBoolean); public byte[] ReadByteArray() => ReadBytes(); public byte[][] ReadByteArrayArray() => ReadArray(ReadBytes); public decimal[] ReadDecimalArray() => ReadArray(ReadDecimal); public TimeSpan[] ReadTimeSpanArray() => ReadArray(ReadTimeSpan); #endregion public Dictionary ReadDictionary() { int count = ReadInt32(); var collection = new Dictionary(count); if (count > 0) { TKey key; TValue value; for (int i = 0; i < count; i++) { key = ReadCompatible(); value = ReadCompatible(); collection.Add(key, value); } } return collection; } public ConcurrentDictionary ReadDictionaryAsConcurrent() { int count = ReadInt32(); var collection = new ConcurrentDictionary(); if (count > 0) { TKey key; TValue value; for (int i = 0; i < count; i++) { key = ReadCompatible(); value = ReadCompatible(); collection.TryAdd(key, value); } } 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 bool TryReadByte(out byte b) { if (TryReadBuffer(1, out var buffer)) { b = buffer[0]; return true; } b = default; return false; } public bool TryRead(out T item) where T : IBinarySerializable { if (TryReadByte(out var type)) { if (type == 0) { item = default(T); return true; } try { var o = (IBinarySerializable)FormatterServices.GetUninitializedObject(typeof(T)); o.Deserialize(this); item = (T)o; return true; } catch (Exception ex) { Log.SystemError(ex, "[MemoryStreamReader.TryRead]"); } } item = default; return false; } public T Read(object arg) where T : IBinarySerializable { byte type = ReadByte(); if (type == 0) return default(T); var item = (T)Activator.CreateInstance(typeof(T), arg); item.Deserialize(this); return item; } #endregion Extensions public void Dispose() { _accessor.Dispose(); } } public partial class MemoryStreamReader : IAsyncBinaryReader { /// /// Reading byte-package (read the size of the specified number of bytes, and then the packet itself read size) /// public async Task ReadBufferAsync(int count) { if (CheckOutOfRange(count)) throw new OutOfMemoryException("Array index out of bounds"); var buffer = await _accessor.ReadBuffer(count); if (_reverseByteOrder && count > 1) { byte b; for (int i = 0; i < (count >> 1); i++) { b = buffer[i]; buffer[i] = buffer[count - i - 1]; buffer[count - i - 1] = b; } } return buffer; } public async Task TryReadBufferAsync(int count, byte[] buffer) { if (CheckOutOfRange(count)) { buffer = null; return false; } try { buffer = await _accessor.ReadBuffer(count); if (_reverseByteOrder && count > 1) { byte b; for (int i = 0; i < (count >> 1); i++) { b = buffer[i]; buffer[i] = buffer[count - i - 1]; buffer[count - i - 1] = b; } } } catch (Exception ex) { Log.SystemError(ex, $"[MemoryStreamReader.TryReadBufferAsync] Fault read {count} bytes"); buffer = null; return false; } return true; } /// /// Flag reading /// public async Task ReadBooleanAsync() { return BitConverter.ToBoolean(new byte[1] { await ReadByteAsync() }, 0); } /// /// Reading byte /// public async Task ReadByteAsync() { var buffer = await ReadBufferAsync(1); return buffer[0]; } public async Task ReadCharAsync() { var buffer = await ReadBufferAsync(2); return BitConverter.ToChar(buffer, 0); } /// /// Reading bytes /// /// public async Task ReadBytesAsync() { var length = BitConverter.ToInt32(await ReadBufferAsync(4), 0); if (length == 0) return new byte[0]; return ReadBuffer(length); } public async Task ReadShortAsync() { var buffer = await ReadBufferAsync(2); return BitConverter.ToInt16(buffer, 0); } public async Task ReadUShortAsync() { var buffer = await ReadBufferAsync(2); return BitConverter.ToUInt16(buffer, 0); } /// /// Read 32-bit integer (4 bytes) /// public async Task ReadInt32Async() { var buffer = await ReadBufferAsync(4); return BitConverter.ToInt32(buffer, 0); } public async Task ReadUInt32Async() { var buffer = await ReadBufferAsync(4); return BitConverter.ToUInt32(buffer, 0); } public async Task ReadDecimalAsync() { var arr = await ReadBufferAsync(16); var p1 = BitConverter.ToInt32(arr, 0); var p2 = BitConverter.ToInt32(arr, 4); var p3 = BitConverter.ToInt32(arr, 8); var p4 = BitConverter.ToInt32(arr, 12); return BitConverterExt.ToDecimal(new int[] { p1, p2, p3, p4 }); } /// /// Read integer 64-bit number (8 bytes) /// public async Task ReadLongAsync() { var buffer = await ReadBufferAsync(8); return BitConverter.ToInt64(buffer, 0); } public async Task ReadULongAsync() { var buffer = await ReadBufferAsync(8); return BitConverter.ToUInt64(buffer, 0); } public async Task ReadTimeSpanAsync() { return new TimeSpan(await ReadLongAsync()); } public async Task ReadFloatAsync() { var buffer = await ReadBufferAsync(4); return BitConverter.ToSingle(buffer, 0); } public async Task ReadDoubleAsync() { var buffer = await ReadBufferAsync(8); return BitConverter.ToDouble(buffer, 0); } /// /// Read string (4 bytes per length + Length bytes) /// public async Task ReadStringAsync() { var length = BitConverter.ToInt32(await ReadBufferAsync(4), 0); if (length == 0) return null; var buffer = await ReadBufferAsync(length); return Encoding.UTF8.GetString(buffer); } /// /// Read GUID (16 bytes) /// public async Task ReadGuidAsync() { var buffer = await ReadBufferAsync(16); return new Guid(buffer); } /// /// Reading the datetime /// /// public async Task ReadDateTimeAsync() { var is_null = ReadByte(); if (is_null == 0) return null; var buffer = await ReadBufferAsync(8); long deserialized = BitConverter.ToInt64(buffer, 0); return DateTime.FromBinary(deserialized); } public async Task ReadIPAsync() { var exists = await ReadByteAsync(); if (exists == 1) { var addr = await ReadBytesAsync(); return new IPAddress(addr); } return null; } public async Task ReadIPEndpointAsync() { var exists = await ReadByteAsync(); if (exists == 1) { var addr = await ReadIPAsync(); var port = await ReadInt32Async(); return new IPEndPoint(addr, port); } return null; } #region Extensions #region Collections private async Task> ReadListAsync(Func> readAsync, Func read) { int count = await ReadInt32Async(); var collection = new List(count); if (count > 0) { if (_accessor.IsMemoryStream) { for (int i = 0; i < count; i++) { collection.Add(read.Invoke()); } } else { for (int i = 0; i < count; i++) { collection.Add(await readAsync.Invoke()); } } } return collection; } public async Task> ReadCollectionAsync() where T : IAsyncBinarySerializable, new() { int count = await ReadInt32Async(); var collection = new List(count); if (count > 0) { for (int i = 0; i < count; i++) { var item = new T(); await item.DeserializeAsync(this); collection.Add(item); } } return collection; } public async Task> ReadStringCollectionAsync() => await ReadListAsync(ReadStringAsync, ReadString); public async Task> ReadIPCollectionAsync() => await ReadListAsync(ReadIPAsync, ReadIP); public async Task> ReadIPEndPointCollectionAsync() => await ReadListAsync(ReadIPEndpointAsync, ReadIPEndpoint); public async Task> ReadGuidCollectionAsync() => await ReadListAsync(ReadGuidAsync, ReadGuid); public async Task> ReadDateTimeCollectionAsync() => await ReadListAsync(ReadDateTimeAsync, ReadDateTime); public async Task> ReadInt64CollectionAsync() => await ReadListAsync(ReadLongAsync, ReadLong); public async Task> ReadInt32CollectionAsync() => await ReadListAsync(ReadInt32Async, ReadInt32); public async Task> ReadUInt64CollectionAsync() => await ReadListAsync(ReadULongAsync, ReadULong); public async Task> ReadUInt32CollectionAsync() => await ReadListAsync(ReadUInt32Async, ReadUInt32); public async Task> ReadCharCollectionAsync() => await ReadListAsync(ReadCharAsync, ReadChar); public async Task> ReadShortCollectionAsync() => await ReadListAsync(ReadShortAsync, ReadShort); public async Task> ReadUShortCollectionAsync() => await ReadListAsync(ReadUShortAsync, ReadUShort); public async Task> ReadFloatCollectionAsync() => await ReadListAsync(ReadFloatAsync, ReadFloat); public async Task> ReadDoubleCollectionAsync() => await ReadListAsync(ReadDoubleAsync, ReadDouble); public async Task> ReadBooleanCollectionAsync() => await ReadListAsync(ReadBooleanAsync, ReadBoolean); public async Task> ReadByteCollectionAsync() => await ReadListAsync(ReadByteAsync, ReadByte); public async Task> ReadByteArrayCollectionAsync() => await ReadListAsync(ReadBytesAsync, ReadBytes); public async Task> ReadDecimalCollectionAsync() => await ReadListAsync(ReadDecimalAsync, ReadDecimal); public async Task> ReadTimeSpanCollectionAsync() => await ReadListAsync(ReadTimeSpanAsync, ReadTimeSpan); #endregion #region Arrays private async Task ReadArrayAsync(Func> readAsync, Func read) { int count = await ReadInt32Async(); var array = new T[count]; if (count > 0) { if (_accessor.IsMemoryStream) { for (int i = 0; i < count; i++) { array[i] = read.Invoke(); } } else { for (int i = 0; i < count; i++) { array[i] = await readAsync.Invoke(); } } } return array; } public async Task ReadArrayAsync() where T : IAsyncBinarySerializable, new() { int count = ReadInt32(); var array = new T[count]; if (count > 0) { for (int i = 0; i < count; i++) { var item = new T(); await item.DeserializeAsync(this); array[i] = item; } } return array; } public async Task ReadStringArrayAsync() => await ReadArrayAsync(ReadStringAsync, ReadString); public async Task ReadIPArrayAsync() => await ReadArrayAsync(ReadIPAsync, ReadIP); public async Task ReadIPEndPointArrayAsync() => await ReadArrayAsync(ReadIPEndpointAsync, ReadIPEndpoint); public async Task ReadGuidArrayAsync() => await ReadArrayAsync(ReadGuidAsync, ReadGuid); public async Task ReadDateTimeArrayAsync() => await ReadArrayAsync(ReadDateTimeAsync, ReadDateTime); public async Task ReadInt64ArrayAsync() => await ReadArrayAsync(ReadLongAsync, ReadLong); public async Task ReadInt32ArrayAsync() => await ReadArrayAsync(ReadInt32Async, ReadInt32); public async Task ReadUInt64ArrayAsync() => await ReadArrayAsync(ReadULongAsync, ReadULong); public async Task ReadUInt32ArrayAsync() => await ReadArrayAsync(ReadUInt32Async, ReadUInt32); public async Task ReadCharArrayAsync() => await ReadArrayAsync(ReadCharAsync, ReadChar); public async Task ReadShortArrayAsync() => await ReadArrayAsync(ReadShortAsync, ReadShort); public async Task ReadUShortArrayAsync() => await ReadArrayAsync(ReadUShortAsync, ReadUShort); public async Task ReadFloatArrayAsync() => await ReadArrayAsync(ReadFloatAsync, ReadFloat); public async Task ReadDoubleArrayAsync() => await ReadArrayAsync(ReadDoubleAsync, ReadDouble); public async Task ReadBooleanArrayAsync() => await ReadArrayAsync(ReadBooleanAsync, ReadBoolean); public async Task ReadByteArrayAsync() { if (_accessor.IsMemoryStream) { return ReadBytes(); } return await ReadBytesAsync(); } public async Task ReadByteArrayArrayAsync() => await ReadArrayAsync(ReadBytesAsync, ReadBytes); public async Task ReadDecimalArrayAsync() => await ReadArrayAsync(ReadDecimalAsync, ReadDecimal); public async Task ReadTimeSpanArrayAsync() => await ReadArrayAsync(ReadTimeSpanAsync, ReadTimeSpan); #endregion public async Task> ReadDictionaryAsync() { int count = ReadInt32(); var collection = new Dictionary(count); if (count > 0) { TKey key; TValue value; for (int i = 0; i < count; i++) { key = await ReadCompatibleAsync(); value = await ReadCompatibleAsync(); collection.Add(key, value); } } return collection; } public async Task> ReadDictionaryAsConcurrentAsync() { int count = ReadInt32(); var collection = new ConcurrentDictionary(); if (count > 0) { TKey key; TValue value; for (int i = 0; i < count; i++) { key = await ReadCompatibleAsync(); value = await ReadCompatibleAsync(); collection.TryAdd(key, value); } } return collection; } public async Task ReadCompatibleAsync() { return await MessageSerializer.DeserializeCompatibleAsync(this); } public async Task ReadAsync() where T : IAsyncBinarySerializable { byte type = await ReadByteAsync(); if (type == 0) return default(T); var item = (T)Activator.CreateInstance(); await item.DeserializeAsync(this); return item; } public async Task ReadAsync(object arg) where T : IAsyncBinarySerializable { byte type = ReadByte(); if (type == 0) return default(T); var item = (T)Activator.CreateInstance(typeof(T), arg); await item.DeserializeAsync(this); return item; } #endregion Extensions } }