Skip to content

Commit c0f7e53

Browse files
committed
Added BigEndianBitConverter and LittleEndianBitConverter.
1 parent 8f6bd41 commit c0f7e53

File tree

8 files changed

+420
-0
lines changed

8 files changed

+420
-0
lines changed

ReClass.NET/ReClass.NET.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,9 @@
394394
<Compile Include="Util\BitString.cs" />
395395
<Compile Include="Util\CircularBuffer.cs" />
396396
<Compile Include="Util\CommandLineArgs.cs" />
397+
<Compile Include="Util\Conversion\BigEndianBitConverter.cs" />
398+
<Compile Include="Util\Conversion\EndianBitConverter.cs" />
399+
<Compile Include="Util\Conversion\LittleEndianBitConverter.cs" />
397400
<Compile Include="Util\CustomDataMap.cs" />
398401
<Compile Include="Extensions\BinaryReaderWriterExtensions.cs" />
399402
<Compile Include="Extensions\ColorExtensions.cs" />
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System;
2+
3+
namespace ReClassNET.Util.Conversion
4+
{
5+
public sealed class BigEndianBitConverter : EndianBitConverter
6+
{
7+
protected override long FromBytes(byte[] buffer, int index, int bytesToConvert)
8+
{
9+
if (buffer == null)
10+
{
11+
throw new ArgumentNullException(nameof(buffer));
12+
}
13+
if (index + bytesToConvert > buffer.Length)
14+
{
15+
throw new ArgumentOutOfRangeException(nameof(index));
16+
}
17+
18+
long ret = 0;
19+
for (var i = 0; i < bytesToConvert; i++)
20+
{
21+
ret = unchecked((ret << 8) | buffer[index + i]);
22+
}
23+
return ret;
24+
}
25+
26+
protected override byte[] ToBytes(long value, int bytes)
27+
{
28+
var endOffset = bytes - 1;
29+
30+
var buffer = new byte[bytes];
31+
for (var i = 0; i < bytes; i++)
32+
{
33+
buffer[endOffset - i] = unchecked((byte)(value & 0xFF));
34+
value >>= 8;
35+
}
36+
return buffer;
37+
}
38+
}
39+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
4+
namespace ReClassNET.Util.Conversion
5+
{
6+
public abstract class EndianBitConverter
7+
{
8+
public static LittleEndianBitConverter Little { get; } = new LittleEndianBitConverter();
9+
10+
public static BigEndianBitConverter Big { get; } = new BigEndianBitConverter();
11+
12+
public static EndianBitConverter System { get; } = BitConverter.IsLittleEndian ? (EndianBitConverter)Little : Big;
13+
14+
15+
public bool ToBoolean(byte[] value, int startIndex) => BitConverter.ToBoolean(value, startIndex);
16+
17+
public char ToChar(byte[] value, int startIndex) => unchecked((char)FromBytes(value, startIndex, 2));
18+
19+
public double ToDouble(byte[] value, int startIndex) => BitConverter.Int64BitsToDouble(ToInt64(value, startIndex));
20+
21+
public float ToSingle(byte[] value, int startIndex) => new Int32FloatUnion(ToInt32(value, startIndex)).FloatValue;
22+
23+
public short ToInt16(byte[] value, int startIndex) => unchecked((short)FromBytes(value, startIndex, 2));
24+
25+
public int ToInt32(byte[] value, int startIndex) => unchecked((int)FromBytes(value, startIndex, 4));
26+
27+
public long ToInt64(byte[] value, int startIndex) => FromBytes(value, startIndex, 8);
28+
29+
public ushort ToUInt16(byte[] value, int startIndex) => unchecked((ushort)FromBytes(value, startIndex, 2));
30+
31+
public uint ToUInt32(byte[] value, int startIndex) => unchecked((uint)FromBytes(value, startIndex, 4));
32+
33+
public ulong ToUInt64(byte[] value, int startIndex) => unchecked((ulong)FromBytes(value, startIndex, 8));
34+
35+
protected abstract long FromBytes(byte[] value, int index, int bytesToConvert);
36+
37+
38+
public byte[] GetBytes(bool value) => BitConverter.GetBytes(value);
39+
40+
public byte[] GetBytes(char value) => ToBytes(value, 2);
41+
42+
public byte[] GetBytes(double value) => ToBytes(BitConverter.DoubleToInt64Bits(value), 8);
43+
44+
public byte[] GetBytes(short value) => ToBytes(value, 2);
45+
46+
public byte[] GetBytes(int value) => ToBytes(value, 4);
47+
48+
public byte[] GetBytes(long value) => ToBytes(value, 8);
49+
50+
public byte[] GetBytes(float value) => ToBytes(new Int32FloatUnion(value).IntValue, 4);
51+
52+
public byte[] GetBytes(ushort value) => ToBytes(value, 2);
53+
54+
public byte[] GetBytes(uint value) => ToBytes(value, 4);
55+
56+
public byte[] GetBytes(ulong value) => ToBytes(unchecked((long)value), 8);
57+
58+
protected abstract byte[] ToBytes(long value, int bytes);
59+
60+
61+
[StructLayout(LayoutKind.Explicit)]
62+
private readonly struct Int32FloatUnion
63+
{
64+
[FieldOffset(0)]
65+
public readonly int IntValue;
66+
67+
[FieldOffset(0)]
68+
public readonly float FloatValue;
69+
70+
internal Int32FloatUnion(int value)
71+
{
72+
FloatValue = 0.0f;
73+
IntValue = value;
74+
}
75+
76+
internal Int32FloatUnion(float value)
77+
{
78+
IntValue = 0;
79+
FloatValue = value;
80+
}
81+
}
82+
}
83+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System;
2+
3+
namespace ReClassNET.Util.Conversion
4+
{
5+
public sealed class LittleEndianBitConverter : EndianBitConverter
6+
{
7+
protected override long FromBytes(byte[] buffer, int index, int bytesToConvert)
8+
{
9+
if (buffer == null)
10+
{
11+
throw new ArgumentNullException(nameof(buffer));
12+
}
13+
if (index + bytesToConvert > buffer.Length)
14+
{
15+
throw new ArgumentOutOfRangeException(nameof(index));
16+
}
17+
18+
var ret = 0L;
19+
for (var i = 0; i < bytesToConvert; i++)
20+
{
21+
ret = unchecked((ret << 8) | buffer[index + bytesToConvert - 1 - i]);
22+
}
23+
return ret;
24+
}
25+
26+
protected override byte[] ToBytes(long value, int bytes)
27+
{
28+
var buffer = new byte[bytes];
29+
30+
for (var i = 0; i < bytes; i++)
31+
{
32+
buffer[i] = unchecked((byte)(value & 0xFF));
33+
value >>= 8;
34+
}
35+
36+
return buffer;
37+
}
38+
}
39+
}

ReClass.NET_Tests/ReClass.NET_Tests.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@
9191
<Compile Include="Util\BitStringTest.cs" />
9292
<Compile Include="Util\CircularBufferTest.cs" />
9393
<Compile Include="Util\CommandLineArgsTest.cs" />
94+
<Compile Include="Util\Conversion\BigEndianBitConverterTest.cs" />
95+
<Compile Include="Util\Conversion\EndianBitConverterTest.cs" />
96+
<Compile Include="Util\Conversion\LittleEndianBitConverterTest.cs" />
9497
<Compile Include="Util\CustomDataMapTest.cs" />
9598
<Compile Include="Util\DirectedGraphTest.cs" />
9699
<Compile Include="Util\GrowingListTest.cs" />
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
using System;
2+
using NFluent;
3+
using ReClassNET.Util.Conversion;
4+
using Xunit;
5+
6+
namespace ReClass.NET_Tests.Util.Conversion
7+
{
8+
public class BigEndianBitConverterTest
9+
{
10+
[Fact]
11+
public void ToXXX_ThrowsOnNull()
12+
{
13+
var sut = new BigEndianBitConverter();
14+
15+
Check.ThatCode(() => sut.ToInt32(null, 0)).Throws<ArgumentNullException>();
16+
}
17+
18+
[Fact]
19+
public void ToXXX_ThrowsOnInvalidIndexOrSize()
20+
{
21+
var sut = new BigEndianBitConverter();
22+
23+
var data = new byte[3];
24+
Check.ThatCode(() => sut.ToInt32(data, 0)).Throws<ArgumentOutOfRangeException>();
25+
26+
data = new byte[4];
27+
Check.ThatCode(() => sut.ToInt32(data, 1)).Throws<ArgumentOutOfRangeException>();
28+
}
29+
30+
[Fact]
31+
public void GetBytes()
32+
{
33+
var sut = new BigEndianBitConverter();
34+
35+
Check.That(new byte[] { 0 }).ContainsExactly(sut.GetBytes(false));
36+
Check.That(new byte[] { 1 }).ContainsExactly(sut.GetBytes(true));
37+
38+
Check.That(new byte[] { 0, 0 }).ContainsExactly(sut.GetBytes((short)0));
39+
Check.That(new byte[] { 0, 1 }).ContainsExactly(sut.GetBytes((short)1));
40+
Check.That(new byte[] { 1, 0 }).ContainsExactly(sut.GetBytes((short)256));
41+
Check.That(new byte[] { 255, 255 }).ContainsExactly(sut.GetBytes((short)-1));
42+
43+
Check.That(new byte[] { 0, 0 }).ContainsExactly(sut.GetBytes((ushort)0));
44+
Check.That(new byte[] { 0, 1 }).ContainsExactly(sut.GetBytes((ushort)1));
45+
Check.That(new byte[] { 1, 0 }).ContainsExactly(sut.GetBytes((ushort)256));
46+
Check.That(new byte[] { 255, 255 }).ContainsExactly(sut.GetBytes(ushort.MaxValue));
47+
48+
Check.That(new byte[] { 0, 0, 0, 0 }).ContainsExactly(sut.GetBytes(0));
49+
Check.That(new byte[] { 0, 0, 0, 1 }).ContainsExactly(sut.GetBytes(1));
50+
Check.That(new byte[] { 0, 0, 1, 0 }).ContainsExactly(sut.GetBytes(256));
51+
Check.That(new byte[] { 0, 1, 0, 0 }).ContainsExactly(sut.GetBytes(65536));
52+
Check.That(new byte[] { 1, 0, 0, 0 }).ContainsExactly(sut.GetBytes(16777216));
53+
Check.That(new byte[] { 255, 255, 255, 255 }).ContainsExactly(sut.GetBytes(-1));
54+
55+
Check.That(new byte[] { 0, 0, 0, 0 }).ContainsExactly(sut.GetBytes(0u));
56+
Check.That(new byte[] { 0, 0, 0, 1 }).ContainsExactly(sut.GetBytes(1u));
57+
Check.That(new byte[] { 0, 0, 1, 0 }).ContainsExactly(sut.GetBytes(256u));
58+
Check.That(new byte[] { 0, 1, 0, 0 }).ContainsExactly(sut.GetBytes(65536u));
59+
Check.That(new byte[] { 1, 0, 0, 0 }).ContainsExactly(sut.GetBytes(16777216u));
60+
Check.That(new byte[] { 255, 255, 255, 255 }).ContainsExactly(sut.GetBytes(uint.MaxValue));
61+
62+
Check.That(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }).ContainsExactly(sut.GetBytes(0L));
63+
Check.That(new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 }).ContainsExactly(sut.GetBytes(1L));
64+
Check.That(new byte[] { 0, 0, 0, 0, 0, 0, 1, 0 }).ContainsExactly(sut.GetBytes(256L));
65+
Check.That(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }).ContainsExactly(sut.GetBytes(65536L));
66+
Check.That(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }).ContainsExactly(sut.GetBytes(16777216L));
67+
Check.That(new byte[] { 0, 0, 0, 1, 0, 0, 0, 0 }).ContainsExactly(sut.GetBytes(4294967296L));
68+
Check.That(new byte[] { 0, 0, 1, 0, 0, 0, 0, 0 }).ContainsExactly(sut.GetBytes(1099511627776L));
69+
Check.That(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0 }).ContainsExactly(sut.GetBytes(281474976710656L));
70+
Check.That(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0 }).ContainsExactly(sut.GetBytes(72057594037927936L));
71+
Check.That(new byte[] { 255, 255, 255, 255, 255, 255, 255, 255 }).ContainsExactly(sut.GetBytes(-1L));
72+
73+
Check.That(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }).ContainsExactly(sut.GetBytes(0UL));
74+
Check.That(new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 }).ContainsExactly(sut.GetBytes(1UL));
75+
Check.That(new byte[] { 0, 0, 0, 0, 0, 0, 1, 0 }).ContainsExactly(sut.GetBytes(256UL));
76+
Check.That(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }).ContainsExactly(sut.GetBytes(65536UL));
77+
Check.That(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }).ContainsExactly(sut.GetBytes(16777216UL));
78+
Check.That(new byte[] { 0, 0, 0, 1, 0, 0, 0, 0 }).ContainsExactly(sut.GetBytes(4294967296UL));
79+
Check.That(new byte[] { 0, 0, 1, 0, 0, 0, 0, 0 }).ContainsExactly(sut.GetBytes(1099511627776UL));
80+
Check.That(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0 }).ContainsExactly(sut.GetBytes(281474976710656UL));
81+
Check.That(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0 }).ContainsExactly(sut.GetBytes(72057594037927936UL));
82+
Check.That(new byte[] { 255, 255, 255, 255, 255, 255, 255, 255 }).ContainsExactly(sut.GetBytes(ulong.MaxValue));
83+
}
84+
85+
[Fact]
86+
public void ToXXX()
87+
{
88+
var sut = new BigEndianBitConverter();
89+
90+
var data = new byte[] { 0, 0, 0, 0, 0, 0, 0, 3 };
91+
Check.That(sut.ToBoolean(data, 0)).IsFalse();
92+
Check.That(sut.ToBoolean(data, 7)).IsTrue();
93+
Check.That(sut.ToChar(data, 0)).IsEqualTo('\0');
94+
Check.That(sut.ToChar(data, 6)).IsEqualTo('\u0003');
95+
Check.That(sut.ToInt16(data, 0)).IsEqualTo(0);
96+
Check.That(sut.ToInt16(data, 6)).IsEqualTo(3);
97+
Check.That(sut.ToUInt16(data, 0)).IsEqualTo(0u);
98+
Check.That(sut.ToUInt16(data, 6)).IsEqualTo(3u);
99+
Check.That(sut.ToInt32(data, 0)).IsEqualTo(0);
100+
Check.That(sut.ToInt32(data, 4)).IsEqualTo(3);
101+
Check.That(sut.ToUInt32(data, 0)).IsEqualTo(0u);
102+
Check.That(sut.ToUInt32(data, 4)).IsEqualTo(3u);
103+
Check.That(sut.ToInt64(data, 0)).IsEqualTo(3L);
104+
Check.That(sut.ToUInt64(data, 0)).IsEqualTo(3UL);
105+
106+
data = new byte[] { 0x41, 0x20, 0, 0, 0, 0, 0, 0 };
107+
Check.That(sut.ToSingle(data, 0)).IsEqualTo(10.0f);
108+
Check.That(sut.ToSingle(data, 4)).IsEqualTo(0.0f);
109+
110+
data = new byte[] { 0x40, 0x24, 0, 0, 0, 0, 0, 0 };
111+
Check.That(sut.ToDouble(data, 0)).IsEqualTo(10.0);
112+
}
113+
}
114+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System;
2+
using NFluent;
3+
using ReClassNET.Util.Conversion;
4+
using Xunit;
5+
6+
namespace ReClass.NET_Tests.Util.Conversion
7+
{
8+
public class EndianBitConverterTest
9+
{
10+
[Fact]
11+
public void Properties_AreNotNull()
12+
{
13+
Check.That(EndianBitConverter.System).IsNotNull();
14+
Check.That(EndianBitConverter.Big).IsNotNull();
15+
Check.That(EndianBitConverter.Little).IsNotNull();
16+
}
17+
18+
[Fact]
19+
public void Types()
20+
{
21+
Check.That(EndianBitConverter.Big.GetType()).IsNotEqualTo(EndianBitConverter.Little.GetType());
22+
Check.That(EndianBitConverter.System.GetType()).IsEqualTo(BitConverter.IsLittleEndian ? EndianBitConverter.Little.GetType() : EndianBitConverter.Big.GetType());
23+
}
24+
}
25+
}

0 commit comments

Comments
 (0)