8 Commits
1.6.0 ... 1.6.2

Author SHA1 Message Date
Matt Nadareski
04f095018c Bump version 2024-12-16 13:59:19 -05:00
Matt Nadareski
ff18049832 Add explicit value building to extensions 2024-12-16 13:55:32 -05:00
Matt Nadareski
5e7d2901c8 Update IO to 1.5.1 2024-12-16 12:22:32 -05:00
Matt Nadareski
add7bc8ea5 Allow symbols to be packed 2024-12-16 12:20:05 -05:00
Matt Nadareski
f95853cc87 Use publish script and update README 2024-12-06 10:59:42 -05:00
Matt Nadareski
3f146d45a8 Bump version 2024-11-29 19:54:37 -05:00
Matt Nadareski
f3689087e6 Add alignment tests 2024-11-28 21:31:38 -05:00
Matt Nadareski
d2d191d86f Add boundary alignment stream extension 2024-11-28 21:17:33 -05:00
12 changed files with 1326 additions and 267 deletions

View File

@@ -1,4 +1,4 @@
name: Nuget Pack
name: Build and Test
on:
push:
@@ -18,29 +18,23 @@ jobs:
with:
dotnet-version: 9.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build library
run: dotnet build
- name: Run tests
run: dotnet test
- name: Pack
run: dotnet pack
- name: Run publish script
run: ./publish-nix.sh
- name: Upload build
uses: actions/upload-artifact@v4
with:
name: 'Nuget Package'
path: 'SabreTools.IO/bin/Release/*.nupkg'
path: "*.nupkg,*.snupkg"
- name: Upload to rolling
uses: ncipollo/release-action@v1.14.0
with:
allowUpdates: True
artifacts: 'SabreTools.IO/bin/Release/*.nupkg'
artifacts: "*.nupkg,*.snupkg"
body: 'Last built commit: ${{ github.sha }}'
name: 'Rolling Release'
prerelease: True

View File

@@ -17,4 +17,4 @@ jobs:
run: dotnet build
- name: Run tests
run: dotnet test
run: dotnet test

View File

@@ -1,5 +1,7 @@
# SabreTools.IO
[![Build and Test](https://github.com/SabreTools/SabreTools.IO/actions/workflows/build_and_test.yml/badge.svg)](https://github.com/SabreTools/SabreTools.IO/actions/workflows/build_and_test.yml)
This library comprises I/O functionality for the following file types:
- ClrMamePro-derived Metadata files
@@ -9,3 +11,9 @@ This library comprises I/O functionality for the following file types:
There are also some extensions that are useful for wrapping common functionality required by SabreTools.
Find the link to the Nuget package [here](https://www.nuget.org/packages/SabreTools.IO).
## Releases
For the most recent stable build, download the latest release here: [Releases Page](https://github.com/SabreTools/SabreTools.IO/releases)
For the latest WIP build here: [Rolling Release](https://github.com/SabreTools/SabreTools.IO/releases/rolling)

View File

@@ -163,6 +163,15 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0x0001, read);
}
[Fact]
public void ReadInt16LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
short read = br.ReadInt16LittleEndian();
Assert.Equal(0x0100, read);
}
[Fact]
public void ReadUInt16Test()
{
@@ -181,6 +190,15 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0x0001, read);
}
[Fact]
public void ReadUInt16LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
ushort read = br.ReadUInt16LittleEndian();
Assert.Equal(0x0100, read);
}
[Fact]
public void ReadWORDTest()
{
@@ -199,6 +217,15 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0x0001, read);
}
[Fact]
public void ReadWORDLittleEndianTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
ushort read = br.ReadWORDLittleEndian();
Assert.Equal(0x0100, read);
}
#if NET6_0_OR_GREATER
[Fact]
public void ReadHalfTest()
@@ -239,6 +266,15 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0x000102, read);
}
[Fact]
public void ReadInt24LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
int read = br.ReadInt24LittleEndian();
Assert.Equal(0x020100, read);
}
[Fact]
public void ReadUInt24Test()
{
@@ -257,6 +293,15 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal((uint)0x000102, read);
}
[Fact]
public void ReadUInt24LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
uint read = br.ReadUInt24LittleEndian();
Assert.Equal((uint)0x020100, read);
}
[Fact]
public void ReadInt32Test()
{
@@ -275,6 +320,15 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0x00010203, read);
}
[Fact]
public void ReadInt32LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
int read = br.ReadInt32LittleEndian();
Assert.Equal(0x03020100, read);
}
[Fact]
public void ReadUInt32Test()
{
@@ -293,6 +347,15 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal((uint)0x00010203, read);
}
[Fact]
public void ReadUInt32LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
uint read = br.ReadUInt32LittleEndian();
Assert.Equal((uint)0x03020100, read);
}
[Fact]
public void ReadDWORDTest()
{
@@ -311,6 +374,15 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal((uint)0x00010203, read);
}
[Fact]
public void ReadDWORDLittleEndianTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
uint read = br.ReadDWORDLittleEndian();
Assert.Equal((uint)0x03020100, read);
}
[Fact]
public void ReadSingleTest()
{
@@ -349,6 +421,15 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0x000102030405, read);
}
[Fact]
public void ReadInt48LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
long read = br.ReadInt48LittleEndian();
Assert.Equal(0x050403020100, read);
}
[Fact]
public void ReadUInt48Test()
{
@@ -367,6 +448,15 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal((ulong)0x000102030405, read);
}
[Fact]
public void ReadUInt48LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
ulong read = br.ReadUInt48LittleEndian();
Assert.Equal((ulong)0x050403020100, read);
}
[Fact]
public void ReadInt64Test()
{
@@ -385,6 +475,15 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0x0001020304050607, read);
}
[Fact]
public void ReadInt64LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
long read = br.ReadInt64LittleEndian();
Assert.Equal(0x0706050403020100, read);
}
[Fact]
public void ReadUInt64Test()
{
@@ -403,6 +502,42 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal((ulong)0x0001020304050607, read);
}
[Fact]
public void ReadUInt64LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
ulong read = br.ReadUInt64LittleEndian();
Assert.Equal((ulong)0x0706050403020100, read);
}
[Fact]
public void ReadQWORDTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
ulong read = br.ReadQWORD();
Assert.Equal((ulong)0x0706050403020100, read);
}
[Fact]
public void ReadQWORDBigEndianTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
ulong read = br.ReadQWORDBigEndian();
Assert.Equal((ulong)0x0001020304050607, read);
}
[Fact]
public void ReadQWORDLittleEndianTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
ulong read = br.ReadQWORDLittleEndian();
Assert.Equal((ulong)0x0706050403020100, read);
}
[Fact]
public void ReadDoubleTest()
{

View File

@@ -86,6 +86,14 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0x0001, read);
}
[Fact]
public void ReadInt16LittleEndianTest()
{
int offset = 0;
short read = _bytes.ReadInt16LittleEndian(ref offset);
Assert.Equal(0x0100, read);
}
[Fact]
public void ReadUInt16Test()
{
@@ -102,6 +110,14 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0x0001, read);
}
[Fact]
public void ReadUInt16LittleEndianTest()
{
int offset = 0;
ushort read = _bytes.ReadUInt16LittleEndian(ref offset);
Assert.Equal(0x0100, read);
}
[Fact]
public void ReadWORDTest()
{
@@ -118,6 +134,14 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0x0001, read);
}
[Fact]
public void ReadWORDLittleEndianTest()
{
int offset = 0;
ushort read = _bytes.ReadWORDLittleEndian(ref offset);
Assert.Equal(0x0100, read);
}
#if NET6_0_OR_GREATER
[Fact]
public void ReadHalfTest()
@@ -154,6 +178,14 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0x000102, read);
}
[Fact]
public void ReadInt24LittleEndianTest()
{
int offset = 0;
int read = _bytes.ReadInt24LittleEndian(ref offset);
Assert.Equal(0x020100, read);
}
[Fact]
public void ReadUInt24Test()
{
@@ -170,6 +202,14 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal((uint)0x000102, read);
}
[Fact]
public void ReadUInt24LittleEndianTest()
{
int offset = 0;
uint read = _bytes.ReadUInt24LittleEndian(ref offset);
Assert.Equal((uint)0x020100, read);
}
[Fact]
public void ReadInt32Test()
{
@@ -186,6 +226,14 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0x00010203, read);
}
[Fact]
public void ReadInt32LittleEndianTest()
{
int offset = 0;
int read = _bytes.ReadInt32LittleEndian(ref offset);
Assert.Equal(0x03020100, read);
}
[Fact]
public void ReadUInt32Test()
{
@@ -202,6 +250,14 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal((uint)0x00010203, read);
}
[Fact]
public void ReadUInt32LittleEndianTest()
{
int offset = 0;
uint read = _bytes.ReadUInt32LittleEndian(ref offset);
Assert.Equal((uint)0x03020100, read);
}
[Fact]
public void ReadDWORDTest()
{
@@ -218,6 +274,14 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal((uint)0x00010203, read);
}
[Fact]
public void ReadDWORDLittleEndianTest()
{
int offset = 0;
uint read = _bytes.ReadDWORDLittleEndian(ref offset);
Assert.Equal((uint)0x03020100, read);
}
[Fact]
public void ReadSingleTest()
{
@@ -252,6 +316,14 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0x000102030405, read);
}
[Fact]
public void ReadInt48LittleEndianTest()
{
int offset = 0;
long read = _bytes.ReadInt48LittleEndian(ref offset);
Assert.Equal(0x050403020100, read);
}
[Fact]
public void ReadUInt48Test()
{
@@ -268,6 +340,14 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal((ulong)0x000102030405, read);
}
[Fact]
public void ReadUInt48LittleEndianTest()
{
int offset = 0;
ulong read = _bytes.ReadUInt48LittleEndian(ref offset);
Assert.Equal((ulong)0x050403020100, read);
}
[Fact]
public void ReadInt64Test()
{
@@ -284,6 +364,14 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0x0001020304050607, read);
}
[Fact]
public void ReadInt64LittleEndianTest()
{
int offset = 0;
long read = _bytes.ReadInt64LittleEndian(ref offset);
Assert.Equal(0x0706050403020100, read);
}
[Fact]
public void ReadUInt64Test()
{
@@ -300,6 +388,38 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal((ulong)0x0001020304050607, read);
}
[Fact]
public void ReadUInt64LittleEndianTest()
{
int offset = 0;
ulong read = _bytes.ReadUInt64LittleEndian(ref offset);
Assert.Equal((ulong)0x0706050403020100, read);
}
[Fact]
public void ReadQWORDTest()
{
int offset = 0;
ulong read = _bytes.ReadQWORD(ref offset);
Assert.Equal((ulong)0x0706050403020100, read);
}
[Fact]
public void ReadQWORDBigEndianTest()
{
int offset = 0;
ulong read = _bytes.ReadQWORDBigEndian(ref offset);
Assert.Equal((ulong)0x0001020304050607, read);
}
[Fact]
public void ReadQWORDLittleEndianTest()
{
int offset = 0;
ulong read = _bytes.ReadQWORDLittleEndian(ref offset);
Assert.Equal((ulong)0x0706050403020100, read);
}
[Fact]
public void ReadDoubleTest()
{

View File

@@ -7,6 +7,63 @@ namespace SabreTools.IO.Test.Extensions
{
public class StreamExtensionsTests
{
#region Align to Boundary
[Fact]
public void AlignToBoundary_Null_False()
{
Stream? stream = null;
byte alignment = 4;
bool actual = stream.AlignToBoundary(alignment);
Assert.False(actual);
}
[Fact]
public void AlignToBoundary_Empty_False()
{
Stream? stream = new MemoryStream([]);
byte alignment = 4;
bool actual = stream.AlignToBoundary(alignment);
Assert.False(actual);
}
[Fact]
public void AlignToBoundary_EOF_False()
{
Stream? stream = new MemoryStream([0x01, 0x02]);
byte alignment = 4;
stream.Position = 1;
bool actual = stream.AlignToBoundary(alignment);
Assert.False(actual);
}
[Fact]
public void AlignToBoundary_TooShort_False()
{
Stream? stream = new MemoryStream([0x01, 0x02]);
byte alignment = 4;
stream.Position = 1;
bool actual = stream.AlignToBoundary(alignment);
Assert.False(actual);
}
[Fact]
public void AlignToBoundary_CanAlign_True()
{
Stream? stream = new MemoryStream([0x01, 0x02, 0x03, 0x04, 0x05]);
byte alignment = 4;
stream.Position = 1;
bool actual = stream.AlignToBoundary(alignment);
Assert.True(actual);
}
#endregion
#region Seek If Possible
[Fact]
public void SeekIfPossible_NonSeekable_CurrentPosition()
{
@@ -47,6 +104,8 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(13, actual);
}
#endregion
/// <summary>
/// Represents a hidden non-seekable stream
/// </summary>

View File

@@ -90,6 +90,14 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0x0001, read);
}
[Fact]
public void ReadInt16LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
short read = stream.ReadInt16LittleEndian();
Assert.Equal(0x0100, read);
}
[Fact]
public void ReadUInt16Test()
{
@@ -106,6 +114,14 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0x0001, read);
}
[Fact]
public void ReadUInt16LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
ushort read = stream.ReadUInt16LittleEndian();
Assert.Equal(0x0100, read);
}
[Fact]
public void ReadWORDTest()
{
@@ -122,6 +138,14 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0x0001, read);
}
[Fact]
public void ReadWORDLittleEndianTest()
{
var stream = new MemoryStream(_bytes);
ushort read = stream.ReadWORDLittleEndian();
Assert.Equal(0x0100, read);
}
#if NET6_0_OR_GREATER
[Fact]
public void ReadHalfTest()
@@ -158,6 +182,14 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0x000102, read);
}
[Fact]
public void ReadInt24LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
int read = stream.ReadInt24LittleEndian();
Assert.Equal(0x020100, read);
}
[Fact]
public void ReadUInt24Test()
{
@@ -174,6 +206,14 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal((uint)0x000102, read);
}
[Fact]
public void ReadUInt24LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
uint read = stream.ReadUInt24LittleEndian();
Assert.Equal((uint)0x020100, read);
}
[Fact]
public void ReadInt32Test()
{
@@ -190,6 +230,14 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0x00010203, read);
}
[Fact]
public void ReadInt32LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
int read = stream.ReadInt32LittleEndian();
Assert.Equal(0x03020100, read);
}
[Fact]
public void ReadUInt32Test()
{
@@ -206,6 +254,14 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal((uint)0x00010203, read);
}
[Fact]
public void ReadUInt32LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
uint read = stream.ReadUInt32LittleEndian();
Assert.Equal((uint)0x03020100, read);
}
[Fact]
public void ReadDWORDTest()
{
@@ -222,6 +278,14 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal((uint)0x00010203, read);
}
[Fact]
public void ReadDWORDLittleEndianTest()
{
var stream = new MemoryStream(_bytes);
uint read = stream.ReadDWORDLittleEndian();
Assert.Equal((uint)0x03020100, read);
}
[Fact]
public void ReadSingleTest()
{
@@ -256,6 +320,14 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0x000102030405, read);
}
[Fact]
public void ReadInt48LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
long read = stream.ReadInt48LittleEndian();
Assert.Equal(0x050403020100, read);
}
[Fact]
public void ReadUInt48Test()
{
@@ -272,6 +344,14 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal((ulong)0x000102030405, read);
}
[Fact]
public void ReadUInt48LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
ulong read = stream.ReadUInt48LittleEndian();
Assert.Equal((ulong)0x050403020100, read);
}
[Fact]
public void ReadInt64Test()
{
@@ -288,6 +368,14 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0x0001020304050607, read);
}
[Fact]
public void ReadInt64LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
long read = stream.ReadInt64LittleEndian();
Assert.Equal(0x0706050403020100, read);
}
[Fact]
public void ReadUInt64Test()
{
@@ -304,6 +392,38 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal((ulong)0x0001020304050607, read);
}
[Fact]
public void ReadUInt64LittleEndianTest()
{
var stream = new MemoryStream(_bytes);
ulong read = stream.ReadUInt64LittleEndian();
Assert.Equal((ulong)0x0706050403020100, read);
}
[Fact]
public void ReadQWORDTest()
{
var stream = new MemoryStream(_bytes);
ulong read = stream.ReadQWORD();
Assert.Equal((ulong)0x0706050403020100, read);
}
[Fact]
public void ReadQWORDBigEndianTest()
{
var stream = new MemoryStream(_bytes);
ulong read = stream.ReadQWORDBigEndian();
Assert.Equal((ulong)0x0001020304050607, read);
}
[Fact]
public void ReadQWORDLittleEndianTest()
{
var stream = new MemoryStream(_bytes);
ulong read = stream.ReadQWORDLittleEndian();
Assert.Equal((ulong)0x0706050403020100, read);
}
[Fact]
public void ReadDoubleTest()
{

View File

@@ -13,7 +13,6 @@ namespace SabreTools.IO.Extensions
/// <summary>
/// Extensions for BinaryReader
/// </summary>
/// TODO: Handle proper negative values for Int24 and Int48
public static class BinaryReaderExtensions
{
/// <inheritdoc cref="BinaryReader.Read(byte[], int, int)"/>
@@ -57,8 +56,17 @@ namespace SabreTools.IO.Extensions
public static short ReadInt16BigEndian(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(2);
Array.Reverse(buffer);
return BitConverter.ToInt16(buffer, 0);
return (short)(buffer[1]
| (buffer[0] << 8));
}
/// <inheritdoc cref="BinaryReader.ReadInt16"/>
/// <remarks>Reads in little-endian format</remarks>
public static short ReadInt16LittleEndian(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(2);
return (short)(buffer[0]
| (buffer[1] << 8));
}
/// <inheritdoc cref="BinaryReader.ReadUInt16"/>
@@ -66,8 +74,17 @@ namespace SabreTools.IO.Extensions
public static ushort ReadUInt16BigEndian(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(2);
Array.Reverse(buffer);
return BitConverter.ToUInt16(buffer, 0);
return (ushort)(buffer[1]
| (buffer[0] << 8));
}
/// <inheritdoc cref="BinaryReader.ReadUInt16"/>
/// <remarks>Reads in little-endian format</remarks>
public static ushort ReadUInt16LittleEndian(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(2);
return (ushort)(buffer[0]
| (buffer[1] << 8));
}
/// <summary>
@@ -83,6 +100,13 @@ namespace SabreTools.IO.Extensions
public static ushort ReadWORDBigEndian(this BinaryReader reader)
=> reader.ReadUInt16BigEndian();
/// <summary>
/// Read a WORD (2-byte) from the base stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static ushort ReadWORDLittleEndian(this BinaryReader reader)
=> reader.ReadUInt16LittleEndian();
// Half was introduced in net5.0 but doesn't have a BitConverter implementation until net6.0
#if NET6_0_OR_GREATER
/// <inheritdoc cref="BinaryReader.ReadHalf"/>
@@ -96,55 +120,75 @@ namespace SabreTools.IO.Extensions
#endif
/// <summary>
/// Read an Int24 encoded as an Int32
/// Read an Int24 encoded as an Int32 from the base stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static int ReadInt24(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(3);
byte[] padded = new byte[4];
Array.Copy(buffer, padded, 3);
return BitConverter.ToInt32(padded, 0);
if (BitConverter.IsLittleEndian)
return reader.ReadInt24LittleEndian();
else
return reader.ReadInt24BigEndian();
}
/// <summary>
/// Read an Int24 encoded as an Int32
/// Read an Int24 encoded as an Int32 from the base stream
/// </summary>
/// <remarks>Reads in big-endian format</remarks>
public static int ReadInt24BigEndian(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(3);
Array.Reverse(buffer);
byte[] padded = new byte[4];
Array.Copy(buffer, padded, 3);
return BitConverter.ToInt32(padded, 0);
return (int)(buffer[2]
| (buffer[1] << 8)
| (buffer[0] << 16));
}
/// <summary>
/// Read a UInt24 encoded as a UInt32
/// Read an Int24 encoded as an Int32 from the base stream
/// </summary>
public static uint ReadUInt24(this BinaryReader reader)
/// <remarks>Reads in little-endian format</remarks>
public static int ReadInt24LittleEndian(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(3);
byte[] padded = new byte[4];
Array.Copy(buffer, padded, 3);
return BitConverter.ToUInt32(padded, 0);
return (int)(buffer[0]
| (buffer[1] << 8)
| (buffer[2] << 16));
}
/// <summary>
/// Read a UInt24 encoded as a UInt32
/// Read a UInt24 encoded as a UInt32 from the base stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static uint ReadUInt24(this BinaryReader reader)
{
if (BitConverter.IsLittleEndian)
return reader.ReadUInt24LittleEndian();
else
return reader.ReadUInt24BigEndian();
}
/// <summary>
/// Read a UInt24 encoded as a UInt32 from the base stream
/// </summary>
/// <remarks>Reads in big-endian format</remarks>
public static uint ReadUInt24BigEndian(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(3);
Array.Reverse(buffer);
return (uint)(buffer[2]
| (buffer[1] << 8)
| (buffer[0] << 16));
}
byte[] padded = new byte[4];
Array.Copy(buffer, padded, 3);
return BitConverter.ToUInt32(padded, 0);
/// <summary>
/// Read a UInt24 encoded as a UInt32 from the base stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static uint ReadUInt24LittleEndian(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(3);
return (uint)(buffer[0]
| (buffer[1] << 8)
| (buffer[2] << 16));
}
/// <inheritdoc cref="BinaryReader.ReadInt32"/>
@@ -152,16 +196,43 @@ namespace SabreTools.IO.Extensions
public static int ReadInt32BigEndian(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(4);
Array.Reverse(buffer);
return BitConverter.ToInt32(buffer, 0);
return (int)(buffer[3]
| (buffer[2] << 8)
| (buffer[1] << 16)
| (buffer[0] << 24));
}
/// <inheritdoc cref="BinaryReader.ReadInt32"/>
/// <remarks>Reads in little-endian format</remarks>
public static int ReadInt32LittleEndian(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(4);
return (int)(buffer[0]
| (buffer[1] << 8)
| (buffer[2] << 16)
| (buffer[3] << 24));
}
/// <inheritdoc cref="BinaryReader.ReadUInt32"/>
/// <remarks>Reads in big-endian format</remarks>
public static uint ReadUInt32BigEndian(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(4);
Array.Reverse(buffer);
return BitConverter.ToUInt32(buffer, 0);
return (uint)(buffer[3]
| (buffer[2] << 8)
| (buffer[1] << 16)
| (buffer[0] << 24));
}
/// <inheritdoc cref="BinaryReader.ReadUInt32"/>
/// <remarks>Reads in little-endian format</remarks>
public static uint ReadUInt32LittleEndian(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(4);
return (uint)(buffer[0]
| (buffer[1] << 8)
| (buffer[2] << 16)
| (buffer[3] << 24));
}
/// <summary>
@@ -177,6 +248,13 @@ namespace SabreTools.IO.Extensions
public static uint ReadDWORDBigEndian(this BinaryReader reader)
=> reader.ReadUInt32BigEndian();
/// <summary>
/// Read a DWORD (4-byte) from the base stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static uint ReadDWORDLittleEndian(this BinaryReader reader)
=> reader.ReadUInt32LittleEndian();
/// <inheritdoc cref="BinaryReader.ReadSingle"/>
/// <remarks>Reads in big-endian format</remarks>
public static float ReadSingleBigEndian(this BinaryReader reader)
@@ -187,55 +265,87 @@ namespace SabreTools.IO.Extensions
}
/// <summary>
/// Read an Int48 encoded as an Int64
/// Read an Int48 encoded as an Int64 from the base stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static long ReadInt48(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(6);
byte[] padded = new byte[8];
Array.Copy(buffer, padded, 6);
return BitConverter.ToInt64(padded, 0);
if (BitConverter.IsLittleEndian)
return reader.ReadInt48LittleEndian();
else
return reader.ReadInt48BigEndian();
}
/// <summary>
/// Read an Int48 encoded as an Int64
/// Read an Int48 encoded as an Int64 from the base stream
/// </summary>
/// <remarks>Reads in big-endian format</remarks>
public static long ReadInt48BigEndian(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(6);
Array.Reverse(buffer);
byte[] padded = new byte[8];
Array.Copy(buffer, padded, 6);
return BitConverter.ToInt64(padded, 0);
return ((long)buffer[5] << 0)
| ((long)buffer[4] << 8)
| ((long)buffer[3] << 16)
| ((long)buffer[2] << 24)
| ((long)buffer[1] << 32)
| ((long)buffer[0] << 40);
}
/// <summary>
/// Read a UInt48 encoded as a UInt64
/// Read an Int48 encoded as an Int64 from the base stream
/// </summary>
public static ulong ReadUInt48(this BinaryReader reader)
/// <remarks>Reads in little-endian format</remarks>
public static long ReadInt48LittleEndian(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(6);
byte[] padded = new byte[8];
Array.Copy(buffer, padded, 6);
return BitConverter.ToUInt64(padded, 0);
return ((long)buffer[0] << 0)
| ((long)buffer[1] << 8)
| ((long)buffer[2] << 16)
| ((long)buffer[3] << 24)
| ((long)buffer[4] << 32)
| ((long)buffer[5] << 40);
}
/// <summary>
/// Read a UInt48 encoded as a UInt64
/// Read a UInt48 encoded as a UInt64 from the base stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static ulong ReadUInt48(this BinaryReader reader)
{
if (BitConverter.IsLittleEndian)
return reader.ReadUInt48LittleEndian();
else
return reader.ReadUInt48BigEndian();
}
/// <summary>
/// Read a UInt48 encoded as a UInt64 from the base stream
/// </summary>
/// <remarks>Reads in big-endian format</remarks>
public static ulong ReadUInt48BigEndian(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(6);
Array.Reverse(buffer);
return ((ulong)buffer[5] << 0)
| ((ulong)buffer[4] << 8)
| ((ulong)buffer[3] << 16)
| ((ulong)buffer[2] << 24)
| ((ulong)buffer[1] << 32)
| ((ulong)buffer[0] << 40);
}
byte[] padded = new byte[8];
Array.Copy(buffer, padded, 6);
return BitConverter.ToUInt64(padded, 0);
/// <summary>
/// Read an UInt48 encoded as an UInt64 from the base stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static ulong ReadUInt48LittleEndian(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(6);
return ((ulong)buffer[0] << 0)
| ((ulong)buffer[1] << 8)
| ((ulong)buffer[2] << 16)
| ((ulong)buffer[3] << 24)
| ((ulong)buffer[4] << 32)
| ((ulong)buffer[5] << 40);
}
/// <inheritdoc cref="BinaryReader.ReadInt64"/>
@@ -243,8 +353,29 @@ namespace SabreTools.IO.Extensions
public static long ReadInt64BigEndian(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(8);
Array.Reverse(buffer);
return BitConverter.ToInt64(buffer, 0);
return ((long)buffer[7] << 0)
| ((long)buffer[6] << 8)
| ((long)buffer[5] << 16)
| ((long)buffer[4] << 24)
| ((long)buffer[3] << 32)
| ((long)buffer[2] << 40)
| ((long)buffer[1] << 48)
| ((long)buffer[0] << 56);
}
/// <inheritdoc cref="BinaryReader.ReadInt64"/>
/// <remarks>Reads in little-endian format</remarks>
public static long ReadInt64LittleEndian(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(8);
return ((long)buffer[0] << 0)
| ((long)buffer[1] << 8)
| ((long)buffer[2] << 16)
| ((long)buffer[3] << 24)
| ((long)buffer[4] << 32)
| ((long)buffer[5] << 40)
| ((long)buffer[6] << 48)
| ((long)buffer[7] << 56);
}
/// <inheritdoc cref="BinaryReader.ReadUInt64"/>
@@ -252,10 +383,52 @@ namespace SabreTools.IO.Extensions
public static ulong ReadUInt64BigEndian(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(8);
Array.Reverse(buffer);
return BitConverter.ToUInt64(buffer, 0);
return ((ulong)buffer[7] << 0)
| ((ulong)buffer[6] << 8)
| ((ulong)buffer[5] << 16)
| ((ulong)buffer[4] << 24)
| ((ulong)buffer[3] << 32)
| ((ulong)buffer[2] << 40)
| ((ulong)buffer[1] << 48)
| ((ulong)buffer[0] << 56);
}
/// <inheritdoc cref="BinaryReader.ReadUInt64"/>
/// <remarks>Reads in little-endian format</remarks>
public static ulong ReadUInt64LittleEndian(this BinaryReader reader)
{
byte[] buffer = reader.ReadBytes(8);
return ((ulong)buffer[0] << 0)
| ((ulong)buffer[1] << 8)
| ((ulong)buffer[2] << 16)
| ((ulong)buffer[3] << 24)
| ((ulong)buffer[4] << 32)
| ((ulong)buffer[5] << 40)
| ((ulong)buffer[6] << 48)
| ((ulong)buffer[7] << 56);
}
/// <summary>
/// Read a QWORD (8-byte) from the base stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static ulong ReadQWORD(this BinaryReader reader)
=> reader.ReadUInt64();
/// <summary>
/// Read a QWORD (8-byte) from the base stream
/// </summary>
/// <remarks>Reads in big-endian format</remarks>
public static ulong ReadQWORDBigEndian(this BinaryReader reader)
=> reader.ReadUInt64BigEndian();
/// <summary>
/// Read a QWORD (8-byte) from the base stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static ulong ReadQWORDLittleEndian(this BinaryReader reader)
=> reader.ReadUInt64LittleEndian();
/// <inheritdoc cref="BinaryReader.ReadDouble"/>
/// <remarks>Reads in big-endian format</remarks>
public static double ReadDoubleBigEndian(this BinaryReader reader)

View File

@@ -12,7 +12,6 @@ namespace SabreTools.IO.Extensions
/// <summary>
/// Extensions for byte arrays
/// </summary>
/// TODO: Handle proper negative values for Int24 and Int48
public static class ByteArrayReaderExtensions
{
/// <summary>
@@ -20,7 +19,7 @@ namespace SabreTools.IO.Extensions
/// </summary>
public static byte ReadByte(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 1);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 1);
return buffer[0];
}
@@ -34,7 +33,7 @@ namespace SabreTools.IO.Extensions
/// Read a UInt8[] and increment the pointer to an array
/// </summary>
public static byte[] ReadBytes(this byte[] content, ref int offset, int count)
=> ReadToBuffer(content, ref offset, count);
=> ReadExactlyToBuffer(content, ref offset, count);
/// <summary>
/// Read a UInt8[] and increment the pointer to an array
@@ -42,7 +41,7 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static byte[] ReadBytesBigEndian(this byte[] content, ref int offset, int count)
{
byte[] buffer = ReadToBuffer(content, ref offset, count);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, count);
Array.Reverse(buffer);
return buffer;
}
@@ -52,7 +51,7 @@ namespace SabreTools.IO.Extensions
/// </summary>
public static sbyte ReadSByte(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 1);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 1);
return (sbyte)buffer[0];
}
@@ -61,17 +60,20 @@ namespace SabreTools.IO.Extensions
/// </summary>
public static char ReadChar(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 1);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 1);
return (char)buffer[0];
}
/// <summary>
/// Read an Int16 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static short ReadInt16(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 2);
return BitConverter.ToInt16(buffer, 0);
if (BitConverter.IsLittleEndian)
return content.ReadInt16LittleEndian(ref offset);
else
return content.ReadInt16BigEndian(ref offset);
}
/// <summary>
@@ -80,18 +82,32 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static short ReadInt16BigEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 2);
Array.Reverse(buffer);
return BitConverter.ToInt16(buffer, 0);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 2);
return (short)(buffer[1]
| (buffer[0] << 8));
}
/// <summary>
/// Read an Int16 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static short ReadInt16LittleEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 2);
return (short)(buffer[0]
| (buffer[1] << 8));
}
/// <summary>
/// Read a UInt16 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static ushort ReadUInt16(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 2);
return BitConverter.ToUInt16(buffer, 0);
if (BitConverter.IsLittleEndian)
return content.ReadUInt16LittleEndian(ref offset);
else
return content.ReadUInt16BigEndian(ref offset);
}
/// <summary>
@@ -100,14 +116,26 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static ushort ReadUInt16BigEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 2);
Array.Reverse(buffer);
return BitConverter.ToUInt16(buffer, 0);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 2);
return (ushort)(buffer[1]
| (buffer[0] << 8));
}
/// <summary>
/// Read a UInt16 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static ushort ReadUInt16LittleEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 2);
return (ushort)(buffer[0]
| (buffer[1] << 8));
}
/// <summary>
/// Read a WORD (2-byte) and increment the pointer to an array
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static ushort ReadWORD(this byte[] content, ref int offset)
=> content.ReadUInt16(ref offset);
@@ -118,14 +146,22 @@ namespace SabreTools.IO.Extensions
public static ushort ReadWORDBigEndian(this byte[] content, ref int offset)
=> content.ReadUInt16BigEndian(ref offset);
/// <summary>
/// Read a WORD (2-byte) and increment the pointer to an array
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static ushort ReadWORDLittleEndian(this byte[] content, ref int offset)
=> content.ReadUInt16LittleEndian(ref offset);
// Half was introduced in net5.0 but doesn't have a BitConverter implementation until net6.0
#if NET6_0_OR_GREATER
/// <summary>
/// Read a Half and increment the pointer to an array
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static Half ReadHalf(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 2);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 2);
return BitConverter.ToHalf(buffer, 0);
}
@@ -135,7 +171,7 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static Half ReadHalfBigEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 2);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 2);
Array.Reverse(buffer);
return BitConverter.ToHalf(buffer, 0);
}
@@ -144,13 +180,13 @@ namespace SabreTools.IO.Extensions
/// <summary>
/// Read an Int24 encoded as an Int32 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static int ReadInt24(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 3);
byte[] padded = new byte[4];
Array.Copy(buffer, padded, 3);
return BitConverter.ToInt32(padded, 0);
if (BitConverter.IsLittleEndian)
return content.ReadInt24LittleEndian(ref offset);
else
return content.ReadInt24BigEndian(ref offset);
}
/// <summary>
@@ -159,24 +195,34 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static int ReadInt24BigEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 3);
Array.Reverse(buffer);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 3);
return (int)(buffer[2]
| (buffer[1] << 8)
| (buffer[0] << 16));
}
byte[] padded = new byte[4];
Array.Copy(buffer, padded, 3);
return BitConverter.ToInt32(padded, 0);
/// <summary>
/// Read an Int24 encoded as an Int32 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static int ReadInt24LittleEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 3);
return (int)(buffer[0]
| (buffer[1] << 8)
| (buffer[2] << 16));
}
/// <summary>
/// Read a UInt24 encoded as a UInt32 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static uint ReadUInt24(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 3);
byte[] padded = new byte[4];
Array.Copy(buffer, padded, 3);
return BitConverter.ToUInt32(padded, 0);
if (BitConverter.IsLittleEndian)
return content.ReadUInt24LittleEndian(ref offset);
else
return content.ReadUInt24BigEndian(ref offset);
}
/// <summary>
@@ -185,21 +231,34 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static uint ReadUInt24BigEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 3);
Array.Reverse(buffer);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 3);
return (uint)(buffer[2]
| (buffer[1] << 8)
| (buffer[0] << 16));
}
byte[] padded = new byte[4];
Array.Copy(buffer, padded, 3);
return BitConverter.ToUInt32(padded, 0);
/// <summary>
/// Read a UInt24 encoded as a UInt32 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static uint ReadUInt24LittleEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 3);
return (uint)(buffer[0]
| (buffer[1] << 8)
| (buffer[2] << 16));
}
/// <summary>
/// Read an Int32 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static int ReadInt32(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 4);
return BitConverter.ToInt32(buffer, 0);
if (BitConverter.IsLittleEndian)
return content.ReadInt32LittleEndian(ref offset);
else
return content.ReadInt32BigEndian(ref offset);
}
/// <summary>
@@ -208,18 +267,36 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static int ReadInt32BigEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 4);
Array.Reverse(buffer);
return BitConverter.ToInt32(buffer, 0);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 4);
return (int)(buffer[3]
| (buffer[2] << 8)
| (buffer[1] << 16)
| (buffer[0] << 24));
}
/// <summary>
/// Read an Int32 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static int ReadInt32LittleEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 4);
return (int)(buffer[0]
| (buffer[1] << 8)
| (buffer[2] << 16)
| (buffer[3] << 24));
}
/// <summary>
/// Read a UInt32 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static uint ReadUInt32(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 4);
return BitConverter.ToUInt32(buffer, 0);
if (BitConverter.IsLittleEndian)
return content.ReadUInt32LittleEndian(ref offset);
else
return content.ReadUInt32BigEndian(ref offset);
}
/// <summary>
@@ -228,14 +305,30 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static uint ReadUInt32BigEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 4);
Array.Reverse(buffer);
return BitConverter.ToUInt32(buffer, 0);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 4);
return (uint)(buffer[3]
| (buffer[2] << 8)
| (buffer[1] << 16)
| (buffer[0] << 24));
}
/// <summary>
/// Read a UInt32 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static uint ReadUInt32LittleEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 4);
return (uint)(buffer[0]
| (buffer[1] << 8)
| (buffer[2] << 16)
| (buffer[3] << 24));
}
/// <summary>
/// Read a DWORD (4-byte) and increment the pointer to an array
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static uint ReadDWORD(this byte[] content, ref int offset)
=> content.ReadUInt32(ref offset);
@@ -246,12 +339,20 @@ namespace SabreTools.IO.Extensions
public static uint ReadDWORDBigEndian(this byte[] content, ref int offset)
=> content.ReadUInt32BigEndian(ref offset);
/// <summary>
/// Read a DWORD (4-byte) and increment the pointer to an array
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static uint ReadDWORDLittleEndian(this byte[] content, ref int offset)
=> content.ReadUInt32LittleEndian(ref offset);
/// <summary>
/// Read a Single and increment the pointer to an array
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static float ReadSingle(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 4);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 4);
return BitConverter.ToSingle(buffer, 0);
}
@@ -261,7 +362,7 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static float ReadSingleBigEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 4);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 4);
Array.Reverse(buffer);
return BitConverter.ToSingle(buffer, 0);
}
@@ -269,13 +370,13 @@ namespace SabreTools.IO.Extensions
/// <summary>
/// Read an Int48 encoded as an Int64 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static long ReadInt48(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 6);
byte[] padded = new byte[8];
Array.Copy(buffer, padded, 6);
return BitConverter.ToInt64(padded, 0);
if (BitConverter.IsLittleEndian)
return content.ReadInt48LittleEndian(ref offset);
else
return content.ReadInt48BigEndian(ref offset);
}
/// <summary>
@@ -284,47 +385,82 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static long ReadInt48BigEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 6);
Array.Reverse(buffer);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 6);
return ((long)buffer[5] << 0)
| ((long)buffer[4] << 8)
| ((long)buffer[3] << 16)
| ((long)buffer[2] << 24)
| ((long)buffer[1] << 32)
| ((long)buffer[0] << 40);
}
byte[] padded = new byte[8];
Array.Copy(buffer, padded, 6);
return BitConverter.ToInt64(padded, 0);
/// <summary>
/// Read an Int48 encoded as an Int64 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static long ReadInt48LittleEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 6);
return ((long)buffer[0] << 0)
| ((long)buffer[1] << 8)
| ((long)buffer[2] << 16)
| ((long)buffer[3] << 24)
| ((long)buffer[4] << 32)
| ((long)buffer[5] << 40);
}
/// <summary>
/// Read a UInt48 encoded as a UInt64 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static ulong ReadUInt48(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 6);
byte[] padded = new byte[8];
Array.Copy(buffer, padded, 6);
return BitConverter.ToUInt64(padded, 0);
if (BitConverter.IsLittleEndian)
return content.ReadUInt48LittleEndian(ref offset);
else
return content.ReadUInt48BigEndian(ref offset);
}
/// <summary>
/// Read a UInt48 encoded as a UInt64 and increment the pointer to an array
/// Read an UInt48 encoded as an UInt64 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in big-endian format</remarks>
public static ulong ReadUInt48BigEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 6);
Array.Reverse(buffer);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 6);
return ((ulong)buffer[5] << 0)
| ((ulong)buffer[4] << 8)
| ((ulong)buffer[3] << 16)
| ((ulong)buffer[2] << 24)
| ((ulong)buffer[1] << 32)
| ((ulong)buffer[0] << 40);
}
byte[] padded = new byte[8];
Array.Copy(buffer, padded, 6);
return BitConverter.ToUInt64(padded, 0);
/// <summary>
/// Read an UInt48 encoded as an UInt64 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static ulong ReadUInt48LittleEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 6);
return ((ulong)buffer[0] << 0)
| ((ulong)buffer[1] << 8)
| ((ulong)buffer[2] << 16)
| ((ulong)buffer[3] << 24)
| ((ulong)buffer[4] << 32)
| ((ulong)buffer[5] << 40);
}
/// <summary>
/// Read an Int64 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static long ReadInt64(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 8);
return BitConverter.ToInt64(buffer, 0);
if (BitConverter.IsLittleEndian)
return content.ReadInt64LittleEndian(ref offset);
else
return content.ReadInt64BigEndian(ref offset);
}
/// <summary>
@@ -333,18 +469,44 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static long ReadInt64BigEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 8);
Array.Reverse(buffer);
return BitConverter.ToInt64(buffer, 0);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 8);
return ((long)buffer[7] << 0)
| ((long)buffer[6] << 8)
| ((long)buffer[5] << 16)
| ((long)buffer[4] << 24)
| ((long)buffer[3] << 32)
| ((long)buffer[2] << 40)
| ((long)buffer[1] << 48)
| ((long)buffer[0] << 56);
}
/// <summary>
/// Read an Int64 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in big-endian format</remarks>
public static long ReadInt64LittleEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 8);
return ((long)buffer[0] << 0)
| ((long)buffer[1] << 8)
| ((long)buffer[2] << 16)
| ((long)buffer[3] << 24)
| ((long)buffer[4] << 32)
| ((long)buffer[5] << 40)
| ((long)buffer[6] << 48)
| ((long)buffer[7] << 56);
}
/// <summary>
/// Read a UInt64 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static ulong ReadUInt64(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 8);
return BitConverter.ToUInt64(buffer, 0);
if (BitConverter.IsLittleEndian)
return content.ReadUInt64LittleEndian(ref offset);
else
return content.ReadUInt64BigEndian(ref offset);
}
/// <summary>
@@ -353,17 +515,62 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static ulong ReadUInt64BigEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 8);
Array.Reverse(buffer);
return BitConverter.ToUInt64(buffer, 0);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 8);
return ((ulong)buffer[7] << 0)
| ((ulong)buffer[6] << 8)
| ((ulong)buffer[5] << 16)
| ((ulong)buffer[4] << 24)
| ((ulong)buffer[3] << 32)
| ((ulong)buffer[2] << 40)
| ((ulong)buffer[1] << 48)
| ((ulong)buffer[0] << 56);
}
/// <summary>
/// Read a UInt64 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static ulong ReadUInt64LittleEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 8);
return ((ulong)buffer[0] << 0)
| ((ulong)buffer[1] << 8)
| ((ulong)buffer[2] << 16)
| ((ulong)buffer[3] << 24)
| ((ulong)buffer[4] << 32)
| ((ulong)buffer[5] << 40)
| ((ulong)buffer[6] << 48)
| ((ulong)buffer[7] << 56);
}
/// <summary>
/// Read a QWORD (8-byte) and increment the pointer to an array
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static ulong ReadQWORD(this byte[] content, ref int offset)
=> content.ReadUInt64(ref offset);
/// <summary>
/// Read a QWORD (8-byte) and increment the pointer to an array
/// </summary>
/// <remarks>Reads in big-endian format</remarks>
public static ulong ReadQWORDBigEndian(this byte[] content, ref int offset)
=> content.ReadUInt64BigEndian(ref offset);
/// <summary>
/// Read a QWORD (8-byte) and increment the pointer to an array
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static ulong ReadQWORDLittleEndian(this byte[] content, ref int offset)
=> content.ReadUInt64LittleEndian(ref offset);
/// <summary>
/// Read a Double and increment the pointer to an array
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static double ReadDouble(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 8);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 8);
return BitConverter.ToDouble(buffer, 0);
}
@@ -373,7 +580,7 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static double ReadDoubleBigEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 8);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 8);
Array.Reverse(buffer);
return BitConverter.ToDouble(buffer, 0);
}
@@ -381,9 +588,10 @@ namespace SabreTools.IO.Extensions
/// <summary>
/// Read a Decimal and increment the pointer to an array
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static decimal ReadDecimal(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 16);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 16);
int lo = BitConverter.ToInt32(buffer, 0);
int mid = BitConverter.ToInt32(buffer, 4);
@@ -399,7 +607,7 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static decimal ReadDecimalBigEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 16);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 16);
Array.Reverse(buffer);
int lo = BitConverter.ToInt32(buffer, 0);
@@ -413,9 +621,10 @@ namespace SabreTools.IO.Extensions
/// <summary>
/// Read a Guid and increment the pointer to an array
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static Guid ReadGuid(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 16);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 16);
return new Guid(buffer);
}
@@ -425,7 +634,7 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static Guid ReadGuidBigEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 16);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 16);
Array.Reverse(buffer);
return new Guid(buffer);
}
@@ -434,9 +643,10 @@ namespace SabreTools.IO.Extensions
/// <summary>
/// Read an Int128 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static Int128 ReadInt128(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 16);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 16);
return (Int128)new BigInteger(buffer);
}
@@ -446,7 +656,7 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static Int128 ReadInt128BigEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 16);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 16);
Array.Reverse(buffer);
return (Int128)new BigInteger(buffer);
}
@@ -454,9 +664,10 @@ namespace SabreTools.IO.Extensions
/// <summary>
/// Read a UInt128 and increment the pointer to an array
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static UInt128 ReadUInt128(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 16);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 16);
return (UInt128)new BigInteger(buffer);
}
@@ -466,7 +677,7 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static UInt128 ReadUInt128BigEndian(this byte[] content, ref int offset)
{
byte[] buffer = ReadToBuffer(content, ref offset, 16);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, 16);
Array.Reverse(buffer);
return (UInt128)new BigInteger(buffer);
}
@@ -640,7 +851,7 @@ namespace SabreTools.IO.Extensions
try
{
int typeSize = Marshal.SizeOf(type);
byte[] buffer = ReadToBuffer(content, ref offset, typeSize);
byte[] buffer = ReadExactlyToBuffer(content, ref offset, typeSize);
var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
var data = Marshal.PtrToStructure(handle.AddrOfPinnedObject(), type);
@@ -852,7 +1063,7 @@ namespace SabreTools.IO.Extensions
/// <summary>
/// Read a number of bytes from the byte array to a buffer
/// </summary>
private static byte[] ReadToBuffer(byte[] content, ref int offset, int length)
private static byte[] ReadExactlyToBuffer(byte[] content, ref int offset, int length)
{
// If we have an invalid length
if (length < 0)

View File

@@ -4,6 +4,32 @@ namespace SabreTools.IO.Extensions
{
public static class StreamExtensions
{
/// <summary>
/// Align the stream position to a byte-size boundary
/// </summary>
/// <param name="input">Input stream to try aligning</param>
/// <param name="alignment">Number of bytes to align on</param>
/// <returns>True if the stream could be aligned, false otherwise</returns>
public static bool AlignToBoundary(this Stream? input, byte alignment)
{
// If the stream is invalid
if (input == null || input.Length == 0 || !input.CanRead)
return false;
// If already at the end of the stream
if (input.Position >= input.Length)
return false;
// Align the stream position
while (input.Position % alignment != 0 && input.Position < input.Length)
{
_ = input.ReadByteValue();
}
// Return if the alignment completed
return input.Position % alignment == 0;
}
/// <summary>
/// Seek to a specific point in the stream, if possible
/// </summary>

View File

@@ -13,7 +13,6 @@ namespace SabreTools.IO.Extensions
/// <summary>
/// Extensions for Streams
/// </summary>
/// TODO: Handle proper negative values for Int24 and Int48
public static class StreamReaderExtensions
{
/// <summary>
@@ -21,7 +20,7 @@ namespace SabreTools.IO.Extensions
/// </summary>
public static byte ReadByteValue(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 1);
byte[] buffer = ReadExactlyToBuffer(stream, 1);
return buffer[0];
}
@@ -29,14 +28,14 @@ namespace SabreTools.IO.Extensions
/// Read a UInt8[] from the stream
/// </summary>
public static byte[] ReadBytes(this Stream stream, int count)
=> ReadToBuffer(stream, count);
=> ReadExactlyToBuffer(stream, count);
/// <summary>
/// Read an Int8 from the stream
/// </summary>
public static sbyte ReadSByte(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 1);
byte[] buffer = ReadExactlyToBuffer(stream, 1);
return (sbyte)buffer[0];
}
@@ -45,17 +44,20 @@ namespace SabreTools.IO.Extensions
/// </summary>
public static char ReadChar(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 1);
byte[] buffer = ReadExactlyToBuffer(stream, 1);
return (char)buffer[0];
}
/// <summary>
/// Read an Int16 from the stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static short ReadInt16(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 2);
return BitConverter.ToInt16(buffer, 0);
if (BitConverter.IsLittleEndian)
return stream.ReadInt16LittleEndian();
else
return stream.ReadInt16BigEndian();
}
/// <summary>
@@ -64,18 +66,32 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static short ReadInt16BigEndian(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 2);
Array.Reverse(buffer);
return BitConverter.ToInt16(buffer, 0);
byte[] buffer = ReadExactlyToBuffer(stream, 2);
return (short)(buffer[1]
| (buffer[0] << 8));
}
/// <summary>
/// Read an Int16 from the stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static short ReadInt16LittleEndian(this Stream stream)
{
byte[] buffer = ReadExactlyToBuffer(stream, 2);
return (short)(buffer[0]
| (buffer[1] << 8));
}
/// <summary>
/// Read a UInt16 from the stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static ushort ReadUInt16(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 2);
return BitConverter.ToUInt16(buffer, 0);
if (BitConverter.IsLittleEndian)
return stream.ReadUInt16LittleEndian();
else
return stream.ReadUInt16BigEndian();
}
/// <summary>
@@ -84,14 +100,26 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static ushort ReadUInt16BigEndian(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 2);
Array.Reverse(buffer);
return BitConverter.ToUInt16(buffer, 0);
byte[] buffer = ReadExactlyToBuffer(stream, 2);
return (ushort)(buffer[1]
| (buffer[0] << 8));
}
/// <summary>
/// Read a UInt16 from the stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static ushort ReadUInt16LittleEndian(this Stream stream)
{
byte[] buffer = ReadExactlyToBuffer(stream, 2);
return (ushort)(buffer[0]
| (buffer[1] << 8));
}
/// <summary>
/// Read a WORD (2-byte) from the stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static ushort ReadWORD(this Stream stream)
=> stream.ReadUInt16();
@@ -102,14 +130,22 @@ namespace SabreTools.IO.Extensions
public static ushort ReadWORDBigEndian(this Stream stream)
=> stream.ReadUInt16BigEndian();
/// <summary>
/// Read a WORD (2-byte) from the stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static ushort ReadWORDLittleEndian(this Stream stream)
=> stream.ReadUInt16LittleEndian();
// Half was introduced in net5.0 but doesn't have a BitConverter implementation until net6.0
#if NET6_0_OR_GREATER
/// <summary>
/// Read a Half from the stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static Half ReadHalf(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 2);
byte[] buffer = ReadExactlyToBuffer(stream, 2);
return BitConverter.ToHalf(buffer, 0);
}
@@ -119,71 +155,94 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static Half ReadHalfBigEndian(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 2);
byte[] buffer = ReadExactlyToBuffer(stream, 2);
Array.Reverse(buffer);
return BitConverter.ToHalf(buffer, 0);
}
#endif
/// <summary>
/// Read an Int24 encoded as an Int32
/// Read an Int24 encoded as an Int32 from the stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static int ReadInt24(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 3);
byte[] padded = new byte[4];
Array.Copy(buffer, padded, 3);
return BitConverter.ToInt32(padded, 0);
if (BitConverter.IsLittleEndian)
return stream.ReadInt24LittleEndian();
else
return stream.ReadInt24BigEndian();
}
/// <summary>
/// Read an Int24 encoded as an Int32
/// Read an Int24 encoded as an Int32 from the stream
/// </summary>
/// <remarks>Reads in big-endian format</remarks>
public static int ReadInt24BigEndian(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 3);
Array.Reverse(buffer);
byte[] padded = new byte[4];
Array.Copy(buffer, padded, 3);
return BitConverter.ToInt32(padded, 0);
byte[] buffer = ReadExactlyToBuffer(stream, 3);
return (int)(buffer[2]
| (buffer[1] << 8)
| (buffer[0] << 16));
}
/// <summary>
/// Read a UInt24 encoded as a UInt32
/// Read an Int24 encoded as an Int32 from the stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static int ReadInt24LittleEndian(this Stream stream)
{
byte[] buffer = ReadExactlyToBuffer(stream, 3);
return (int)(buffer[0]
| (buffer[1] << 8)
| (buffer[2] << 16));
}
/// <summary>
/// Read a UInt24 encoded as a UInt32 from the stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static uint ReadUInt24(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 3);
byte[] padded = new byte[4];
Array.Copy(buffer, padded, 3);
return BitConverter.ToUInt32(padded, 0);
if (BitConverter.IsLittleEndian)
return stream.ReadUInt24LittleEndian();
else
return stream.ReadUInt24BigEndian();
}
/// <summary>
/// Read a UInt24 encoded as a UInt32
/// Read a UInt24 encoded as a UInt32 from the stream
/// </summary>
/// <remarks>Reads in big-endian format</remarks>
public static uint ReadUInt24BigEndian(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 3);
Array.Reverse(buffer);
byte[] buffer = ReadExactlyToBuffer(stream, 3);
return (uint)(buffer[2]
| (buffer[1] << 8)
| (buffer[0] << 16));
}
byte[] padded = new byte[4];
Array.Copy(buffer, padded, 3);
return BitConverter.ToUInt32(padded, 0);
/// <summary>
/// Read a UInt24 encoded as a UInt32 from the stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static uint ReadUInt24LittleEndian(this Stream stream)
{
byte[] buffer = ReadExactlyToBuffer(stream, 3);
return (uint)(buffer[0]
| (buffer[1] << 8)
| (buffer[2] << 16));
}
/// <summary>
/// Read an Int32 from the stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static int ReadInt32(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 4);
return BitConverter.ToInt32(buffer, 0);
if (BitConverter.IsLittleEndian)
return stream.ReadInt32LittleEndian();
else
return stream.ReadInt32BigEndian();
}
/// <summary>
@@ -192,18 +251,36 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static int ReadInt32BigEndian(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 4);
Array.Reverse(buffer);
return BitConverter.ToInt32(buffer, 0);
byte[] buffer = ReadExactlyToBuffer(stream, 4);
return (int)(buffer[3]
| (buffer[2] << 8)
| (buffer[1] << 16)
| (buffer[0] << 24));
}
/// <summary>
/// Read an Int32 from the stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static int ReadInt32LittleEndian(this Stream stream)
{
byte[] buffer = ReadExactlyToBuffer(stream, 4);
return (int)(buffer[0]
| (buffer[1] << 8)
| (buffer[2] << 16)
| (buffer[3] << 24));
}
/// <summary>
/// Read a UInt32 from the stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static uint ReadUInt32(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 4);
return BitConverter.ToUInt32(buffer, 0);
if (BitConverter.IsLittleEndian)
return stream.ReadUInt32LittleEndian();
else
return stream.ReadUInt32BigEndian();
}
/// <summary>
@@ -212,14 +289,30 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static uint ReadUInt32BigEndian(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 4);
Array.Reverse(buffer);
return BitConverter.ToUInt32(buffer, 0);
byte[] buffer = ReadExactlyToBuffer(stream, 4);
return (uint)(buffer[3]
| (buffer[2] << 8)
| (buffer[1] << 16)
| (buffer[0] << 24));
}
/// <summary>
/// Read a UInt32 from the stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static uint ReadUInt32LittleEndian(this Stream stream)
{
byte[] buffer = ReadExactlyToBuffer(stream, 4);
return (uint)(buffer[0]
| (buffer[1] << 8)
| (buffer[2] << 16)
| (buffer[3] << 24));
}
/// <summary>
/// Read a DWORD (4-byte) from the stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static uint ReadDWORD(this Stream stream)
=> stream.ReadUInt32();
@@ -230,12 +323,20 @@ namespace SabreTools.IO.Extensions
public static uint ReadDWORDBigEndian(this Stream stream)
=> stream.ReadUInt32BigEndian();
/// <summary>
/// Read a DWORD (4-byte) from the stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static uint ReadDWORDLittleEndian(this Stream stream)
=> stream.ReadUInt32LittleEndian();
/// <summary>
/// Read a Single from the stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static float ReadSingle(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 4);
byte[] buffer = ReadExactlyToBuffer(stream, 4);
return BitConverter.ToSingle(buffer, 0);
}
@@ -245,70 +346,105 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static float ReadSingleBigEndian(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 4);
byte[] buffer = ReadExactlyToBuffer(stream, 4);
Array.Reverse(buffer);
return BitConverter.ToSingle(buffer, 0);
}
/// <summary>
/// Read an Int48 encoded as an Int64
/// Read an Int48 encoded as an Int64 from the stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static long ReadInt48(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 6);
byte[] padded = new byte[8];
Array.Copy(buffer, padded, 6);
return BitConverter.ToInt64(padded, 0);
if (BitConverter.IsLittleEndian)
return stream.ReadInt48LittleEndian();
else
return stream.ReadInt48BigEndian();
}
/// <summary>
/// Read an Int48 encoded as an Int64
/// Read an Int48 encoded as an Int64 from the stream
/// </summary>
/// <remarks>Reads in big-endian format</remarks>
public static long ReadInt48BigEndian(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 6);
Array.Reverse(buffer);
byte[] padded = new byte[8];
Array.Copy(buffer, padded, 6);
return BitConverter.ToInt64(padded, 0);
byte[] buffer = ReadExactlyToBuffer(stream, 6);
return ((long)buffer[5] << 0)
| ((long)buffer[4] << 8)
| ((long)buffer[3] << 16)
| ((long)buffer[2] << 24)
| ((long)buffer[1] << 32)
| ((long)buffer[0] << 40);
}
/// <summary>
/// Read a UInt48 encoded as a UInt64
/// Read an Int48 encoded as an Int64 from the stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static long ReadInt48LittleEndian(this Stream stream)
{
byte[] buffer = ReadExactlyToBuffer(stream, 6);
return ((long)buffer[0] << 0)
| ((long)buffer[1] << 8)
| ((long)buffer[2] << 16)
| ((long)buffer[3] << 24)
| ((long)buffer[4] << 32)
| ((long)buffer[5] << 40);
}
/// <summary>
/// Read a UInt48 encoded as a UInt64 from the stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static ulong ReadUInt48(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 6);
byte[] padded = new byte[8];
Array.Copy(buffer, padded, 6);
return BitConverter.ToUInt64(padded, 0);
if (BitConverter.IsLittleEndian)
return stream.ReadUInt48LittleEndian();
else
return stream.ReadUInt48BigEndian();
}
/// <summary>
/// Read a UInt48 encoded as a UInt64
/// Read a UInt48 encoded as a UInt64 from the stream
/// </summary>
/// <remarks>Reads in big-endian format</remarks>
public static ulong ReadUInt48BigEndian(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 6);
Array.Reverse(buffer);
byte[] buffer = ReadExactlyToBuffer(stream, 6);
return ((ulong)buffer[5] << 0)
| ((ulong)buffer[4] << 8)
| ((ulong)buffer[3] << 16)
| ((ulong)buffer[2] << 24)
| ((ulong)buffer[1] << 32)
| ((ulong)buffer[0] << 40);
}
byte[] padded = new byte[8];
Array.Copy(buffer, padded, 6);
return BitConverter.ToUInt64(padded, 0);
/// <summary>
/// Read an UInt48 encoded as an UInt64 from the stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static ulong ReadUInt48LittleEndian(this Stream stream)
{
byte[] buffer = ReadExactlyToBuffer(stream, 6);
return ((ulong)buffer[0] << 0)
| ((ulong)buffer[1] << 8)
| ((ulong)buffer[2] << 16)
| ((ulong)buffer[3] << 24)
| ((ulong)buffer[4] << 32)
| ((ulong)buffer[5] << 40);
}
/// <summary>
/// Read an Int64 from the stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static long ReadInt64(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 8);
return BitConverter.ToInt64(buffer, 0);
if (BitConverter.IsLittleEndian)
return stream.ReadInt64LittleEndian();
else
return stream.ReadInt64BigEndian();
}
/// <summary>
@@ -317,18 +453,44 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static long ReadInt64BigEndian(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 8);
Array.Reverse(buffer);
return BitConverter.ToInt64(buffer, 0);
byte[] buffer = ReadExactlyToBuffer(stream, 8);
return ((long)buffer[7] << 0)
| ((long)buffer[6] << 8)
| ((long)buffer[5] << 16)
| ((long)buffer[4] << 24)
| ((long)buffer[3] << 32)
| ((long)buffer[2] << 40)
| ((long)buffer[1] << 48)
| ((long)buffer[0] << 56);
}
/// <summary>
/// Read an Int64 from the stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static long ReadInt64LittleEndian(this Stream stream)
{
byte[] buffer = ReadExactlyToBuffer(stream, 8);
return ((long)buffer[0] << 0)
| ((long)buffer[1] << 8)
| ((long)buffer[2] << 16)
| ((long)buffer[3] << 24)
| ((long)buffer[4] << 32)
| ((long)buffer[5] << 40)
| ((long)buffer[6] << 48)
| ((long)buffer[7] << 56);
}
/// <summary>
/// Read a UInt64 from the stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static ulong ReadUInt64(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 8);
return BitConverter.ToUInt64(buffer, 0);
if (BitConverter.IsLittleEndian)
return stream.ReadUInt64LittleEndian();
else
return stream.ReadUInt64BigEndian();
}
/// <summary>
@@ -337,17 +499,62 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static ulong ReadUInt64BigEndian(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 8);
Array.Reverse(buffer);
return BitConverter.ToUInt64(buffer, 0);
byte[] buffer = ReadExactlyToBuffer(stream, 8);
return ((ulong)buffer[7] << 0)
| ((ulong)buffer[6] << 8)
| ((ulong)buffer[5] << 16)
| ((ulong)buffer[4] << 24)
| ((ulong)buffer[3] << 32)
| ((ulong)buffer[2] << 40)
| ((ulong)buffer[1] << 48)
| ((ulong)buffer[0] << 56);
}
/// <summary>
/// Read a UInt64 from the stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static ulong ReadUInt64LittleEndian(this Stream stream)
{
byte[] buffer = ReadExactlyToBuffer(stream, 8);
return ((ulong)buffer[0] << 0)
| ((ulong)buffer[1] << 8)
| ((ulong)buffer[2] << 16)
| ((ulong)buffer[3] << 24)
| ((ulong)buffer[4] << 32)
| ((ulong)buffer[5] << 40)
| ((ulong)buffer[6] << 48)
| ((ulong)buffer[7] << 56);
}
/// <summary>
/// Read a QWORD (8-byte) from the stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static ulong ReadQWORD(this Stream stream)
=> stream.ReadUInt64();
/// <summary>
/// Read a QWORD (8-byte) from the stream
/// </summary>
/// <remarks>Reads in big-endian format</remarks>
public static ulong ReadQWORDBigEndian(this Stream stream)
=> stream.ReadUInt64BigEndian();
/// <summary>
/// Read a QWORD (8-byte) from the stream
/// </summary>
/// <remarks>Reads in little-endian format</remarks>
public static ulong ReadQWORDLittleEndian(this Stream stream)
=> stream.ReadUInt64LittleEndian();
/// <summary>
/// Read a Double from the stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static double ReadDouble(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 8);
byte[] buffer = ReadExactlyToBuffer(stream, 8);
return BitConverter.ToDouble(buffer, 0);
}
@@ -357,7 +564,7 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static double ReadDoubleBigEndian(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 8);
byte[] buffer = ReadExactlyToBuffer(stream, 8);
Array.Reverse(buffer);
return BitConverter.ToDouble(buffer, 0);
}
@@ -365,9 +572,10 @@ namespace SabreTools.IO.Extensions
/// <summary>
/// Read a Decimal from the stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static decimal ReadDecimal(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 16);
byte[] buffer = ReadExactlyToBuffer(stream, 16);
int lo = BitConverter.ToInt32(buffer, 0);
int mid = BitConverter.ToInt32(buffer, 4);
@@ -383,7 +591,7 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static decimal ReadDecimalBigEndian(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 16);
byte[] buffer = ReadExactlyToBuffer(stream, 16);
Array.Reverse(buffer);
int lo = BitConverter.ToInt32(buffer, 0);
@@ -397,9 +605,10 @@ namespace SabreTools.IO.Extensions
/// <summary>
/// Read a Guid from the stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static Guid ReadGuid(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 16);
byte[] buffer = ReadExactlyToBuffer(stream, 16);
return new Guid(buffer);
}
@@ -409,7 +618,7 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static Guid ReadGuidBigEndian(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 16);
byte[] buffer = ReadExactlyToBuffer(stream, 16);
Array.Reverse(buffer);
return new Guid(buffer);
}
@@ -418,9 +627,10 @@ namespace SabreTools.IO.Extensions
/// <summary>
/// Read an Int128 from the stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static Int128 ReadInt128(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 16);
byte[] buffer = ReadExactlyToBuffer(stream, 16);
return (Int128)new BigInteger(buffer);
}
@@ -430,7 +640,7 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static Int128 ReadInt128BigEndian(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 16);
byte[] buffer = ReadExactlyToBuffer(stream, 16);
Array.Reverse(buffer);
return (Int128)new BigInteger(buffer);
}
@@ -438,9 +648,10 @@ namespace SabreTools.IO.Extensions
/// <summary>
/// Read a UInt128 from the stream
/// </summary>
/// <remarks>Reads in machine native format</remarks>
public static UInt128 ReadUInt128(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 16);
byte[] buffer = ReadExactlyToBuffer(stream, 16);
return (UInt128)new BigInteger(buffer);
}
@@ -450,7 +661,7 @@ namespace SabreTools.IO.Extensions
/// <remarks>Reads in big-endian format</remarks>
public static UInt128 ReadUInt128BigEndian(this Stream stream)
{
byte[] buffer = ReadToBuffer(stream, 16);
byte[] buffer = ReadExactlyToBuffer(stream, 16);
Array.Reverse(buffer);
return (UInt128)new BigInteger(buffer);
}
@@ -624,7 +835,7 @@ namespace SabreTools.IO.Extensions
try
{
int typeSize = Marshal.SizeOf(type);
byte[] buffer = ReadToBuffer(stream, typeSize);
byte[] buffer = ReadExactlyToBuffer(stream, typeSize);
var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
var data = Marshal.PtrToStructure(handle.AddrOfPinnedObject(), type);
@@ -836,7 +1047,7 @@ namespace SabreTools.IO.Extensions
/// <summary>
/// Read a number of bytes from the stream to a buffer
/// </summary>
private static byte[] ReadToBuffer(Stream stream, int length)
private static byte[] ReadExactlyToBuffer(Stream stream, int length)
{
// If we have an invalid length
if (length < 0)

View File

@@ -3,11 +3,13 @@
<PropertyGroup>
<!-- Assembly Properties -->
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0</TargetFrameworks>
<IncludeSymbols>true</IncludeSymbols>
<LangVersion>latest</LangVersion>
<NoWarn>CS0618</NoWarn>
<Nullable>enable</Nullable>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>1.6.0</Version>
<Version>1.6.2</Version>
<!-- Package Properties -->
<Authors>Matt Nadareski</Authors>
@@ -26,7 +28,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.Matching" Version="1.5.0" />
<PackageReference Include="SabreTools.Matching" Version="1.5.1" />
</ItemGroup>
</Project>