using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Net;
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;
}
///
/// 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 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();
}
}
}