From 4e430731cc10d36804f2f6927f255f40029788dd Mon Sep 17 00:00:00 2001 From: Drew Tingen Date: Wed, 14 Jun 2023 06:05:22 -0400 Subject: [PATCH] feat[BigEndianBitConverter]: Added BigEndianBitConverter --- .../BigEndianBitConverterTest.cs | 154 +++++++++++++++ ICD.Common.Utils/BigEndianBitConverter.cs | 183 ++++++++++++++++++ .../ICD.Common.Utils_SimplSharp.csproj | 1 + 3 files changed, 338 insertions(+) create mode 100644 ICD.Common.Utils.Tests/BigEndianBitConverterTest.cs create mode 100644 ICD.Common.Utils/BigEndianBitConverter.cs diff --git a/ICD.Common.Utils.Tests/BigEndianBitConverterTest.cs b/ICD.Common.Utils.Tests/BigEndianBitConverterTest.cs new file mode 100644 index 0000000..303ed77 --- /dev/null +++ b/ICD.Common.Utils.Tests/BigEndianBitConverterTest.cs @@ -0,0 +1,154 @@ +using System; +using NUnit.Framework; +using NUnit.Framework.Internal; + +namespace ICD.Common.Utils.Tests +{ + [TestFixture] + public class BigEndianBitConverterTest + { + [TestCase(ushort.MaxValue, new byte[] {0xFF, 0xFF}, 0)] + [TestCase(ushort.MinValue, new byte[] {0x00, 0x00}, 0)] + [TestCase((ushort)255, new byte[]{0x00, 0xFF}, 0)] + [TestCase((ushort)65280, new byte[]{0xFF, 0x00},0)] + [TestCase(ushort.MaxValue, new byte[] {0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00}, 2)] + [TestCase(ushort.MinValue, new byte[] { 0xFF, 0x00, 0x00, 0xFF, 0xFF}, 1)] + [TestCase((ushort)255, new byte[]{0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00}, 3)] + [TestCase((ushort)65280, new byte[]{0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF},4)] + [TestCase((ushort)240, new byte[]{0x00, 0xFF,0x00, 0xF0, 0xFF}, 2)] + [TestCase((ushort)15, new byte[]{0x00, 0x0F},0)] + public void ToUshortTest(ushort expectedResult, byte[] value, int startIndex) + { + // We use system BitConverter for systems that are already big-endian + if (!BitConverter.IsLittleEndian) + Assert.Inconclusive(); + + + Assert.AreEqual(expectedResult, BigEndianBitConverter.ToUshort(value, startIndex)); + } + + [Test] + public void ToUshortExceptionTest() + { + // We use system BitConverter for systems that are already big-endian + if (!BitConverter.IsLittleEndian) + Assert.Inconclusive(); + + byte[] values = { 0x00, 0xFF, 0x0F, 0xF0, 0xFF, 0xAA, 0x55, 0xF1, 0x1F }; + + Assert.Throws(() => BigEndianBitConverter.ToUshort(null, 0)); + Assert.Throws(() => BigEndianBitConverter.ToUshort(values, -1)); + Assert.Throws(() => BigEndianBitConverter.ToUshort(values, 9)); + Assert.Throws(() => BigEndianBitConverter.ToUshort(values, 8)); + } + + [TestCase(short.MaxValue, new byte[] {0x7F, 0xFF}, 0)] + [TestCase(short.MinValue, new byte[] {0x80, 0x00}, 0)] + [TestCase(0, new byte[] {0x00, 0x00},0)] + [TestCase(-1, new byte[] {0xFF, 0xFF}, 0)] + [TestCase((short)255, new byte[]{0x00, 0xFF}, 0)] + [TestCase((short)-256, new byte[]{0xFF, 0x00},0)] + [TestCase(short.MaxValue, new byte[] {0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00}, 2)] + [TestCase(short.MinValue, new byte[] { 0xFF, 0x80, 0x00, 0xFF, 0xFF}, 1)] + [TestCase((short)255, new byte[]{0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00}, 3)] + [TestCase((short)-256, new byte[]{0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF},4)] + [TestCase((short)240, new byte[]{0x00, 0xFF,0x00, 0xF0, 0xFF}, 2)] + [TestCase((short)15, new byte[]{0x00, 0x0F},0)] + public void ToShortTest(short expectedResult, byte[] value, int startIndex) + { + // We use system BitConverter for systems that are already big-endian + if (!BitConverter.IsLittleEndian) + Assert.Inconclusive(); + + + Assert.AreEqual(expectedResult, BigEndianBitConverter.ToShort(value, startIndex)); + } + + [Test] + public void ToShortExceptionTest() + { + // We use system BitConverter for systems that are already big-endian + if (!BitConverter.IsLittleEndian) + Assert.Inconclusive(); + + byte[] values = { 0x00, 0xFF, 0x0F, 0xF0, 0xFF, 0xAA, 0x55, 0xF1, 0x1F }; + + Assert.Throws(() => BigEndianBitConverter.ToShort(null, 0)); + Assert.Throws(() => BigEndianBitConverter.ToShort(values, -1)); + Assert.Throws(() => BigEndianBitConverter.ToShort(values, 9)); + Assert.Throws(() => BigEndianBitConverter.ToShort(values, 8)); + } + + [TestCase(uint.MaxValue, new byte[] {0xFF, 0xFF, 0xFF, 0xFF}, 0)] + [TestCase(uint.MinValue, new byte[] {0x00, 0x00, 0x00, 0x00}, 0)] + [TestCase((uint)255, new byte[]{ 0x00, 0x00, 0x00, 0xFF}, 0)] + [TestCase((uint)4278190080, new byte[]{0xFF, 0x00, 0x00, 0x00},0)] + [TestCase(uint.MaxValue, new byte[] {0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00}, 2)] + [TestCase(uint.MinValue, new byte[] { 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF}, 1)] + [TestCase((uint)255, new byte[]{0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00}, 3)] + [TestCase((uint)4278190080, new byte[]{0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF},4)] + [TestCase((uint)15728895, new byte[]{0x00, 0xFF,0x00, 0xF0, 0x00, 0xFF, 0xFF}, 2)] + [TestCase((uint)1044735, new byte[]{0x00, 0x0F, 0xF0, 0xFF},0)] + public void ToUintTest(uint expectedResult, byte[] value, int startIndex) + { + // We use system BitConverter for systems that are already big-endian + if (!BitConverter.IsLittleEndian) + Assert.Inconclusive(); + + + Assert.AreEqual(expectedResult, BigEndianBitConverter.ToUint(value, startIndex)); + } + + [Test] + public void ToUintExceptionTest() + { + // We use system BitConverter for systems that are already big-endian + if (!BitConverter.IsLittleEndian) + Assert.Inconclusive(); + + byte[] values = { 0x00, 0xFF, 0x0F, 0xF0, 0xFF, 0xAA, 0x55, 0xF1, 0x1F }; + + Assert.Throws(() => BigEndianBitConverter.ToUint(null, 0)); + Assert.Throws(() => BigEndianBitConverter.ToUint(values, -1)); + Assert.Throws(() => BigEndianBitConverter.ToUint(values, 9)); + Assert.Throws(() => BigEndianBitConverter.ToUint(values, 6)); + } + + [TestCase(int.MaxValue, new byte[] {0x7F, 0xFF, 0xFF, 0xFF}, 0)] + [TestCase(int.MinValue, new byte[] {0x80, 0x00, 0x00, 0x00}, 0)] + [TestCase(0, new byte[] {0x00, 0x00, 0x00, 0x00}, 0)] + [TestCase(255, new byte[]{ 0x00, 0x00, 0x00, 0xFF}, 0)] + [TestCase(-1, new byte[]{0xFF, 0xFF, 0xFF, 0xFF},0)] + [TestCase(-16777216, new byte[]{0xFF, 0x00, 0x00, 0x00},0)] + [TestCase(int.MaxValue, new byte[] {0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0x00, 0x00}, 2)] + [TestCase(int.MinValue, new byte[] { 0xFF, 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF}, 1)] + [TestCase(255, new byte[]{0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00}, 3)] + [TestCase(-16777216, new byte[]{0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF},4)] + [TestCase(15728895, new byte[]{0x00, 0xFF,0x00, 0xF0, 0x00, 0xFF, 0xFF}, 2)] + [TestCase(1044735, new byte[]{0x00, 0x0F, 0xF0, 0xFF},0)] + public void ToIntTest(int expectedResult, byte[] value, int startIndex) + { + // We use system BitConverter for systems that are already big-endian + if (!BitConverter.IsLittleEndian) + Assert.Inconclusive(); + + + Assert.AreEqual(expectedResult, BigEndianBitConverter.ToInt(value, startIndex)); + } + + [Test] + public void ToIntExceptionTest() + { + // We use system BitConverter for systems that are already big-endian + if (!BitConverter.IsLittleEndian) + Assert.Inconclusive(); + + byte[] values = { 0x00, 0xFF, 0x0F, 0xF0, 0xFF, 0xAA, 0x55, 0xF1, 0x1F }; + + Assert.Throws(() => BigEndianBitConverter.ToInt(null, 0)); + Assert.Throws(() => BigEndianBitConverter.ToInt(values, -1)); + Assert.Throws(() => BigEndianBitConverter.ToInt(values, 9)); + Assert.Throws(() => BigEndianBitConverter.ToInt(values, 6)); + } + } +} \ No newline at end of file diff --git a/ICD.Common.Utils/BigEndianBitConverter.cs b/ICD.Common.Utils/BigEndianBitConverter.cs new file mode 100644 index 0000000..f5a0e0c --- /dev/null +++ b/ICD.Common.Utils/BigEndianBitConverter.cs @@ -0,0 +1,183 @@ +using System; +using ICD.Common.Properties; + +namespace ICD.Common.Utils +{ + public static class BigEndianBitConverter + { + private const byte FULL_BYTE = 0xFF; + + public static ushort ToUshort([NotNull] byte[] value, int startIndex) + { + return unchecked((ushort)ToShort(value, startIndex)); + } + + public static short ToShort([NotNull] byte[] value, int startIndex) + { + if (!BitConverter.IsLittleEndian) + return BitConverter.ToInt16(value, startIndex); + + const int bytes = sizeof(short); + + if (value == null) + throw new ArgumentNullException("value"); + if (startIndex < 0 || startIndex >= value.Length) + throw new ArgumentOutOfRangeException("startIndex"); + if (startIndex > value.Length - bytes) + throw new ArgumentException("Array plus start index too small"); + + short result = 0; + for (int i = 0; i < bytes; i++) + result |= (short)(value[i + startIndex] << GetBitShift(i, bytes)); + + return result; + } + + public static uint ToUint([NotNull] byte[] value, int startIndex) + { + return unchecked((uint)ToInt(value, startIndex)); + } + + public static int ToInt([NotNull] byte[] value, int startIndex) + { + if (!BitConverter.IsLittleEndian) + return BitConverter.ToInt32(value, startIndex); + + const int bytes = sizeof(int); + + if (value == null) + throw new ArgumentNullException("value"); + if (startIndex < 0 || startIndex >= value.Length) + throw new ArgumentOutOfRangeException("startIndex"); + if (startIndex > value.Length - bytes) + throw new ArgumentException("Array plus start index too small"); + + int result = 0; + for (int i = 0; i < bytes; i++) + result |= value[i + startIndex] << GetBitShift(i, bytes); + + return result; + } + + public static ulong ToUlong([NotNull] byte[] value, int startIndex) + { + return unchecked((ulong)ToLong(value, startIndex)); + } + + public static long ToLong([NotNull] byte[] value, int startIndex) + { + if (!BitConverter.IsLittleEndian) + return BitConverter.ToInt64(value, startIndex); + + const int bytes = sizeof(long); + + if (value == null) + throw new ArgumentNullException("value"); + if (startIndex < 0 || startIndex >= value.Length) + throw new ArgumentOutOfRangeException("startIndex"); + if (startIndex > value.Length - bytes) + throw new ArgumentException("Array plus start index too small"); + + int result = 0; + for (int i = 0; i < bytes; i++) + result |= value[i + startIndex] << GetBitShift(i, bytes); + + return result; + } + + public static byte[] GetBytes(int value) + { + if (!BitConverter.IsLittleEndian) + return BitConverter.GetBytes(value); + + const int total_bytes = sizeof(int); + + byte[] response = new byte[total_bytes]; + + for (int i = 0; i < total_bytes; i++) + response[i] = (byte)(value >> GetBitShift(i,total_bytes) & FULL_BYTE); + + return response; + } + public static byte[] GetBytes(uint value) + { + if (!BitConverter.IsLittleEndian) + return BitConverter.GetBytes(value); + + const int total_bytes = sizeof(uint); + + byte[] response = new byte[total_bytes]; + + for (int i = 0; i < total_bytes; i++) + response[i] = (byte)(value >> GetBitShift(i,total_bytes) & FULL_BYTE); + + return response; + } + + public static byte[] GetBytes(short value) + { + if (!BitConverter.IsLittleEndian) + return BitConverter.GetBytes(value); + + const int total_bytes = sizeof(short); + + byte[] response = new byte[total_bytes]; + + for (int i = 0; i < total_bytes; i++) + response[i] = (byte)(value >> GetBitShift(i,total_bytes) & FULL_BYTE); + + return response; + } + + public static byte[] GetBytes(ushort value) + { + if (!BitConverter.IsLittleEndian) + return BitConverter.GetBytes(value); + + const int total_bytes = sizeof(short); + + byte[] response = new byte[total_bytes]; + + for (int i = 0; i < total_bytes; i++) + response[i] = (byte)(value >> GetBitShift(i,total_bytes) & FULL_BYTE); + + return response; + } + + public static byte[] GetBytes(long value) + { + if (!BitConverter.IsLittleEndian) + return BitConverter.GetBytes(value); + + const int total_bytes = sizeof(long); + + byte[] response = new byte[total_bytes]; + + for (int i = 0; i < total_bytes; i++) + response[i] = (byte)(value >> GetBitShift(i,total_bytes) & FULL_BYTE); + + return response; + } + + public static byte[] GetBytes(ulong value) + { + if (!BitConverter.IsLittleEndian) + return BitConverter.GetBytes(value); + + const int total_bytes = sizeof(ulong); + + byte[] response = new byte[total_bytes]; + + for (int i = 0; i < total_bytes; i++) + response[i] = (byte)(value >> GetBitShift(i,total_bytes) & FULL_BYTE); + + return response; + } + private static int GetBitShift(int byteNumber, int totalBytes) + { + return ((totalBytes - 1 - byteNumber) * 8); + } + + + } +} \ No newline at end of file diff --git a/ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj b/ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj index aeab5d9..33e38a3 100644 --- a/ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj +++ b/ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj @@ -79,6 +79,7 @@ +