using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Net; using System.Runtime.Serialization; using System.Text; 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 sealed 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 p1 = ReadInt32(); var p2 = ReadInt32(); var p3 = ReadInt32(); var p4 = ReadInt32(); 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); 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); 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 TimeOnly? ReadTime() { var is_null = ReadByte(); if (is_null == 0) return null; var ts = ReadTimeSpan(); return TimeOnly.FromTimeSpan(ts); } public DateOnly? ReadDate() { var is_null = ReadByte(); if (is_null == 0) return null; var days = ReadInt32(); return DateOnly.FromDayNumber(days); } 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 /// public bool CheckOutOfRange(int offset) { return _accessor.CheckOutOfRange(offset); } #region Extensions #region Collections 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 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 ReadUInt64Collection() { int count = ReadInt32(); var collection = new List(count); if (count > 0) { for (int i = 0; i < count; i++) { collection.Add(ReadULong()); } } return collection; } public List ReadUInt32Collection() { int count = ReadInt32(); var collection = new List(count); if (count > 0) { for (int i = 0; i < count; i++) { collection.Add(ReadUInt32()); } } return collection; } public List ReadCharCollection() { int count = ReadInt32(); var collection = new List(count); if (count > 0) { for (int i = 0; i < count; i++) { collection.Add(ReadChar()); } } return collection; } public List ReadShortCollection() { int count = ReadInt32(); var collection = new List(count); if (count > 0) { for (int i = 0; i < count; i++) { collection.Add(ReadShort()); } } return collection; } public List ReadUShortCollection() { int count = ReadInt32(); var collection = new List(count); if (count > 0) { for (int i = 0; i < count; i++) { collection.Add(ReadUShort()); } } return collection; } public List ReadFloatCollection() { int count = ReadInt32(); var collection = new List(count); if (count > 0) { for (int i = 0; i < count; i++) { collection.Add(ReadFloat()); } } 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; } public List ReadDecimalCollection() { int count = ReadInt32(); var collection = new List(count); if (count > 0) { for (int i = 0; i < count; i++) { collection.Add(ReadDecimal()); } } return collection; } public List ReadTimeSpanCollection() { int count = ReadInt32(); var collection = new List(count); if (count > 0) { for (int i = 0; i < count; i++) { collection.Add(ReadTimeSpan()); } } return collection; } #endregion #region Collections lazy public IEnumerable ReadCollectionLazy() where T : IBinarySerializable, new() { int count = ReadInt32(); if (count > 0) { for (int i = 0; i < count; i++) { var item = new T(); item.Deserialize(this); yield return item; } } } public IEnumerable ReadStringCollectionLazy() { int count = ReadInt32(); if (count > 0) { for (int i = 0; i < count; i++) { yield return ReadString(); } } } public IEnumerable ReadIPCollectionLazy() { int count = ReadInt32(); if (count > 0) { for (int i = 0; i < count; i++) { yield return ReadIP(); } } } public IEnumerable ReadIPEndPointCollectionLazy() { int count = ReadInt32(); if (count > 0) { for (int i = 0; i < count; i++) { yield return ReadIPEndpoint(); } } } public IEnumerable ReadGuidCollectionLazy() { int count = ReadInt32(); if (count > 0) { for (int i = 0; i < count; i++) { yield return ReadGuid(); } } } public IEnumerable ReadDateTimeCollectionLazy() { int count = ReadInt32(); if (count > 0) { for (int i = 0; i < count; i++) { yield return ReadDateTime() ?? DateTime.MinValue; } } } public IEnumerable ReadInt64CollectionLazy() { int count = ReadInt32(); if (count > 0) { for (int i = 0; i < count; i++) { yield return ReadLong(); } } } public IEnumerable ReadInt32CollectionLazy() { int count = ReadInt32(); if (count > 0) { for (int i = 0; i < count; i++) { yield return ReadInt32(); } } } public IEnumerable ReadUInt64CollectionLazy() { int count = ReadInt32(); if (count > 0) { for (int i = 0; i < count; i++) { yield return ReadULong(); } } } public IEnumerable ReadUInt32CollectionLazy() { int count = ReadInt32(); if (count > 0) { for (int i = 0; i < count; i++) { yield return ReadUInt32(); } } } public IEnumerable ReadCharCollectionLazy() { int count = ReadInt32(); if (count > 0) { for (int i = 0; i < count; i++) { yield return ReadChar(); } } } public IEnumerable ReadShortCollectionLazy() { int count = ReadInt32(); if (count > 0) { for (int i = 0; i < count; i++) { yield return ReadShort(); } } } public IEnumerable ReadUShortCollectionLazy() { int count = ReadInt32(); if (count > 0) { for (int i = 0; i < count; i++) { yield return ReadUShort(); } } } public IEnumerable ReadFloatCollectionLazy() { int count = ReadInt32(); if (count > 0) { for (int i = 0; i < count; i++) { yield return ReadFloat(); } } } public IEnumerable ReadDoubleCollectionLazy() { int count = ReadInt32(); if (count > 0) { for (int i = 0; i < count; i++) { yield return ReadDouble(); } } } public IEnumerable ReadBooleanCollectionLazy() { int count = ReadInt32(); if (count > 0) { for (int i = 0; i < count; i++) { yield return ReadBoolean(); } } } public IEnumerable ReadByteCollectionLazy() { int count = ReadInt32(); if (count > 0) { for (int i = 0; i < count; i++) { yield return ReadByte(); } } } public IEnumerable ReadByteArrayCollectionLazy() { int count = ReadInt32(); if (count > 0) { for (int i = 0; i < count; i++) { yield return ReadBytes(); } } } public IEnumerable ReadDecimalCollectionLazy() { int count = ReadInt32(); if (count > 0) { for (int i = 0; i < count; i++) { yield return ReadDecimal(); } } } public IEnumerable ReadTimeSpanCollectionLazy() { int count = ReadInt32(); if (count > 0) { for (int i = 0; i < count; i++) { yield return ReadTimeSpan(); } } } #endregion #region Arrays public T[] ReadArray() where T : IBinarySerializable, new() { int count = ReadInt32(); var array = new T[count]; if (count > 0) { for (int i = 0; i < count; i++) { var item = new T(); item.Deserialize(this); array[i] = item; } } return array; } public string[] ReadStringArray() { int count = ReadInt32(); var array = new string[count]; if (count > 0) { for (int i = 0; i < count; i++) { array[i] = ReadString(); } } return array; } public IPAddress[] ReadIPArray() { int count = ReadInt32(); var array = new IPAddress[count]; if (count > 0) { for (int i = 0; i < count; i++) { array[i] = ReadIP(); } } return array; } public IPEndPoint[] ReadIPEndPointArray() { int count = ReadInt32(); var array = new IPEndPoint[count]; if (count > 0) { for (int i = 0; i < count; i++) { array[i] = ReadIPEndpoint(); } } return array; } public Guid[] ReadGuidArray() { int count = ReadInt32(); var array = new Guid[count]; if (count > 0) { for (int i = 0; i < count; i++) { array[i] = ReadGuid(); } } return array; } public DateTime[] ReadDateTimeArray() { int count = ReadInt32(); var array = new DateTime[count]; if (count > 0) { for (int i = 0; i < count; i++) { array[i] = (ReadDateTime() ?? DateTime.MinValue); } } return array; } public Int64[] ReadInt64Array() { int count = ReadInt32(); var array = new Int64[count]; if (count > 0) { for (int i = 0; i < count; i++) { array[i] = ReadLong(); } } return array; } public Int32[] ReadInt32Array() { int count = ReadInt32(); var array = new Int32[count]; if (count > 0) { for (int i = 0; i < count; i++) { array[i] = ReadInt32(); } } return array; } public UInt64[] ReadUInt64Array() { int count = ReadInt32(); var array = new UInt64[count]; if (count > 0) { for (int i = 0; i < count; i++) { array[i] = ReadULong(); } } return array; } public UInt32[] ReadUInt32Array() { int count = ReadInt32(); var array = new UInt32[count]; if (count > 0) { for (int i = 0; i < count; i++) { array[i] = ReadUInt32(); } } return array; } public char[] ReadCharArray() { int count = ReadInt32(); var array = new char[count]; if (count > 0) { for (int i = 0; i < count; i++) { array[i] = ReadChar(); } } return array; } public short[] ReadShortArray() { int count = ReadInt32(); var array = new short[count]; if (count > 0) { for (int i = 0; i < count; i++) { array[i] = ReadShort(); } } return array; } public ushort[] ReadUShortArray() { int count = ReadInt32(); var array = new ushort[count]; if (count > 0) { for (int i = 0; i < count; i++) { array[i] = ReadUShort(); } } return array; } public float[] ReadFloatArray() { int count = ReadInt32(); var array = new float[count]; if (count > 0) { for (int i = 0; i < count; i++) { array[i] = ReadFloat(); } } return array; } public Double[] ReadDoubleArray() { int count = ReadInt32(); var array = new Double[count]; if (count > 0) { for (int i = 0; i < count; i++) { array[i] = ReadDouble(); } } return array; } public bool[] ReadBooleanArray() { int count = ReadInt32(); var array = new bool[count]; if (count > 0) { for (int i = 0; i < count; i++) { array[i] = ReadBoolean(); } } return array; } public byte[] ReadByteArray() { return ReadBytes(); } public byte[][] ReadByteArrayArray() { int count = ReadInt32(); var array = new byte[count][]; if (count > 0) { for (int i = 0; i < count; i++) { array[i] = ReadBytes(); } } return array; } public decimal[] ReadDecimalArray() { int count = ReadInt32(); var array = new decimal[count]; if (count > 0) { for (int i = 0; i < count; i++) { array[i] = ReadDecimal(); } } return array; } public TimeSpan[] ReadTimeSpanArray() { int count = ReadInt32(); var array = new TimeSpan[count]; if (count > 0) { for (int i = 0; i < count; i++) { array[i] = ReadTimeSpan(); } } return array; } #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(); } } }