Add proper U/Int128 support

This commit is contained in:
Matt Nadareski
2026-03-14 23:40:34 -04:00
parent 0c7a2dd0dd
commit 96f9698aa4
10 changed files with 715 additions and 165 deletions

View File

@@ -684,6 +684,16 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(expected, read);
}
[Fact]
public void ReadInt128LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
var expected = (Int128)new BigInteger(_bytes);
Int128 read = br.ReadInt128LittleEndian();
Assert.Equal(expected, read);
}
[Fact]
public void ReadUInt128Test()
{
@@ -705,6 +715,16 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(expected, read);
}
[Fact]
public void ReadUInt128LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
var expected = (UInt128)new BigInteger(_bytes);
UInt128 read = br.ReadUInt128LittleEndian();
Assert.Equal(expected, read);
}
[Fact]
public void ReadNullTerminatedStringTest()
{
@@ -1680,6 +1700,17 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0, br.BaseStream.Position);
}
[Fact]
public void PeekInt128LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
var expected = (Int128)new BigInteger(_bytes);
Int128 read = br.PeekInt128LittleEndian();
Assert.Equal(expected, read);
Assert.Equal(0, br.BaseStream.Position);
}
[Fact]
public void PeekUInt128Test()
{
@@ -1703,6 +1734,17 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0, br.BaseStream.Position);
}
[Fact]
public void PeekUInt128LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
var expected = (UInt128)new BigInteger(_bytes);
UInt128 read = br.PeekUInt128LittleEndian();
Assert.Equal(expected, read);
Assert.Equal(0, br.BaseStream.Position);
}
#endregion
#region Try Read
@@ -2389,6 +2431,16 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(default, read);
}
[Fact]
public void TryReadInt128LittleEndianTest()
{
var stream = new MemoryStream([]);
var br = new BinaryReader(stream);
bool actual = br.TryReadInt128LittleEndian(out Int128 read);
Assert.False(actual);
Assert.Equal(default, read);
}
[Fact]
public void TryReadUInt128Test()
{
@@ -2409,6 +2461,16 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(default, read);
}
[Fact]
public void TryReadUInt128LittleEndianTest()
{
var stream = new MemoryStream([]);
var br = new BinaryReader(stream);
bool actual = br.TryReadUInt128LittleEndian(out UInt128 read);
Assert.False(actual);
Assert.Equal(default, read);
}
#endregion
}
}

View File

@@ -591,6 +591,15 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(expected, read);
}
[Fact]
public void ReadInt128LittleEndianTest()
{
int offset = 0;
var expected = (Int128)new BigInteger(_bytes);
Int128 read = _bytes.ReadInt128LittleEndian(ref offset);
Assert.Equal(expected, read);
}
[Fact]
public void ReadUInt128Test()
{
@@ -610,6 +619,15 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(expected, read);
}
[Fact]
public void ReadUInt128LittleEndianTest()
{
int offset = 0;
var expected = (UInt128)new BigInteger(_bytes);
UInt128 read = _bytes.ReadUInt128LittleEndian(ref offset);
Assert.Equal(expected, read);
}
[Fact]
public void ReadNullTerminatedStringTest()
{
@@ -1519,6 +1537,16 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0, offset);
}
[Fact]
public void PeekInt128LittleEndianTest()
{
int offset = 0;
var expected = (Int128)new BigInteger(_bytes);
Int128 read = _bytes.PeekInt128LittleEndian(ref offset);
Assert.Equal(expected, read);
Assert.Equal(0, offset);
}
[Fact]
public void PeekUInt128Test()
{
@@ -1540,6 +1568,16 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0, offset);
}
[Fact]
public void PeekUInt128LittleEndianTest()
{
int offset = 0;
var expected = (UInt128)new BigInteger(_bytes);
UInt128 read = _bytes.PeekUInt128LittleEndian(ref offset);
Assert.Equal(expected, read);
Assert.Equal(0, offset);
}
#endregion
#region Try Read
@@ -2158,6 +2196,15 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(default, read);
}
[Fact]
public void TryReadInt128LittleEndianTest()
{
int offset = 0;
bool actual = Array.Empty<byte>().TryReadInt128LittleEndian(ref offset, out Int128 read);
Assert.False(actual);
Assert.Equal(default, read);
}
[Fact]
public void TryReadUInt128Test()
{
@@ -2176,6 +2223,15 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(default, read);
}
[Fact]
public void TryReadUInt128LittleEndianTest()
{
int offset = 0;
bool actual = Array.Empty<byte>().TryReadUInt128LittleEndian(ref offset, out UInt128 read);
Assert.False(actual);
Assert.Equal(default, read);
}
#endregion
}
}

View File

@@ -595,6 +595,15 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(expected, read);
}
[Fact]
public void ReadInt128LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
var expected = (Int128)new BigInteger(_bytes);
Int128 read = stream.ReadInt128LittleEndian();
Assert.Equal(expected, read);
}
[Fact]
public void ReadUInt128Test()
{
@@ -614,6 +623,15 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(expected, read);
}
[Fact]
public void ReadUInt128LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
var expected = (UInt128)new BigInteger(_bytes);
UInt128 read = stream.ReadUInt128LittleEndian();
Assert.Equal(expected, read);
}
[Fact]
public void ReadNullTerminatedStringTest()
{
@@ -1515,6 +1533,16 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0, stream.Position);
}
[Fact]
public void PeekInt128LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
var expected = (Int128)new BigInteger(_bytes);
Int128 read = stream.PeekInt128LittleEndian();
Assert.Equal(expected, read);
Assert.Equal(0, stream.Position);
}
[Fact]
public void PeekUInt128Test()
{
@@ -1536,6 +1564,16 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0, stream.Position);
}
[Fact]
public void PeekUInt128LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
var expected = (UInt128)new BigInteger(_bytes);
UInt128 read = stream.PeekUInt128LittleEndian();
Assert.Equal(expected, read);
Assert.Equal(0, stream.Position);
}
#endregion
#region Try Read
@@ -2146,6 +2184,15 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(default, read);
}
[Fact]
public void TryReadInt128LittleEndianTest()
{
var stream = new MemoryStream([]);
bool actual = stream.TryReadInt128LittleEndian(out Int128 read);
Assert.False(actual);
Assert.Equal(default, read);
}
[Fact]
public void TryReadUInt128Test()
{
@@ -2164,6 +2211,15 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(default, read);
}
[Fact]
public void TryReadUInt128LittleEndianTest()
{
var stream = new MemoryStream([]);
bool actual = stream.TryReadUInt128LittleEndian(out UInt128 read);
Assert.False(actual);
Assert.Equal(default, read);
}
#endregion
}
}

View File

@@ -1,9 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
#if NET7_0_OR_GREATER
using System.Numerics;
#endif
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
@@ -461,15 +458,17 @@ namespace SabreTools.IO.Extensions
return new Guid(buffer);
}
// TODO: Determine if the reverse reads are doing what are expected
#if NET7_0_OR_GREATER
/// <summary>
/// Read an Int128 from the underlying stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static Int128 ReadInt128(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(16);
return (Int128)new BigInteger(buffer);
if (BitConverter.IsLittleEndian)
return reader.ReadInt128LittleEndian();
else
return reader.ReadInt128BigEndian();
}
/// <summary>
@@ -479,17 +478,29 @@ namespace SabreTools.IO.Extensions
public static Int128 ReadInt128BigEndian(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(16);
Array.Reverse(buffer);
return (Int128)new BigInteger(buffer);
return buffer.ToInt128BigEndian(0);
}
/// <summary>
/// Read an Int128 from the underlying stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static Int128 ReadInt128LittleEndian(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(16);
return buffer.ToInt128LittleEndian(0);
}
/// <summary>
/// Read a UInt128 from the underlying stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static UInt128 ReadUInt128(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(16);
return (UInt128)new BigInteger(buffer);
if (BitConverter.IsLittleEndian)
return reader.ReadUInt128LittleEndian();
else
return reader.ReadUInt128BigEndian();
}
/// <summary>
@@ -499,8 +510,17 @@ namespace SabreTools.IO.Extensions
public static UInt128 ReadUInt128BigEndian(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(16);
Array.Reverse(buffer);
return (UInt128)new BigInteger(buffer);
return buffer.ToUInt128BigEndian(0);
}
/// <summary>
/// Read a UInt128 from the underlying stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static UInt128 ReadUInt128LittleEndian(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(16);
return buffer.ToUInt128LittleEndian(0);
}
#endif
@@ -1677,9 +1697,10 @@ namespace SabreTools.IO.Extensions
/// <remarks>Only works properly on seekable streams</remarks>
public static Int128 PeekInt128(this BinaryReader reader)
{
Int128 value = reader.ReadInt128();
reader.BaseStream.SeekIfPossible(-16, SeekOrigin.Current);
return value;
if (BitConverter.IsLittleEndian)
return reader.PeekInt128LittleEndian();
else
return reader.PeekInt128BigEndian();
}
/// <summary>
@@ -1694,6 +1715,18 @@ namespace SabreTools.IO.Extensions
return value;
}
/// <summary>
/// Peek an Int128 from the base stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
/// <remarks>Only works properly on seekable streams</remarks>
public static Int128 PeekInt128LittleEndian(this BinaryReader reader)
{
Int128 value = reader.ReadInt128LittleEndian();
reader.BaseStream.SeekIfPossible(-16, SeekOrigin.Current);
return value;
}
/// <summary>
/// Peek a UInt128 from the base stream
/// </summary>
@@ -1701,9 +1734,10 @@ namespace SabreTools.IO.Extensions
/// <remarks>Only works properly on seekable streams</remarks>
public static UInt128 PeekUInt128(this BinaryReader reader)
{
UInt128 value = reader.ReadUInt128();
reader.BaseStream.SeekIfPossible(-16, SeekOrigin.Current);
return value;
if (BitConverter.IsLittleEndian)
return reader.PeekUInt128LittleEndian();
else
return reader.PeekUInt128BigEndian();
}
/// <summary>
@@ -1717,6 +1751,18 @@ namespace SabreTools.IO.Extensions
reader.BaseStream.SeekIfPossible(-16, SeekOrigin.Current);
return value;
}
/// <summary>
/// Peek a UInt128 from the base stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
/// <remarks>Only works properly on seekable streams</remarks>
public static UInt128 PeekUInt128LittleEndian(this BinaryReader reader)
{
UInt128 value = reader.ReadUInt128LittleEndian();
reader.BaseStream.SeekIfPossible(-16, SeekOrigin.Current);
return value;
}
#endif
#endregion
@@ -2605,14 +2651,10 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in machine native format</remarks>
public static bool TryReadInt128(this BinaryReader reader, out Int128 value)
{
if (reader.BaseStream.Position > reader.BaseStream.Length - 16)
{
value = default;
return false;
}
value = reader.ReadInt128();
return true;
if (BitConverter.IsLittleEndian)
return reader.TryReadInt128LittleEndian(out value);
else
return reader.TryReadInt128BigEndian(out value);
}
/// <summary>
@@ -2632,10 +2674,10 @@ namespace SabreTools.IO.Extensions
}
/// <summary>
/// Read a UInt128 from the base stream
/// Read an Int128 from the base stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static bool TryReadUInt128(this BinaryReader reader, out UInt128 value)
/// <remarks>Reads in little-endian format</remarks>
public static bool TryReadInt128LittleEndian(this BinaryReader reader, out Int128 value)
{
if (reader.BaseStream.Position > reader.BaseStream.Length - 16)
{
@@ -2643,10 +2685,22 @@ namespace SabreTools.IO.Extensions
return false;
}
value = reader.ReadUInt128();
value = reader.ReadInt128LittleEndian();
return true;
}
/// <summary>
/// Read a UInt128 from the base stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static bool TryReadUInt128(this BinaryReader reader, out UInt128 value)
{
if (BitConverter.IsLittleEndian)
return reader.TryReadUInt128LittleEndian(out value);
else
return reader.TryReadUInt128BigEndian(out value);
}
/// <summary>
/// Read a UInt128 from the base stream
/// </summary>
@@ -2662,6 +2716,22 @@ namespace SabreTools.IO.Extensions
value = reader.ReadUInt128BigEndian();
return true;
}
/// <summary>
/// Read a UInt128 from the base stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static bool TryReadUInt128LittleEndian(this BinaryReader reader, out UInt128 value)
{
if (reader.BaseStream.Position > reader.BaseStream.Length - 16)
{
value = default;
return false;
}
value = reader.ReadUInt128LittleEndian();
return true;
}
#endif
#endregion

View File

@@ -1,8 +1,5 @@
using System;
using System.IO;
#if NET7_0_OR_GREATER
using System.Numerics;
#endif
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
@@ -311,13 +308,11 @@ namespace SabreTools.IO.Extensions
/// <summary>
/// Write an Int128
/// </summary>
/// <remarks>Writes in little-endian format</remarks>
public static bool Write(this BinaryWriter writer, Int128 value)
{
byte[] buffer = ((BigInteger)value).ToByteArray();
byte[] padded = new byte[16];
Array.Copy(buffer, 0, padded, 16 - buffer.Length, buffer.Length);
return WriteFromBuffer(writer, padded);
byte[] buffer = value.ToByteArrayLittleEndian();
return WriteFromBuffer(writer, buffer);
}
/// <summary>
@@ -326,24 +321,18 @@ namespace SabreTools.IO.Extensions
/// <remarks>Writes in big-endian format</remarks>
public static bool WriteBigEndian(this BinaryWriter writer, Int128 value)
{
byte[] buffer = ((BigInteger)value).ToByteArray();
Array.Reverse(buffer);
byte[] padded = new byte[16];
Array.Copy(buffer, 0, padded, 16 - buffer.Length, buffer.Length);
return WriteFromBuffer(writer, padded);
byte[] buffer = value.ToByteArrayBigEndian();
return WriteFromBuffer(writer, buffer);
}
/// <summary>
/// Write a UInt128
/// </summary>
/// <remarks>Writes in little-endian format</remarks>
public static bool Write(this BinaryWriter writer, UInt128 value)
{
byte[] buffer = ((BigInteger)value).ToByteArray();
byte[] padded = new byte[16];
Array.Copy(buffer, 0, padded, 16 - buffer.Length, buffer.Length);
return WriteFromBuffer(writer, padded);
byte[] buffer = value.ToByteArrayLittleEndian();
return WriteFromBuffer(writer, buffer);
}
/// <summary>
@@ -352,12 +341,8 @@ namespace SabreTools.IO.Extensions
/// <remarks>Writes in big-endian format</remarks>
public static bool WriteBigEndian(this BinaryWriter writer, UInt128 value)
{
byte[] buffer = ((BigInteger)value).ToByteArray();
Array.Reverse(buffer);
byte[] padded = new byte[16];
Array.Copy(buffer, 0, padded, 16 - buffer.Length, buffer.Length);
return WriteFromBuffer(writer, padded);
byte[] buffer = value.ToByteArrayBigEndian();
return WriteFromBuffer(writer, buffer);
}
#endif

View File

@@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
#if NET7_0_OR_GREATER
using System.Numerics;
#endif
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
@@ -675,8 +672,10 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in machine native format</remarks>
public static Int128 ReadInt128(this byte[] content, ref int offset)
{
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 16);
return (Int128)new BigInteger(buffer);
if (BitConverter.IsLittleEndian)
return content.ReadInt128LittleEndian(ref offset);
else
return content.ReadInt128BigEndian(ref offset);
}
/// <summary>
@@ -686,8 +685,17 @@ namespace SabreTools.IO.Extensions
public static Int128 ReadInt128BigEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 16);
Array.Reverse(buffer);
return (Int128)new BigInteger(buffer);
return buffer.ToInt128BigEndian(0);
}
/// <summary>
/// Read an Int128 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static Int128 ReadInt128LittleEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 16);
return buffer.ToInt128LittleEndian(0);
}
/// <summary>
@@ -696,8 +704,10 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in machine native format</remarks>
public static UInt128 ReadUInt128(this byte[] content, ref int offset)
{
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 16);
return (UInt128)new BigInteger(buffer);
if (BitConverter.IsLittleEndian)
return content.ReadUInt128LittleEndian(ref offset);
else
return content.ReadUInt128BigEndian(ref offset);
}
/// <summary>
@@ -707,8 +717,17 @@ namespace SabreTools.IO.Extensions
public static UInt128 ReadUInt128BigEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 16);
Array.Reverse(buffer);
return (UInt128)new BigInteger(buffer);
return buffer.ToUInt128BigEndian(0);
}
/// <summary>
/// Read a UInt128 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static UInt128 ReadUInt128LittleEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 16);
return buffer.ToUInt128LittleEndian(0);
}
#endif
@@ -1877,9 +1896,10 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in machine native format</remarks>
public static Int128 PeekInt128(this byte[] content, ref int offset)
{
Int128 value = content.ReadInt128(ref offset);
offset -= 16;
return value;
if (BitConverter.IsLittleEndian)
return content.PeekInt128LittleEndian(ref offset);
else
return content.PeekInt128BigEndian(ref offset);
}
/// <summary>
@@ -1893,15 +1913,27 @@ namespace SabreTools.IO.Extensions
return value;
}
/// <summary>
/// Peek an Int128 without incrementing the pointer to an array
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static Int128 PeekInt128LittleEndian(this byte[] content, ref int offset)
{
Int128 value = content.ReadInt128LittleEndian(ref offset);
offset -= 16;
return value;
}
/// <summary>
/// Peek a UInt128 without incrementing the pointer to an array
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static UInt128 PeekUInt128(this byte[] content, ref int offset)
{
UInt128 value = content.ReadUInt128(ref offset);
offset -= 16;
return value;
if (BitConverter.IsLittleEndian)
return content.PeekUInt128LittleEndian(ref offset);
else
return content.PeekUInt128BigEndian(ref offset);
}
/// <summary>
@@ -1914,6 +1946,17 @@ namespace SabreTools.IO.Extensions
offset -= 16;
return value;
}
/// <summary>
/// Peek a UInt128 without incrementing the pointer to an array
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static UInt128 PeekUInt128LittleEndian(this byte[] content, ref int offset)
{
UInt128 value = content.ReadUInt128LittleEndian(ref offset);
offset -= 16;
return value;
}
#endif
#endregion
@@ -2817,14 +2860,10 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in machine native format</remarks>
public static bool TryReadInt128(this byte[] content, ref int offset, out Int128 value)
{
if (offset > content.Length - 16)
{
value = default;
return false;
}
value = content.ReadInt128(ref offset);
return true;
if (BitConverter.IsLittleEndian)
return content.TryReadInt128LittleEndian(ref offset, out value);
else
return content.TryReadInt128BigEndian(ref offset, out value);
}
/// <summary>
@@ -2844,10 +2883,10 @@ namespace SabreTools.IO.Extensions
}
/// <summary>
/// Read a UInt128 and increment the pointer to an array
/// Read an Int128 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static bool TryReadUInt128(this byte[] content, ref int offset, out UInt128 value)
/// <remarks>Reads in little-endian format</remarks>
public static bool TryReadInt128LittleEndian(this byte[] content, ref int offset, out Int128 value)
{
if (offset > content.Length - 16)
{
@@ -2855,10 +2894,22 @@ namespace SabreTools.IO.Extensions
return false;
}
value = content.ReadUInt128(ref offset);
value = content.ReadInt128LittleEndian(ref offset);
return true;
}
/// <summary>
/// Read a UInt128 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static bool TryReadUInt128(this byte[] content, ref int offset, out UInt128 value)
{
if (BitConverter.IsLittleEndian)
return content.TryReadUInt128LittleEndian(ref offset, out value);
else
return content.TryReadUInt128BigEndian(ref offset, out value);
}
/// <summary>
/// Read a UInt128 and increment the pointer to an array
/// </summary>
@@ -2874,6 +2925,22 @@ namespace SabreTools.IO.Extensions
value = content.ReadUInt128BigEndian(ref offset);
return true;
}
/// <summary>
/// Read a UInt128 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static bool TryReadUInt128LittleEndian(this byte[] content, ref int offset, out UInt128 value)
{
if (offset > content.Length - 16)
{
value = default;
return false;
}
value = content.ReadUInt128LittleEndian(ref offset);
return true;
}
#endif
#endregion

View File

@@ -1,7 +1,4 @@
using System;
#if NET7_0_OR_GREATER
using System.Numerics;
#endif
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
@@ -490,13 +487,11 @@ namespace SabreTools.IO.Extensions
/// <summary>
/// Write an Int128 and increment the pointer to an array
/// </summary>
/// <remarks>Writes in little-endian format</remarks>
public static bool Write(this byte[] content, ref int offset, Int128 value)
{
byte[] buffer = ((BigInteger)value).ToByteArray();
byte[] padded = new byte[16];
Array.Copy(buffer, 0, padded, 16 - buffer.Length, buffer.Length);
return WriteFromBuffer(content, ref offset, padded);
byte[] buffer = value.ToByteArrayLittleEndian();
return WriteFromBuffer(content, ref offset, buffer);
}
/// <summary>
@@ -505,24 +500,18 @@ namespace SabreTools.IO.Extensions
/// <remarks>Writes in big-endian format</remarks>
public static bool WriteBigEndian(this byte[] content, ref int offset, Int128 value)
{
byte[] buffer = ((BigInteger)value).ToByteArray();
Array.Reverse(buffer);
byte[] padded = new byte[16];
Array.Copy(buffer, 0, padded, 16 - buffer.Length, buffer.Length);
return WriteFromBuffer(content, ref offset, padded);
byte[] buffer = value.ToByteArrayBigEndian();
return WriteFromBuffer(content, ref offset, buffer);
}
/// <summary>
/// Write a UInt128 and increment the pointer to an array
/// </summary>
/// <remarks>Writes in little-endian format</remarks>
public static bool Write(this byte[] content, ref int offset, UInt128 value)
{
byte[] buffer = ((BigInteger)value).ToByteArray();
byte[] padded = new byte[16];
Array.Copy(buffer, 0, padded, 16 - buffer.Length, buffer.Length);
return WriteFromBuffer(content, ref offset, padded);
byte[] buffer = value.ToByteArrayLittleEndian();
return WriteFromBuffer(content, ref offset, buffer);
}
/// <summary>
@@ -531,12 +520,8 @@ namespace SabreTools.IO.Extensions
/// <remarks>Writes in big-endian format</remarks>
public static bool WriteBigEndian(this byte[] content, ref int offset, UInt128 value)
{
byte[] buffer = ((BigInteger)value).ToByteArray();
Array.Reverse(buffer);
byte[] padded = new byte[16];
Array.Copy(buffer, 0, padded, 16 - buffer.Length, buffer.Length);
return WriteFromBuffer(content, ref offset, padded);
byte[] buffer = value.ToByteArrayBigEndian();
return WriteFromBuffer(content, ref offset, buffer);
}
#endif

View File

@@ -4,7 +4,6 @@ namespace SabreTools.IO.Extensions
/// Extensions for numeric conversion
/// </summary>
/// TODO: Add fractional types (Half, Single, Double, Decimal)
/// TODO: Add U/Int128
/// TODO: Add GUID
public static class NumericExtensions
{
@@ -262,6 +261,104 @@ namespace SabreTools.IO.Extensions
| ((ulong)value[offset + 7] << 56);
}
#if NET7_0_OR_GREATER
/// <summary>
/// Convert a byte array at an offset to an Int128
/// </summary>
/// <remarks>Reads in big-endian format</remarks>
public static System.Int128 ToInt128BigEndian(this byte[] value, int offset)
{
return value[offset + 15]
| ((System.Int128)value[offset + 14] << 8)
| ((System.Int128)value[offset + 13] << 16)
| ((System.Int128)value[offset + 12] << 24)
| ((System.Int128)value[offset + 11] << 32)
| ((System.Int128)value[offset + 10] << 40)
| ((System.Int128)value[offset + 9] << 48)
| ((System.Int128)value[offset + 8] << 56)
| ((System.Int128)value[offset + 7] << 64)
| ((System.Int128)value[offset + 6] << 72)
| ((System.Int128)value[offset + 5] << 80)
| ((System.Int128)value[offset + 4] << 88)
| ((System.Int128)value[offset + 3] << 96)
| ((System.Int128)value[offset + 2] << 104)
| ((System.Int128)value[offset + 1] << 112)
| ((System.Int128)value[offset + 0] << 120);
}
/// <summary>
/// Convert a byte array at an offset to an Int128
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static System.Int128 ToInt128LittleEndian(this byte[] value, int offset)
{
return value[offset + 0]
| ((System.Int128)value[offset + 1] << 8)
| ((System.Int128)value[offset + 2] << 16)
| ((System.Int128)value[offset + 3] << 24)
| ((System.Int128)value[offset + 4] << 32)
| ((System.Int128)value[offset + 5] << 40)
| ((System.Int128)value[offset + 6] << 48)
| ((System.Int128)value[offset + 7] << 56)
| ((System.Int128)value[offset + 8] << 64)
| ((System.Int128)value[offset + 9] << 72)
| ((System.Int128)value[offset + 10] << 80)
| ((System.Int128)value[offset + 11] << 88)
| ((System.Int128)value[offset + 12] << 96)
| ((System.Int128)value[offset + 13] << 104)
| ((System.Int128)value[offset + 14] << 112)
| ((System.Int128)value[offset + 15] << 120);
}
/// <summary>
/// Convert a byte array at an offset to a UInt128
/// </summary>
/// <remarks>Reads in big-endian format</remarks>
public static System.UInt128 ToUInt128BigEndian(this byte[] value, int offset)
{
return value[offset + 15]
| ((System.UInt128)value[offset + 14] << 8)
| ((System.UInt128)value[offset + 13] << 16)
| ((System.UInt128)value[offset + 12] << 24)
| ((System.UInt128)value[offset + 11] << 32)
| ((System.UInt128)value[offset + 10] << 40)
| ((System.UInt128)value[offset + 9] << 48)
| ((System.UInt128)value[offset + 8] << 56)
| ((System.UInt128)value[offset + 7] << 64)
| ((System.UInt128)value[offset + 6] << 72)
| ((System.UInt128)value[offset + 5] << 80)
| ((System.UInt128)value[offset + 4] << 88)
| ((System.UInt128)value[offset + 3] << 96)
| ((System.UInt128)value[offset + 2] << 104)
| ((System.UInt128)value[offset + 1] << 112)
| ((System.UInt128)value[offset + 0] << 120);
}
/// <summary>
/// Convert a byte array at an offset to a UInt128
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static System.UInt128 ToUInt128LittleEndian(this byte[] value, int offset)
{
return value[offset + 0]
| ((System.UInt128)value[offset + 1] << 8)
| ((System.UInt128)value[offset + 2] << 16)
| ((System.UInt128)value[offset + 3] << 24)
| ((System.UInt128)value[offset + 4] << 32)
| ((System.UInt128)value[offset + 5] << 40)
| ((System.UInt128)value[offset + 6] << 48)
| ((System.UInt128)value[offset + 7] << 56)
| ((System.UInt128)value[offset + 8] << 64)
| ((System.UInt128)value[offset + 9] << 72)
| ((System.UInt128)value[offset + 10] << 80)
| ((System.UInt128)value[offset + 11] << 88)
| ((System.UInt128)value[offset + 12] << 96)
| ((System.UInt128)value[offset + 13] << 104)
| ((System.UInt128)value[offset + 14] << 112)
| ((System.UInt128)value[offset + 15] << 120);
}
#endif
#endregion
#region To Byte Array
@@ -618,6 +715,124 @@ namespace SabreTools.IO.Extensions
return output;
}
#endregion
#if NET7_0_OR_GREATER
/// <summary>
/// Convert an Int64 to a byte array
/// </summary>
/// <remarks>Reads in big-endian format</remarks>
public static byte[] ToByteArrayBigEndian(this System.Int128 value)
{
byte[] output =
[
(byte)((value >> 120) & 0xFF),
(byte)((value >> 112) & 0xFF),
(byte)((value >> 104) & 0xFF),
(byte)((value >> 96) & 0xFF),
(byte)((value >> 88) & 0xFF),
(byte)((value >> 80) & 0xFF),
(byte)((value >> 72) & 0xFF),
(byte)((value >> 64) & 0xFF),
(byte)((value >> 56) & 0xFF),
(byte)((value >> 48) & 0xFF),
(byte)((value >> 40) & 0xFF),
(byte)((value >> 32) & 0xFF),
(byte)((value >> 24) & 0xFF),
(byte)((value >> 16) & 0xFF),
(byte)((value >> 8) & 0xFF),
(byte)(value & 0xFF),
];
return output;
}
/// <summary>
/// Convert an Int64 to a byte array
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static byte[] ToByteArrayLittleEndian(this System.Int128 value)
{
byte[] output =
[
(byte)(value & 0xFF),
(byte)((value >> 8) & 0xFF),
(byte)((value >> 16) & 0xFF),
(byte)((value >> 24) & 0xFF),
(byte)((value >> 32) & 0xFF),
(byte)((value >> 40) & 0xFF),
(byte)((value >> 48) & 0xFF),
(byte)((value >> 56) & 0xFF),
(byte)((value >> 64) & 0xFF),
(byte)((value >> 72) & 0xFF),
(byte)((value >> 80) & 0xFF),
(byte)((value >> 88) & 0xFF),
(byte)((value >> 96) & 0xFF),
(byte)((value >> 104) & 0xFF),
(byte)((value >> 112) & 0xFF),
(byte)((value >> 120) & 0xFF),
];
return output;
}
/// <summary>
/// Convert a UInt64 to a byte array
/// </summary>
/// <remarks>Reads in big-endian format</remarks>
public static byte[] ToByteArrayBigEndian(this System.UInt128 value)
{
byte[] output =
[
(byte)((value >> 120) & 0xFF),
(byte)((value >> 112) & 0xFF),
(byte)((value >> 104) & 0xFF),
(byte)((value >> 96) & 0xFF),
(byte)((value >> 88) & 0xFF),
(byte)((value >> 80) & 0xFF),
(byte)((value >> 72) & 0xFF),
(byte)((value >> 64) & 0xFF),
(byte)((value >> 56) & 0xFF),
(byte)((value >> 48) & 0xFF),
(byte)((value >> 40) & 0xFF),
(byte)((value >> 32) & 0xFF),
(byte)((value >> 24) & 0xFF),
(byte)((value >> 16) & 0xFF),
(byte)((value >> 8) & 0xFF),
(byte)(value & 0xFF),
];
return output;
}
/// <summary>
/// Convert a UInt64 to a byte array
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static byte[] ToByteArrayLittleEndian(this System.UInt128 value)
{
byte[] output =
[
(byte)(value & 0xFF),
(byte)((value >> 8) & 0xFF),
(byte)((value >> 16) & 0xFF),
(byte)((value >> 24) & 0xFF),
(byte)((value >> 32) & 0xFF),
(byte)((value >> 40) & 0xFF),
(byte)((value >> 48) & 0xFF),
(byte)((value >> 56) & 0xFF),
(byte)((value >> 64) & 0xFF),
(byte)((value >> 72) & 0xFF),
(byte)((value >> 80) & 0xFF),
(byte)((value >> 88) & 0xFF),
(byte)((value >> 96) & 0xFF),
(byte)((value >> 104) & 0xFF),
(byte)((value >> 112) & 0xFF),
(byte)((value >> 120) & 0xFF),
];
return output;
}
#endif
#endregion
}
}

View File

@@ -1,9 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
#if NET7_0_OR_GREATER
using System.Numerics;
#endif
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
@@ -670,8 +667,10 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in machine native format</remarks>
public static Int128 ReadInt128(this Stream stream)
{
byte[] buffer = ReadExactlyToBuffer(stream, 16);
return (Int128)new BigInteger(buffer);
if (BitConverter.IsLittleEndian)
return stream.ReadInt128LittleEndian();
else
return stream.ReadInt128BigEndian();
}
/// <summary>
@@ -681,8 +680,17 @@ namespace SabreTools.IO.Extensions
public static Int128 ReadInt128BigEndian(this Stream stream)
{
byte[] buffer = ReadExactlyToBuffer(stream, 16);
Array.Reverse(buffer);
return (Int128)new BigInteger(buffer);
return buffer.ToInt128BigEndian(0);
}
/// <summary>
/// Read an Int128 from the stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static Int128 ReadInt128LittleEndian(this Stream stream)
{
byte[] buffer = ReadExactlyToBuffer(stream, 16);
return buffer.ToInt128LittleEndian(0);
}
/// <summary>
@@ -691,8 +699,10 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in machine native format</remarks>
public static UInt128 ReadUInt128(this Stream stream)
{
byte[] buffer = ReadExactlyToBuffer(stream, 16);
return (UInt128)new BigInteger(buffer);
if (BitConverter.IsLittleEndian)
return stream.ReadUInt128LittleEndian();
else
return stream.ReadUInt128BigEndian();
}
/// <summary>
@@ -702,8 +712,17 @@ namespace SabreTools.IO.Extensions
public static UInt128 ReadUInt128BigEndian(this Stream stream)
{
byte[] buffer = ReadExactlyToBuffer(stream, 16);
Array.Reverse(buffer);
return (UInt128)new BigInteger(buffer);
return buffer.ToUInt128BigEndian(0);
}
/// <summary>
/// Read a UInt128 from the stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static UInt128 ReadUInt128LittleEndian(this Stream stream)
{
byte[] buffer = ReadExactlyToBuffer(stream, 16);
return buffer.ToUInt128LittleEndian(0);
}
#endif
@@ -1930,9 +1949,10 @@ namespace SabreTools.IO.Extensions
/// <remarks>Only works properly on seekable streams</remarks>
public static Int128 PeekInt128(this Stream stream)
{
Int128 value = stream.ReadInt128();
stream.SeekIfPossible(-16, SeekOrigin.Current);
return value;
if (BitConverter.IsLittleEndian)
return stream.PeekInt128LittleEndian();
else
return stream.PeekInt128BigEndian();
}
/// <summary>
@@ -1947,6 +1967,18 @@ namespace SabreTools.IO.Extensions
return value;
}
/// <summary>
/// Peek an Int128 from the stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
/// <remarks>Only works properly on seekable streams</remarks>
public static Int128 PeekInt128LittleEndian(this Stream stream)
{
Int128 value = stream.ReadInt128LittleEndian();
stream.SeekIfPossible(-16, SeekOrigin.Current);
return value;
}
/// <summary>
/// Peek a UInt128 from the stream
/// </summary>
@@ -1954,9 +1986,10 @@ namespace SabreTools.IO.Extensions
/// <remarks>Only works properly on seekable streams</remarks>
public static UInt128 PeekUInt128(this Stream stream)
{
UInt128 value = stream.ReadUInt128();
stream.SeekIfPossible(-16, SeekOrigin.Current);
return value;
if (BitConverter.IsLittleEndian)
return stream.PeekUInt128LittleEndian();
else
return stream.PeekUInt128BigEndian();
}
/// <summary>
@@ -1970,6 +2003,18 @@ namespace SabreTools.IO.Extensions
stream.SeekIfPossible(-16, SeekOrigin.Current);
return value;
}
/// <summary>
/// Peek a UInt128 from the stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
/// <remarks>Only works properly on seekable streams</remarks>
public static UInt128 PeekUInt128LittleEndian(this Stream stream)
{
UInt128 value = stream.ReadUInt128LittleEndian();
stream.SeekIfPossible(-16, SeekOrigin.Current);
return value;
}
#endif
#endregion
@@ -2858,14 +2903,10 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in machine native format</remarks>
public static bool TryReadInt128(this Stream stream, out Int128 value)
{
if (stream.Position > stream.Length - 16)
{
value = default;
return false;
}
value = stream.ReadInt128();
return true;
if (BitConverter.IsLittleEndian)
return stream.TryReadInt128LittleEndian(out value);
else
return stream.TryReadInt128BigEndian(out value);
}
/// <summary>
@@ -2885,10 +2926,10 @@ namespace SabreTools.IO.Extensions
}
/// <summary>
/// Read a UInt128 from the stream
/// Read an Int128 from the stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static bool TryReadUInt128(this Stream stream, out UInt128 value)
/// <remarks>Reads in little-endian format</remarks>
public static bool TryReadInt128LittleEndian(this Stream stream, out Int128 value)
{
if (stream.Position > stream.Length - 16)
{
@@ -2896,10 +2937,22 @@ namespace SabreTools.IO.Extensions
return false;
}
value = stream.ReadUInt128();
value = stream.ReadInt128LittleEndian();
return true;
}
/// <summary>
/// Read a UInt128 from the stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static bool TryReadUInt128(this Stream stream, out UInt128 value)
{
if (BitConverter.IsLittleEndian)
return stream.TryReadUInt128LittleEndian(out value);
else
return stream.TryReadUInt128BigEndian(out value);
}
/// <summary>
/// Read a UInt128 from the stream
/// </summary>
@@ -2915,6 +2968,22 @@ namespace SabreTools.IO.Extensions
value = stream.ReadUInt128BigEndian();
return true;
}
/// <summary>
/// Read a UInt128 from the stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static bool TryReadUInt128LittleEndian(this Stream stream, out UInt128 value)
{
if (stream.Position > stream.Length - 16)
{
value = default;
return false;
}
value = stream.ReadUInt128LittleEndian();
return true;
}
#endif
#endregion

View File

@@ -1,8 +1,5 @@
using System;
using System.IO;
#if NET7_0_OR_GREATER
using System.Numerics;
#endif
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
@@ -490,13 +487,11 @@ namespace SabreTools.IO.Extensions
/// <summary>
/// Write an Int128
/// </summary>
/// <remarks>Writes in little-endian format</remarks>
public static bool Write(this Stream stream, Int128 value)
{
byte[] buffer = ((BigInteger)value).ToByteArray();
byte[] padded = new byte[16];
Array.Copy(buffer, 0, padded, 16 - buffer.Length, buffer.Length);
return WriteFromBuffer(stream, padded);
byte[] buffer = value.ToByteArrayLittleEndian();
return WriteFromBuffer(stream, buffer);
}
/// <summary>
@@ -505,24 +500,18 @@ namespace SabreTools.IO.Extensions
/// <remarks>Writes in big-endian format</remarks>
public static bool WriteBigEndian(this Stream stream, Int128 value)
{
byte[] buffer = ((BigInteger)value).ToByteArray();
Array.Reverse(buffer);
byte[] padded = new byte[16];
Array.Copy(buffer, 0, padded, 16 - buffer.Length, buffer.Length);
return WriteFromBuffer(stream, padded);
byte[] buffer = value.ToByteArrayBigEndian();
return WriteFromBuffer(stream, buffer);
}
/// <summary>
/// Write a UInt128
/// </summary>
/// <remarks>Writes in little-endian format</remarks>
public static bool Write(this Stream stream, UInt128 value)
{
byte[] buffer = ((BigInteger)value).ToByteArray();
byte[] padded = new byte[16];
Array.Copy(buffer, 0, padded, 16 - buffer.Length, buffer.Length);
return WriteFromBuffer(stream, padded);
byte[] buffer = value.ToByteArrayLittleEndian();
return WriteFromBuffer(stream, buffer);
}
/// <summary>
@@ -531,12 +520,8 @@ namespace SabreTools.IO.Extensions
/// <remarks>Writes in big-endian format</remarks>
public static bool WriteBigEndian(this Stream stream, UInt128 value)
{
byte[] buffer = ((BigInteger)value).ToByteArray();
Array.Reverse(buffer);
byte[] padded = new byte[16];
Array.Copy(buffer, 0, padded, 16 - buffer.Length, buffer.Length);
return WriteFromBuffer(stream, padded);
byte[] buffer = value.ToByteArrayBigEndian();
return WriteFromBuffer(stream, buffer);
}
#endif