BufferHelpers.cs

using GenXdev.Buffers;
using System.Text;
 
namespace GenXdev.Helpers
{
    public static class BufferHelpers
    {
        public static byte[] Concat(byte[] buffer1, byte[] buffer2)
        {
            var result = new byte[buffer1.Length + buffer2.Length];
 
            Buffer.BlockCopy(buffer1, 0, result, 0, buffer1.Length);
            Buffer.BlockCopy(buffer2, 0, result, buffer1.Length, buffer2.Length);
 
            return result;
        }
 
        public static bool TryGetStringFromBuffer(ref int? Count, DynamicBuffer Buffer, out string Value, int maxLength)
        {
            // init output variaible
            Value = null;
 
            // does not have length value in buffer?
            if (Buffer.Count < sizeof(int))
            {
                Count = sizeof(int) - Buffer.Count;
                return false;
            }
 
            // read string length
            Buffer.Position = 0;
            var stringLength = Buffer.Reader.ReadInt32();
 
            if (stringLength < 0)
            {
                // disconnect client
                throw new InvalidOperationException("Length int too small < 0, possibly a client speaking an incompatible protocol.");
            }
 
            // check
 
            {
                if (stringLength > maxLength)
                {
                    // disconnect client
                    throw new InvalidOperationException("String is too long, possibly a client speaking an incompatible protocol.");
                }
            }
 
            // does not have the whole string in the buffer?
            if (Buffer.Count < sizeof(int) + stringLength)
            {
                Count = (sizeof(int) + stringLength) - Buffer.Count;
                return false;
            }
 
            // remove length
            Buffer.Remove(sizeof(int));
 
            // convert it
            Value = Encoding.UTF8.GetString(
 
                Buffer.RemoveBytes(stringLength)
            );
 
            return true;
        }
 
        public static bool TryGetStringAndInt32FromBuffer(ref int? Count, DynamicBuffer Buffer, out string Value, out Int32 IntValue, int maxLength)
        {
            // init output variaible
            Value = null;
            IntValue = 0;
 
            // does not have length value in buffer?
            if (Buffer.Count < sizeof(int))
            {
                Count = sizeof(int) - Buffer.Count;
                return false;
            }
 
            // read string length
            Buffer.Position = 0;
            var stringLength = Buffer.Reader.ReadInt32();
 
            if (stringLength < 0)
            {
                // disconnect client
                throw new InvalidOperationException("Length int too small < 0, possibly a client speaking an incompatible protocol.");
            }
 
            // check
            if (stringLength > maxLength)
            {
                // disconnect client
                throw new InvalidOperationException("String is too long, possibly a client speaking an incompatible protocol.");
            }
 
            // does not have the whole string in the buffer?
            if (Buffer.Count < sizeof(int) + stringLength + sizeof(Int32))
            {
                Count = (sizeof(int) + stringLength + sizeof(Int32)) - Buffer.Count;
                return false;
            }
 
            // remove length
            Buffer.Remove(sizeof(int));
 
            // convert it
            Value = Encoding.UTF8.GetString(
 
                Buffer.RemoveBytes(stringLength)
            );
 
            // get Int32 value
            var pos = Buffer.Position;
            Buffer.Position = 0;
            IntValue = Buffer.Reader.ReadInt32();
            Buffer.Position = pos;
            Buffer.Remove(sizeof(Int32));
 
            return true;
        }
 
        public static bool TryGetStringFromBuffer(DynamicBuffer Buffer, out string Value, int maxLength)
        {
            // init output variaible
            Value = null;
 
            // does not have length value in buffer?
            if (Buffer.Count < sizeof(int))
            {
                return false;
            }
 
            // read string length
            Buffer.Position = 0;
            var stringLength = Buffer.Reader.ReadInt32();
 
            if (stringLength < 0)
            {
                // disconnect client
                throw new InvalidOperationException("Length int too small < 0, possibly a client speaking an incompatible protocol.");
            }
 
            // check
 
            {
                if (stringLength > maxLength)
                {
                    // disconnect client
                    throw new InvalidOperationException("String is too long, possibly a client speaking an incompatible protocol.");
                }
            }
 
            // does not have the whole string in the buffer?
            if (Buffer.Count < sizeof(int) + stringLength)
            {
                return false;
            }
 
            // remove length
            Buffer.Remove(sizeof(int));
 
            // convert it
            Value = Encoding.UTF8.GetString(
 
                Buffer.RemoveBytes(stringLength)
            );
 
            return true;
        }
 
        public static bool TryGetStringAndInt32FromBuffer(DynamicBuffer Buffer, out string Value, out Int32 IntValue, int maxLength)
        {
            // init output variaible
            Value = null;
            IntValue = 0;
 
            // does not have length value in buffer?
            if (Buffer.Count < sizeof(int))
            {
                return false;
            }
 
            // read string length
            Buffer.Position = 0;
            var stringLength = Buffer.Reader.ReadInt32();
 
            if (stringLength < 0)
            {
                // disconnect client
                throw new InvalidOperationException("Length int too small < 0, possibly a client speaking an incompatible protocol.");
            }
 
            // check
            if (stringLength > maxLength)
            {
                // disconnect client
                throw new InvalidOperationException("String is too long, possibly a client speaking an incompatible protocol.");
            }
 
            // does not have the whole string in the buffer?
            if (Buffer.Count < sizeof(int) + stringLength + sizeof(Int32))
            {
                return false;
            }
 
            // remove length
            Buffer.Remove(sizeof(int));
 
            // convert it
            Value = Encoding.UTF8.GetString(
 
                Buffer.RemoveBytes(stringLength)
            );
 
            // get Int32 value
            var pos = Buffer.Position;
            Buffer.Position = 0;
            IntValue = Buffer.Reader.ReadInt32();
            Buffer.Position = pos;
            Buffer.Remove(sizeof(Int32));
 
            return true;
        }
 
        public static bool TryGetStringFromBuffer(ref int? Count, DynamicBuffer Buffer, out bool FirstResultByte, out string Value, int maxLength)
        {
            // init output variaible
            Value = null;
            FirstResultByte = false;
 
            // does not have length value in buffer?
            if (Buffer.Count < sizeof(int) + 1)
            {
                Count = (sizeof(int) + 1) - Buffer.Count;
                return false;
            }
 
            // read string length
            Buffer.Position = 0;
            FirstResultByte = Buffer.Reader.ReadByte() == 1;
            var stringLength = Buffer.Reader.ReadInt32();
 
            if (stringLength < 0)
            {
                // disconnect client
                throw new InvalidOperationException("Length int too small < 0, possibly a client speaking an incompatible protocol.");
            }
 
            // check
 
            {
                if (stringLength > maxLength)
                {
                    // disconnect client
                    throw new InvalidOperationException("String is too long, possibly a client speaking an incompatible protocol.");
                }
            }
 
            // does not have the whole string in the buffer?
            if (Buffer.Count < (sizeof(int) + 1) + stringLength)
            {
                Count = ((sizeof(int) + 1) + stringLength) - Buffer.Count;
 
                return false;
            }
 
            // remove length + result byte
            Buffer.Remove(sizeof(int) + 1);
 
            // convert it
            Value = Encoding.UTF8.GetString(
 
                Buffer.RemoveBytes(stringLength)
            );
 
            return true;
        }
 
        public static bool TryGetStringAndInt32FromBuffer(ref int? Count, DynamicBuffer Buffer, out bool FirstResultByte, out string Value, out Int32 IntValue, int maxLength)
        {
            // init output variaible
            Value = null;
            IntValue = 0;
            FirstResultByte = false;
 
            // does not have length value in buffer?
            if (Buffer.Count < sizeof(int) + 1)
            {
                Count = (sizeof(int) + 1) - Buffer.Count;
                return false;
            }
 
            // read string length
            Buffer.Position = 0;
            FirstResultByte = Buffer.Reader.ReadByte() == 1;
            var stringLength = Buffer.Reader.ReadInt32();
 
            if (stringLength < 0)
            {
                // disconnect client
                throw new InvalidOperationException("Length int too small < 0, possibly a client speaking an incompatible protocol.");
            }
 
            // check
            if (stringLength > maxLength)
            {
                // disconnect client
                throw new InvalidOperationException("String is too long, possibly a client speaking an incompatible protocol.");
            }
 
            // does not have the whole string in the buffer?
            if (Buffer.Count < (sizeof(int) + 1) + stringLength + sizeof(Int32))
            {
                Count = ((sizeof(int) + 1) + stringLength + sizeof(Int32)) - Buffer.Count;
 
                return false;
            }
 
            // remove length + result byte
            Buffer.Remove(sizeof(int) + 1);
 
            // convert it
            Value = Encoding.UTF8.GetString(
 
                Buffer.RemoveBytes(stringLength)
            );
 
            // get Int32 value
            var pos = Buffer.Position;
            Buffer.Position = 0;
            IntValue = Buffer.Reader.ReadInt32();
            Buffer.Position = pos;
            Buffer.Remove(sizeof(Int32));
 
            return true;
        }
 
        public static bool TryGetBytesFromBuffer(ref int? Count, DynamicBuffer Buffer, out byte[] Bytes, int maxLength)
        {
            // init output variaible
            Bytes = null;
 
            // does not have length value in buffer?
            if (Buffer.Count < sizeof(int))
            {
                Count = (sizeof(int)) - Buffer.Count;
 
                return false;
            }
 
            // read length
            Buffer.Position = 0;
            var packetLength = Buffer.Reader.ReadInt32();
 
            if (packetLength < 0)
            {
                // disconnect client
                throw new InvalidOperationException("Length int too small < 0, possibly a client speaking an incompatible protocol.");
            }
 
            // check
 
            {
                if (packetLength > maxLength)
                {
                    // disconnect client
                    throw new InvalidOperationException("Length is too long.");
                }
            }
 
            // does not have the whole packet in the buffer?
            if (Buffer.Length < sizeof(int) + packetLength)
            {
                Count = (sizeof(int) + packetLength) - Buffer.Count;
 
                return false;
            }
 
            // createbuffer
            Bytes = new byte[packetLength];
 
            // remove length
            Buffer.Remove(sizeof(int));
 
            // remove from buffer
            Buffer.Remove(Bytes, 0, packetLength);
 
            return true;
        }
 
        public static bool TryGetBytesFromBuffer(DynamicBuffer Buffer, out byte[] Bytes, int maxLength)
        {
            // init output variaible
            Bytes = null;
 
            // does not have length value in buffer?
            if (Buffer.Count < sizeof(int))
            {
                return false;
            }
 
            // read string length
            Buffer.Position = 0;
            var packetLength = Buffer.Reader.ReadInt32();
 
            if (packetLength < 0)
            {
                // disconnect client
                throw new InvalidOperationException("Length int too small < 0, possibly a client speaking an incompatible protocol.");
            }
 
            // check
 
            {
                if (packetLength > maxLength)
                {
                    // disconnect client
                    throw new InvalidOperationException("Length is too long.");
                }
            }
 
            // does not have the whole packet in the buffer?
            if (Buffer.Length < sizeof(int) + packetLength)
            {
                return false;
            }
 
            // createbuffer
            Bytes = new byte[packetLength];
 
            // remove length
            Buffer.Remove(sizeof(int));
 
            // remove from buffer
            Buffer.Remove(Bytes, 0, packetLength);
 
            return true;
        }
 
        public static void WriteBytesToBuffer(DynamicBuffer Buffer, byte[] Bytes, int offset = 0, int? length = null)
        {
            // init length
            length = length.HasValue ? length.Value : Bytes.Length;
 
            // limit length
            length = Math.Min(Bytes.Length - offset, length.Value);
 
            // write length
            Buffer.Writer.Write(length.Value);
            Buffer.Writer.Flush();
 
            // write content
            Buffer.Add(Bytes, offset, length.Value);
        }
 
        public static void WriteStringToBuffer(DynamicBuffer Buffer, string Value)
        {
            var bytes = (new UTF8Encoding(false)).GetBytes(Value);
            Buffer.Writer.Write(bytes.Length);
            Buffer.Writer.Flush();
            Buffer.Add(bytes);
        }
 
        public static void WriteObjectJsonToBuffer(DynamicBuffer Buffer, object objectToWrite)
        {
            WriteStringToBuffer(Buffer, GenXdev.Helpers.Serialization.ToJson(objectToWrite));
        }
 
        public static bool TryGetObjectFromBuffer<T>(ref int? Count, DynamicBuffer Buffer, out T objectRead, int maxLength)
        {
            // init
            objectRead = default(T);
            string json = String.Empty;
 
            // got the whole json string out of the buffer?
            if (TryGetStringFromBuffer(ref Count, Buffer, out json, maxLength))
            {
                // de-serialize it, throw exception if failed, should never occur
                objectRead = GenXdev.Helpers.Serialization.FromJson<T>(json);
 
                return true;
            }
 
            return false;
        }
 
        public static bool TryGetBytesFromBuffer(ref int? Count, DynamicBuffer buffer, out byte[] bytes, out int additionalInt, int maxLength)
        {
            // init output variaible
            bytes = null;
            additionalInt = 0;
 
            // does not have length value in buffer?
            if (buffer.Count < sizeof(int) * 2)
            {
                Count = (sizeof(int) * 2) - buffer.Count;
                return false;
            }
 
            // read string length
            buffer.Position = 0;
            additionalInt = buffer.Reader.ReadInt32();
            var packetLength = buffer.Reader.ReadInt32();
 
            if (packetLength < 0)
            {
                // disconnect client
                throw new InvalidOperationException("Length is less then zero, possibly a client speaking an incompatible protocol, maxlength: " + maxLength.ToString() + ", received packet length: " + packetLength.ToString());
            }
 
            // check
 
            if (packetLength > maxLength)
            {
                // disconnect client
                throw new InvalidOperationException("Length is too long, possibly a client speaking an incompatible protocol, maxlength: " + maxLength.ToString() + ", received packet length: " + packetLength.ToString());
            }
 
 
            // does not have the whole in the buffer?
            if (buffer.Length < (sizeof(int) * 2) + packetLength)
            {
                Count = ((sizeof(int) * 2) + packetLength) - buffer.Count;
 
                return false;
            }
 
            // remove integers
            buffer.Remove(sizeof(int) * 2);
 
            // create buffer
            bytes = new byte[packetLength];
 
            // remove from buffer
            buffer.Remove(bytes, 0, packetLength);
 
            return true;
        }
 
        public static bool TryGetBytesFromBuffer(ref int? Count, DynamicBuffer buffer, out byte[] bytes, out string additionalString, int maxLength, int maxStringLength)
        {
            // init output variaible
            bytes = null;
            additionalString = "";
 
            // does not have length value in buffer?
            if (buffer.Count < sizeof(int) * 2)
            {
                Count = (sizeof(int) * 2) - buffer.Count;
                return false;
            }
 
            // read string length
            buffer.Position = 0;
            var additionalStrLength = buffer.Reader.ReadInt32();
            var packetLength = buffer.Reader.ReadInt32();
            var requiredBytes = (sizeof(int) * 2) + additionalStrLength + packetLength;
 
            if (packetLength < 0)
            {
                // disconnect client
                throw new InvalidOperationException("Length is less then zero, possibly a client speaking an incompatible protocol, maxlength: " + maxLength.ToString() + ", received packet length: " + packetLength.ToString());
            }
            if (additionalStrLength < 0)
            {
                // disconnect client
                throw new InvalidOperationException("Length is less then zero, possibly a client speaking an incompatible protocol, maxlength: " + maxLength.ToString() + ", received packet length: " + additionalStrLength.ToString());
            }
 
            // check
            if (packetLength > maxLength)
            {
                // disconnect client
                throw new InvalidOperationException("Length is too long, possibly a client speaking an incompatible protocol, maxlength: " + maxLength.ToString() + ", received packet length: " + packetLength.ToString());
            }
            if (additionalStrLength > maxStringLength)
            {
                // disconnect client
                throw new InvalidOperationException("Length is too long, possibly a client speaking an incompatible protocol, maxlength: " + maxStringLength.ToString() + ", received string length: " + additionalStrLength.ToString());
            }
            if (buffer.Count < requiredBytes)
            {
                Count = requiredBytes;
                return false;
            }
 
            // remove integers
            buffer.Remove(sizeof(int) * 2);
 
            if (additionalStrLength > 0)
            {
                additionalString = Encoding.UTF8.GetString(buffer.RemoveBytes(additionalStrLength));
            }
 
            // create buffer
            bytes = new byte[packetLength];
 
            // remove from buffer
            buffer.Remove(bytes, 0, packetLength);
 
            return true;
        }
 
        public static int TryGetBytesFromBuffer(ref int? Count, byte[] bytes, DynamicBuffer buffer, out int additionalInt, int maxLength)
        {
            // init output variaible
            additionalInt = 0;
 
            // does not have length value in buffer?
            if (buffer.Count < sizeof(int) * 2)
            {
                Count = (sizeof(int) * 2) - buffer.Count;
 
                return 0;
            }
 
            // read additional int
            buffer.Position = 0;
            additionalInt = buffer.Reader.ReadInt32();
 
 
            // read length
            var packetLength = buffer.Reader.ReadInt32();
 
            if (packetLength < 0)
            {
                // disconnect client
                throw new InvalidOperationException("Length is less then zero, possibly a client speaking an incompatible protocol, maxlength: " + maxLength.ToString() + ", received packet length: " + packetLength.ToString());
            }
 
            // check
 
 
            if (packetLength > maxLength)
            {
                // disconnect client
                throw new InvalidOperationException("Length is too long, possibly a client speaking an incompatible protocol.");
            }
 
 
            // check buffer
            if (bytes.Length < packetLength)
                throw new InvalidOperationException("Provided buffer to small");
 
            // does not have the it whole in the buffer?
            if (buffer.Length < (sizeof(int) * 2) + packetLength)
            {
                Count = ((sizeof(int) * 2) + packetLength) - buffer.Count;
 
                return 0;
            }
 
            // remove integers
            buffer.Remove(sizeof(int) * 2);
 
            // remove from buffer
            return buffer.Remove(bytes, 0, packetLength);
        }
 
        public static int TryGetBytesFromBuffer(ref int? Count, byte[] bytes, DynamicBuffer buffer, out string additionalString, int maxLength, int maxStringLength)
        {
            // init output variaible
            bytes = null;
            additionalString = "";
 
            // does not have length value in buffer?
            if (buffer.Count < sizeof(int) * 2)
            {
                Count = (sizeof(int) * 2) - buffer.Count;
                return 0;
            }
 
            // read string length
            buffer.Position = 0;
            var additionalStrLength = buffer.Reader.ReadInt32();
            var packetLength = buffer.Reader.ReadInt32();
            var requiredBytes = (sizeof(int) * 2) + additionalStrLength + packetLength;
 
            if (additionalStrLength < 0)
            {
                // disconnect client
                throw new InvalidOperationException("Length is less then zero, possibly a client speaking an incompatible protocol, maxlength: " + maxLength.ToString() + ", received packet length: " + additionalStrLength.ToString());
            }
            if (packetLength < 0)
            {
                // disconnect client
                throw new InvalidOperationException("Length is less then zero, possibly a client speaking an incompatible protocol, maxlength: " + maxLength.ToString() + ", received packet length: " + packetLength.ToString());
            }
            // check
 
            {
                if (packetLength > maxLength)
                {
                    // disconnect client
                    throw new InvalidOperationException("Length is too long, possibly a client speaking an incompatible protocol, maxlength: " + maxLength.ToString() + ", received packet length: " + packetLength.ToString());
                }
                if (additionalStrLength > maxStringLength)
                {
                    // disconnect client
                    throw new InvalidOperationException("Length is too long, possibly a client speaking an incompatible protocol, maxlength: " + maxStringLength.ToString() + ", received string length: " + additionalStrLength.ToString());
                }
            }
 
            // check buffer
            if (bytes.Length < packetLength)
                throw new InvalidOperationException("Provided buffer to small");
 
            // does not have the it whole in the buffer?
            if (buffer.Length < (sizeof(int) * 2) + (packetLength + additionalStrLength))
            {
                Count = ((sizeof(int) * 2) + packetLength) - buffer.Count;
 
                return 0;
            }
 
            // remove integers
            buffer.Remove(sizeof(int) * 2);
 
            if (additionalStrLength > 0)
            {
                additionalString = Encoding.UTF8.GetString(buffer.RemoveBytes(additionalStrLength));
            }
 
            // remove from buffer
            return buffer.Remove(bytes, 0, packetLength);
        }
 
        public static int TryGetBytesFromBuffer(byte[] bytes, DynamicBuffer buffer, out int additionalInt, int maxLength)
        {
            // init output variaible
            additionalInt = 0;
 
            // does not have length value in buffer?
            if (buffer.Count < sizeof(int) * 2)
            {
                return 0;
            }
 
            // read additional int
            buffer.Position = 0;
            additionalInt = buffer.Reader.ReadInt32();
 
            // read length
            var packetLength = buffer.Reader.ReadInt32();
 
            if (packetLength < 0)
            {
                // disconnect client
                throw new InvalidOperationException("Length is less then zero, possibly a client speaking an incompatible protocol, maxlength: " + maxLength.ToString() + ", received packet length: " + packetLength.ToString());
            }
 
            // check
 
            {
                if (packetLength > maxLength)
                {
                    // disconnect client
                    throw new InvalidOperationException("Length is too long, possibly a client speaking an incompatible protocol.");
                }
            }
 
            // check buffer
            if (bytes.Length < packetLength)
                throw new InvalidOperationException("Provided buffer to small");
 
            // does not have the it whole in the buffer?
            if (buffer.Length < (sizeof(int) * 2) + packetLength)
            {
                return 0;
            }
 
            // remove integers
            buffer.Remove(sizeof(int) * 2);
 
            // remove from buffer
            return buffer.Remove(bytes, 0, packetLength);
        }
 
        public static void WriteBytesToBuffer(DynamicBuffer buffer, byte[] bytes, int additionalInt, int offset = 0, int? length = null)
        {
            // init length
            int maxBytes = length.HasValue ? length.Value : bytes.Length;
 
            // limit length
            maxBytes = Math.Min(maxBytes, bytes.Length - offset);
 
            // write additional int
            buffer.Writer.Write(additionalInt);
 
            // write length
            buffer.Writer.Write(maxBytes);
            buffer.Writer.Flush();
 
            // write content
            buffer.Add(bytes, offset, maxBytes);
        }
 
        public static void WriteBytesToBuffer(DynamicBuffer buffer, byte[] bytes, string additionalString, int offset = 0, int? length = null)
        {
            // init length
            int maxBytes = length.HasValue ? length.Value : bytes.Length;
 
            // limit length
            maxBytes = Math.Min(maxBytes, bytes.Length - offset);
 
            if (additionalString.Length > 0)
            {
                var strBytes = (new UTF8Encoding(false)).GetBytes(additionalString);
 
                // write length
                buffer.Writer.Write(strBytes.Length);
                buffer.Writer.Flush();
 
                // write length
                buffer.Writer.Write(maxBytes);
                buffer.Writer.Flush();
 
                // add string
                buffer.Add(strBytes);
            }
            else
            {
                // write additional int
                buffer.Writer.Write(additionalString.Length);
 
                // write length
                buffer.Writer.Write(maxBytes);
                buffer.Writer.Flush();
            }
 
            // write content
            buffer.Add(bytes, offset, maxBytes);
        }
 
        public static unsafe bool ByteArraysAreEqual(byte[] buffer1, byte[] buffer2)
        {
            if (buffer1.Length != buffer2.Length)
                return false;
            if (buffer1.Length == 0)
                return true;
 
            fixed (byte* pb1 = buffer1)
            fixed (byte* pb2 = buffer2)
            {
                byte* b1 = pb1;
                byte* b2 = pb2;
 
                for (var i = 0; i < buffer1.Length; i++)
                {
                    if (*b1++ != *b2++)
                        return false;
                }
            }
 
            return true;
        }
    }
}