mirror of
https://github.com/SabreTools/SabreTools.IO.git
synced 2026-02-10 13:54:50 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec9db7e732 | ||
|
|
3c7401fefc | ||
|
|
09e66c9ec3 | ||
|
|
8d1bc3957c | ||
|
|
245ca9010a | ||
|
|
88207100f1 | ||
|
|
3befd9255a | ||
|
|
37f2848bb2 | ||
|
|
c5dca60d28 | ||
|
|
351e46534d | ||
|
|
d39324c887 | ||
|
|
163f49281d | ||
|
|
03d0f7dd18 | ||
|
|
fbbe77f5f2 | ||
|
|
4bffd9d31c | ||
|
|
904aed1c44 | ||
|
|
69a41b2487 | ||
|
|
f326c921e6 | ||
|
|
73c4e8dd50 | ||
|
|
e4c8bbc3f9 |
@@ -1,19 +1,73 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
#if NET7_0_OR_GREATER
|
||||
using System.Numerics;
|
||||
#endif
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
// TODO: Add string reading tests
|
||||
public class BinaryReaderExtensionsTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Test pattern from 0x00-0x0F
|
||||
/// </summary>
|
||||
private static readonly byte[] _bytes =
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Represents the decimal value 0.0123456789
|
||||
/// </summary>
|
||||
private static readonly byte[] _decimalBytes =
|
||||
[
|
||||
0x15, 0xCD, 0x5B, 0x07, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00,
|
||||
];
|
||||
|
||||
[Fact]
|
||||
public void ReadByteTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var br = new BinaryReader(stream);
|
||||
byte read = br.ReadByte();
|
||||
Assert.Equal(0x00, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadBytesTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var br = new BinaryReader(stream);
|
||||
int length = 4;
|
||||
byte[] read = br.ReadBytes(length);
|
||||
Assert.Equal(length, read.Length);
|
||||
Assert.True(read.SequenceEqual(_bytes.Take(length)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadSByteTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var br = new BinaryReader(stream);
|
||||
sbyte read = br.ReadSByte();
|
||||
Assert.Equal(0x00, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadCharTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var br = new BinaryReader(stream);
|
||||
char read = br.ReadChar();
|
||||
Assert.Equal('\0', read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt16Test()
|
||||
{
|
||||
@@ -50,6 +104,64 @@ namespace SabreTools.IO.Test.Extensions
|
||||
Assert.Equal(0x0001, read);
|
||||
}
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
[Fact]
|
||||
public void ReadHalfTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var br = new BinaryReader(stream);
|
||||
Half expected = BitConverter.Int16BitsToHalf(0x0100);
|
||||
Half read = br.ReadHalf();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadHalfBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var br = new BinaryReader(stream);
|
||||
Half expected = BitConverter.Int16BitsToHalf(0x0001);
|
||||
Half read = br.ReadHalfBigEndian();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void ReadInt24Test()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var br = new BinaryReader(stream);
|
||||
int read = br.ReadInt24();
|
||||
Assert.Equal(0x020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt24BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var br = new BinaryReader(stream);
|
||||
int read = br.ReadInt24BigEndian();
|
||||
Assert.Equal(0x000102, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt24Test()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var br = new BinaryReader(stream);
|
||||
uint read = br.ReadUInt24();
|
||||
Assert.Equal((uint)0x020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt24BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var br = new BinaryReader(stream);
|
||||
uint read = br.ReadUInt24BigEndian();
|
||||
Assert.Equal((uint)0x000102, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt32Test()
|
||||
{
|
||||
@@ -106,6 +218,42 @@ namespace SabreTools.IO.Test.Extensions
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt48Test()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var br = new BinaryReader(stream);
|
||||
long read = br.ReadInt48();
|
||||
Assert.Equal(0x050403020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt48BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var br = new BinaryReader(stream);
|
||||
long read = br.ReadInt48BigEndian();
|
||||
Assert.Equal(0x000102030405, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt48Test()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var br = new BinaryReader(stream);
|
||||
ulong read = br.ReadUInt48();
|
||||
Assert.Equal((ulong)0x050403020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt48BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var br = new BinaryReader(stream);
|
||||
ulong read = br.ReadUInt48BigEndian();
|
||||
Assert.Equal((ulong)0x000102030405, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt64Test()
|
||||
{
|
||||
@@ -162,6 +310,26 @@ namespace SabreTools.IO.Test.Extensions
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadDecimalTest()
|
||||
{
|
||||
var stream = new MemoryStream(_decimalBytes);
|
||||
var br = new BinaryReader(stream);
|
||||
decimal expected = 0.0123456789M;
|
||||
decimal read = br.ReadDecimal();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadDecimalBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_decimalBytes.Reverse().ToArray());
|
||||
var br = new BinaryReader(stream);
|
||||
decimal expected = 0.0123456789M;
|
||||
decimal read = br.ReadDecimalBigEndian();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadGuidTest()
|
||||
{
|
||||
@@ -188,7 +356,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var br = new BinaryReader(stream);
|
||||
var expected = new Int128(BitConverter.ToUInt64(_bytes, 0), BitConverter.ToUInt64(_bytes, 8));
|
||||
var expected = (Int128)new BigInteger(_bytes);
|
||||
Int128 read = br.ReadInt128();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
@@ -199,7 +367,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var br = new BinaryReader(stream);
|
||||
var reversed = _bytes.Reverse().ToArray();
|
||||
var expected = new Int128(BitConverter.ToUInt64(reversed, 0), BitConverter.ToUInt64(reversed, 8));
|
||||
var expected = (Int128)new BigInteger(reversed);
|
||||
Int128 read = br.ReadInt128BigEndian();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
@@ -209,7 +377,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var br = new BinaryReader(stream);
|
||||
var expected = new UInt128(BitConverter.ToUInt64(_bytes, 0), BitConverter.ToUInt64(_bytes, 8));
|
||||
var expected = (UInt128)new BigInteger(_bytes);
|
||||
UInt128 read = br.ReadUInt128();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
@@ -220,7 +388,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var br = new BinaryReader(stream);
|
||||
var reversed = _bytes.Reverse().ToArray();
|
||||
var expected = new UInt128(BitConverter.ToUInt64(reversed, 0), BitConverter.ToUInt64(reversed, 8));
|
||||
var expected = (UInt128)new BigInteger(reversed);
|
||||
UInt128 read = br.ReadUInt128BigEndian();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
@@ -263,9 +431,5 @@ namespace SabreTools.IO.Test.Extensions
|
||||
Assert.Equal(expected.ThirdValue, read.ThirdValue);
|
||||
Assert.Equal(expected.FourthValue, read.FourthValue);
|
||||
}
|
||||
|
||||
// TODO: Add byte[], char[] tests
|
||||
// TODO: Add decimal tests
|
||||
// TODO: Add string reading tests
|
||||
}
|
||||
}
|
||||
494
SabreTools.IO.Test/Extensions/BinaryWriterExtensionsTests.cs
Normal file
494
SabreTools.IO.Test/Extensions/BinaryWriterExtensionsTests.cs
Normal file
@@ -0,0 +1,494 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
#if NET7_0_OR_GREATER
|
||||
using System.Numerics;
|
||||
#endif
|
||||
using System.Text;
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
// TODO: Add byte[], char[] tests
|
||||
// TODO: Add string writing tests
|
||||
public class BinaryWriterExtensionsTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Test pattern from 0x00-0x0F
|
||||
/// </summary>
|
||||
private static readonly byte[] _bytes =
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Represents the decimal value 0.0123456789
|
||||
/// </summary>
|
||||
private static readonly byte[] _decimalBytes =
|
||||
[
|
||||
0x15, 0xCD, 0x5B, 0x07, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00,
|
||||
];
|
||||
|
||||
[Fact]
|
||||
public void WriteByteValueTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(1).ToArray();
|
||||
bw.Write((byte)0x00);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteBytesTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
bw.Write([0x00, 0x01, 0x02, 0x03]);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteSByteTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(1).ToArray();
|
||||
bw.Write((sbyte)0x00);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteCharTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(1).ToArray();
|
||||
bw.Write('\0');
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteCharEncodingTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [0x00, 0x00];
|
||||
bw.Write('\0', Encoding.Unicode);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt16Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
bw.Write((short)0x0100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt16BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
bool write = bw.WriteBigEndian((short)0x0001);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt16Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
bw.Write((ushort)0x0100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt16BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
bool write = bw.WriteBigEndian((ushort)0x0001);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
[Fact]
|
||||
public void WriteHalfTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
bw.Write(BitConverter.Int16BitsToHalf(0x0100));
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteHalfBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
bool write = bw.WriteBigEndian(BitConverter.Int16BitsToHalf(0x0001));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void WriteInt24Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(3).ToArray();
|
||||
bw.WriteAsInt24(0x020100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt24BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(3).ToArray();
|
||||
bool write = bw.WriteAsInt24BigEndian(0x000102);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt24Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(3).ToArray();
|
||||
bw.WriteAsUInt24(0x020100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt24BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(3).ToArray();
|
||||
bool write = bw.WriteAsUInt24BigEndian(0x000102);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt32Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
bw.Write(0x03020100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt32BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
bool write = bw.WriteBigEndian(0x00010203);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt32Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
bw.Write((uint)0x03020100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt32BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
bool write = bw.WriteBigEndian((uint)0x00010203);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteSingleTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
bw.Write(BitConverter.Int32BitsToSingle(0x03020100));
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteSingleBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
bool write = bw.WriteBigEndian(BitConverter.Int32BitsToSingle(0x00010203));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt48Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(6).ToArray();
|
||||
bw.WriteAsInt48(0x050403020100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt48BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(6).ToArray();
|
||||
bool write = bw.WriteAsInt48BigEndian(0x000102030405);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt48Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(6).ToArray();
|
||||
bw.WriteAsUInt48(0x050403020100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt48BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(6).ToArray();
|
||||
bool write = bw.WriteAsUInt48BigEndian(0x000102030405);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt64Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
bw.Write(0x0706050403020100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt64BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
bool write = bw.WriteBigEndian(0x0001020304050607);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt64Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
bw.Write((ulong)0x0706050403020100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt64BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
bool write = bw.WriteBigEndian((ulong)0x0001020304050607);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteDoubleTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
bw.Write(BitConverter.Int64BitsToDouble(0x0706050403020100));
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteDoubleBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
bool write = bw.WriteBigEndian(BitConverter.Int64BitsToDouble(0x0001020304050607));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteDecimalTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _decimalBytes.Take(16).ToArray();
|
||||
bw.Write(0.0123456789M);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteDecimalBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _decimalBytes.Take(16).Reverse().ToArray();
|
||||
bool write = bw.WriteBigEndian(0.0123456789M);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteGuidTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = bw.Write(new Guid(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteGuidBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = bw.WriteBigEndian(new Guid(_bytes.Reverse().ToArray()));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
[Fact]
|
||||
public void WriteInt128Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = bw.Write((Int128)new BigInteger(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt128BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = bw.WriteBigEndian((Int128)new BigInteger(_bytes.Reverse().ToArray()));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt128Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = bw.Write((UInt128)new BigInteger(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt128BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = bw.WriteBigEndian((UInt128)new BigInteger(_bytes.Reverse().ToArray()));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void WriteTypeExplicitTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
var obj = new TestStructExplicit
|
||||
{
|
||||
FirstValue = 0x03020100,
|
||||
SecondValue = 0x07060504,
|
||||
};
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
bool write = bw.WriteType(obj);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteTypeSequentialTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
var obj = new TestStructSequential
|
||||
{
|
||||
FirstValue = 0x03020100,
|
||||
SecondValue = 0x07060504,
|
||||
ThirdValue = 0x0908,
|
||||
FourthValue = 0x0B0A,
|
||||
};
|
||||
byte[] expected = _bytes.Take(12).ToArray();
|
||||
bool write = bw.WriteType(obj);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate that a set of actual bytes matches the expected bytes
|
||||
/// </summary>
|
||||
private static void ValidateBytes(byte[] expected, byte[] actual)
|
||||
{
|
||||
for (int i = 0; i < expected.Length; i++)
|
||||
{
|
||||
Assert.Equal(expected[i], actual[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,34 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
#if NET7_0_OR_GREATER
|
||||
using System.Numerics;
|
||||
#endif
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
public class ByteArrayExtensionsTests
|
||||
// TODO: Add string reading tests
|
||||
public class ByteArrayExtensionsReadTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Test pattern from 0x00-0x0F
|
||||
/// </summary>
|
||||
private static readonly byte[] _bytes =
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Represents the decimal value 0.0123456789
|
||||
/// </summary>
|
||||
private static readonly byte[] _decimalBytes =
|
||||
[
|
||||
0x15, 0xCD, 0x5B, 0x07, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00,
|
||||
];
|
||||
|
||||
[Fact]
|
||||
public void ReadByteTest()
|
||||
{
|
||||
@@ -86,6 +102,58 @@ namespace SabreTools.IO.Test.Extensions
|
||||
Assert.Equal(0x0001, read);
|
||||
}
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
[Fact]
|
||||
public void ReadHalfTest()
|
||||
{
|
||||
int offset = 0;
|
||||
Half expected = BitConverter.Int16BitsToHalf(0x0100);
|
||||
Half read = _bytes.ReadHalf(ref offset);
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadHalfBigEndianTest()
|
||||
{
|
||||
int offset = 0;
|
||||
Half expected = BitConverter.Int16BitsToHalf(0x0001);
|
||||
Half read = _bytes.ReadHalfBigEndian(ref offset);
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void ReadInt24Test()
|
||||
{
|
||||
int offset = 0;
|
||||
int read = _bytes.ReadInt24(ref offset);
|
||||
Assert.Equal(0x020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt24BigEndianTest()
|
||||
{
|
||||
int offset = 0;
|
||||
int read = _bytes.ReadInt24BigEndian(ref offset);
|
||||
Assert.Equal(0x000102, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt24Test()
|
||||
{
|
||||
int offset = 0;
|
||||
uint read = _bytes.ReadUInt24(ref offset);
|
||||
Assert.Equal((uint)0x020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt24BigEndianTest()
|
||||
{
|
||||
int offset = 0;
|
||||
uint read = _bytes.ReadUInt24BigEndian(ref offset);
|
||||
Assert.Equal((uint)0x000102, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt32Test()
|
||||
{
|
||||
@@ -136,6 +204,38 @@ namespace SabreTools.IO.Test.Extensions
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt48Test()
|
||||
{
|
||||
int offset = 0;
|
||||
long read = _bytes.ReadInt48(ref offset);
|
||||
Assert.Equal(0x050403020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt48BigEndianTest()
|
||||
{
|
||||
int offset = 0;
|
||||
long read = _bytes.ReadInt48BigEndian(ref offset);
|
||||
Assert.Equal(0x000102030405, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt48Test()
|
||||
{
|
||||
int offset = 0;
|
||||
ulong read = _bytes.ReadUInt48(ref offset);
|
||||
Assert.Equal((ulong)0x050403020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt48BigEndianTest()
|
||||
{
|
||||
int offset = 0;
|
||||
ulong read = _bytes.ReadUInt48BigEndian(ref offset);
|
||||
Assert.Equal((ulong)0x000102030405, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt64Test()
|
||||
{
|
||||
@@ -186,6 +286,24 @@ namespace SabreTools.IO.Test.Extensions
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadDecimalTest()
|
||||
{
|
||||
int offset = 0;
|
||||
decimal expected = 0.0123456789M;
|
||||
decimal read = _decimalBytes.ReadDecimal(ref offset);
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadDecimalBigEndianTest()
|
||||
{
|
||||
int offset = 0;
|
||||
decimal expected = 0.0123456789M;
|
||||
decimal read = _decimalBytes.Reverse().ToArray().ReadDecimalBigEndian(ref offset);
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadGuidTest()
|
||||
{
|
||||
@@ -209,7 +327,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void ReadInt128Test()
|
||||
{
|
||||
int offset = 0;
|
||||
var expected = new Int128(BitConverter.ToUInt64(_bytes, 0), BitConverter.ToUInt64(_bytes, 8));
|
||||
var expected = (Int128)new BigInteger(_bytes);
|
||||
Int128 read = _bytes.ReadInt128(ref offset);
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
@@ -219,7 +337,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
int offset = 0;
|
||||
var reversed = _bytes.Reverse().ToArray();
|
||||
var expected = new Int128(BitConverter.ToUInt64(reversed, 0), BitConverter.ToUInt64(reversed, 8));
|
||||
var expected = (Int128)new BigInteger(reversed);
|
||||
Int128 read = _bytes.ReadInt128BigEndian(ref offset);
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
@@ -228,7 +346,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void ReadUInt128Test()
|
||||
{
|
||||
int offset = 0;
|
||||
var expected = new UInt128(BitConverter.ToUInt64(_bytes, 0), BitConverter.ToUInt64(_bytes, 8));
|
||||
var expected = (UInt128)new BigInteger(_bytes);
|
||||
UInt128 read = _bytes.ReadUInt128(ref offset);
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
@@ -238,7 +356,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
int offset = 0;
|
||||
var reversed = _bytes.Reverse().ToArray();
|
||||
var expected = new UInt128(BitConverter.ToUInt64(reversed, 0), BitConverter.ToUInt64(reversed, 8));
|
||||
var expected = (UInt128)new BigInteger(reversed);
|
||||
UInt128 read = _bytes.ReadUInt128BigEndian(ref offset);
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
@@ -279,8 +397,5 @@ namespace SabreTools.IO.Test.Extensions
|
||||
Assert.Equal(expected.ThirdValue, read.ThirdValue);
|
||||
Assert.Equal(expected.FourthValue, read.FourthValue);
|
||||
}
|
||||
|
||||
// TODO: Add decimal tests
|
||||
// TODO: Add string reading tests
|
||||
}
|
||||
}
|
||||
477
SabreTools.IO.Test/Extensions/ByteArrayExtensionsWriteTests.cs
Normal file
477
SabreTools.IO.Test/Extensions/ByteArrayExtensionsWriteTests.cs
Normal file
@@ -0,0 +1,477 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
#if NET7_0_OR_GREATER
|
||||
using System.Numerics;
|
||||
#endif
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
// TODO: Add string writing tests
|
||||
public class ByteArrayExtensionsWriteTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Test pattern from 0x00-0x0F
|
||||
/// </summary>
|
||||
private static readonly byte[] _bytes =
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Represents the decimal value 0.0123456789
|
||||
/// </summary>
|
||||
private static readonly byte[] _decimalBytes =
|
||||
[
|
||||
0x15, 0xCD, 0x5B, 0x07, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00,
|
||||
];
|
||||
|
||||
[Fact]
|
||||
public void WriteByteTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(1).ToArray();
|
||||
bool write = buffer.Write(ref offset, (byte)0x00);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteBytesTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
bool write = buffer.Write(ref offset, [0x00, 0x01, 0x02, 0x03]);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteSByteTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(1).ToArray();
|
||||
bool write = buffer.Write(ref offset, (sbyte)0x00);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteCharTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(1).ToArray();
|
||||
bool write = buffer.Write(ref offset, '\0');
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt16Test()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
bool write = buffer.Write(ref offset, (short)0x0100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt16BigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
bool write = buffer.WriteBigEndian(ref offset, (short)0x0001);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt16Test()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
bool write = buffer.Write(ref offset, (ushort)0x0100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt16BigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
bool write = buffer.WriteBigEndian(ref offset, (ushort)0x0001);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
[Fact]
|
||||
public void WriteHalfTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
bool write = buffer.Write(ref offset, BitConverter.Int16BitsToHalf(0x0100));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteHalfBigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
bool write = buffer.WriteBigEndian(ref offset, BitConverter.Int16BitsToHalf(0x0001));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void WriteInt24Test()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(3).ToArray();
|
||||
bool write = buffer.WriteAsInt24(ref offset, 0x020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt24BigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(3).ToArray();
|
||||
bool write = buffer.WriteAsInt24BigEndian(ref offset, 0x000102);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt24Test()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(3).ToArray();
|
||||
bool write = buffer.WriteAsUInt24(ref offset, 0x020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt24BigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(3).ToArray();
|
||||
bool write = buffer.WriteAsUInt24BigEndian(ref offset, 0x000102);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt32Test()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
bool write = buffer.Write(ref offset, 0x03020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt32BigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
bool write = buffer.WriteBigEndian(ref offset, 0x00010203);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt32Test()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
bool write = buffer.Write(ref offset, (uint)0x03020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt32BigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
bool write = buffer.WriteBigEndian(ref offset, (uint)0x00010203);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteSingleTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
bool write = buffer.Write(ref offset, BitConverter.Int32BitsToSingle(0x03020100));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteSingleBigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
bool write = buffer.WriteBigEndian(ref offset, BitConverter.Int32BitsToSingle(0x00010203));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt48Test()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(6).ToArray();
|
||||
bool write = buffer.WriteAsInt48(ref offset, 0x050403020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt48BigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(6).ToArray();
|
||||
bool write = buffer.WriteAsInt48BigEndian(ref offset, 0x000102030405);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt48Test()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(6).ToArray();
|
||||
bool write = buffer.WriteAsUInt48(ref offset, 0x050403020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt48BigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(6).ToArray();
|
||||
bool write = buffer.WriteAsUInt48BigEndian(ref offset, 0x000102030405);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt64Test()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
bool write = buffer.Write(ref offset, 0x0706050403020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt64BigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
bool write = buffer.WriteBigEndian(ref offset, 0x0001020304050607);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt64Test()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
bool write = buffer.Write(ref offset, (ulong)0x0706050403020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt64BigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
bool write = buffer.WriteBigEndian(ref offset, (ulong)0x0001020304050607);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteDecimalTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _decimalBytes.Take(16).ToArray();
|
||||
bool write = buffer.Write(ref offset, 0.0123456789M);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteDecimalBigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _decimalBytes.Take(16).Reverse().ToArray();
|
||||
bool write = buffer.WriteBigEndian(ref offset, 0.0123456789M);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteGuidTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = buffer.Write(ref offset, new Guid(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteGuidBigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = buffer.WriteBigEndian(ref offset, new Guid(_bytes.Reverse().ToArray()));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
[Fact]
|
||||
public void WriteInt128Test()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = buffer.Write(ref offset, (Int128)new BigInteger(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt128BigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = buffer.WriteBigEndian(ref offset, (Int128)new BigInteger(_bytes.Reverse().ToArray()));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt128Test()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = buffer.Write(ref offset, (UInt128)new BigInteger(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt128BigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = buffer.WriteBigEndian(ref offset, (UInt128)new BigInteger(_bytes.Reverse().ToArray()));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void WriteTypeExplicitTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
var obj = new TestStructExplicit
|
||||
{
|
||||
FirstValue = 0x03020100,
|
||||
SecondValue = 0x07060504,
|
||||
};
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
bool write = buffer.WriteType(ref offset, obj);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteTypeSequentialTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
var obj = new TestStructSequential
|
||||
{
|
||||
FirstValue = 0x03020100,
|
||||
SecondValue = 0x07060504,
|
||||
ThirdValue = 0x0908,
|
||||
FourthValue = 0x0B0A,
|
||||
};
|
||||
byte[] expected = _bytes.Take(12).ToArray();
|
||||
bool write = buffer.WriteType(ref offset, obj);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate that a set of actual bytes matches the expected bytes
|
||||
/// </summary>
|
||||
private static void ValidateBytes(byte[] expected, byte[] actual)
|
||||
{
|
||||
for (int i = 0; i < expected.Length; i++)
|
||||
{
|
||||
Assert.Equal(expected[i], actual[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,35 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
#if NET7_0_OR_GREATER
|
||||
using System.Numerics;
|
||||
#endif
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
public class StreamExtensionsTests
|
||||
// TODO: Add string reading tests
|
||||
public class StreamExtensionsReadTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Test pattern from 0x00-0x0F
|
||||
/// </summary>
|
||||
private static readonly byte[] _bytes =
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Represents the decimal value 0.0123456789
|
||||
/// </summary>
|
||||
private static readonly byte[] _decimalBytes =
|
||||
[
|
||||
0x15, 0xCD, 0x5B, 0x07, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00,
|
||||
];
|
||||
|
||||
[Fact]
|
||||
public void ReadByteValueTest()
|
||||
{
|
||||
@@ -80,6 +96,58 @@ namespace SabreTools.IO.Test.Extensions
|
||||
Assert.Equal(0x0001, read);
|
||||
}
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
[Fact]
|
||||
public void ReadHalfTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
Half expected = BitConverter.Int16BitsToHalf(0x0100);
|
||||
Half read = stream.ReadHalf();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadHalfBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
Half expected = BitConverter.Int16BitsToHalf(0x0001);
|
||||
Half read = stream.ReadHalfBigEndian();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void ReadInt24Test()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
int read = stream.ReadInt24();
|
||||
Assert.Equal(0x020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt24BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
int read = stream.ReadInt24BigEndian();
|
||||
Assert.Equal(0x000102, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt24Test()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
uint read = stream.ReadUInt24();
|
||||
Assert.Equal((uint)0x020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt24BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
uint read = stream.ReadUInt24BigEndian();
|
||||
Assert.Equal((uint)0x000102, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt32Test()
|
||||
{
|
||||
@@ -130,6 +198,38 @@ namespace SabreTools.IO.Test.Extensions
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt48Test()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
long read = stream.ReadInt48();
|
||||
Assert.Equal(0x050403020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt48BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
long read = stream.ReadInt48BigEndian();
|
||||
Assert.Equal(0x000102030405, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt48Test()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
ulong read = stream.ReadUInt48();
|
||||
Assert.Equal((ulong)0x050403020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt48BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
ulong read = stream.ReadUInt48BigEndian();
|
||||
Assert.Equal((ulong)0x000102030405, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt64Test()
|
||||
{
|
||||
@@ -180,6 +280,24 @@ namespace SabreTools.IO.Test.Extensions
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadDecimalTest()
|
||||
{
|
||||
var stream = new MemoryStream(_decimalBytes);
|
||||
decimal expected = 0.0123456789M;
|
||||
decimal read = stream.ReadDecimal();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadDecimalBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_decimalBytes.Reverse().ToArray());
|
||||
decimal expected = 0.0123456789M;
|
||||
decimal read = stream.ReadDecimalBigEndian();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadGuidTest()
|
||||
{
|
||||
@@ -203,7 +321,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void ReadInt128Test()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var expected = new Int128(BitConverter.ToUInt64(_bytes, 0), BitConverter.ToUInt64(_bytes, 8));
|
||||
var expected = (Int128)new BigInteger(_bytes);
|
||||
Int128 read = stream.ReadInt128();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
@@ -213,7 +331,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var reversed = _bytes.Reverse().ToArray();
|
||||
var expected = new Int128(BitConverter.ToUInt64(reversed, 0), BitConverter.ToUInt64(reversed, 8));
|
||||
var expected = (Int128)new BigInteger(reversed);
|
||||
Int128 read = stream.ReadInt128BigEndian();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
@@ -222,7 +340,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void ReadUInt128Test()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var expected = new UInt128(BitConverter.ToUInt64(_bytes, 0), BitConverter.ToUInt64(_bytes, 8));
|
||||
var expected = (UInt128)new BigInteger(_bytes);
|
||||
UInt128 read = stream.ReadUInt128();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
@@ -232,7 +350,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var reversed = _bytes.Reverse().ToArray();
|
||||
var expected = new UInt128(BitConverter.ToUInt64(reversed, 0), BitConverter.ToUInt64(reversed, 8));
|
||||
var expected = (UInt128)new BigInteger(reversed);
|
||||
UInt128 read = stream.ReadUInt128BigEndian();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
@@ -273,8 +391,5 @@ namespace SabreTools.IO.Test.Extensions
|
||||
Assert.Equal(expected.ThirdValue, read.ThirdValue);
|
||||
Assert.Equal(expected.FourthValue, read.FourthValue);
|
||||
}
|
||||
|
||||
// TODO: Add decimal tests
|
||||
// TODO: Add string reading tests
|
||||
}
|
||||
}
|
||||
440
SabreTools.IO.Test/Extensions/StreamExtensionsWriteTests.cs
Normal file
440
SabreTools.IO.Test/Extensions/StreamExtensionsWriteTests.cs
Normal file
@@ -0,0 +1,440 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
#if NET7_0_OR_GREATER
|
||||
using System.Numerics;
|
||||
#endif
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
// TODO: Add string writing tests
|
||||
public class StreamExtensionsWriteTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Test pattern from 0x00-0x0F
|
||||
/// </summary>
|
||||
private static readonly byte[] _bytes =
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Represents the decimal value 0.0123456789
|
||||
/// </summary>
|
||||
private static readonly byte[] _decimalBytes =
|
||||
[
|
||||
0x15, 0xCD, 0x5B, 0x07, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00,
|
||||
];
|
||||
|
||||
[Fact]
|
||||
public void WriteByteValueTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(1).ToArray();
|
||||
bool write = stream.Write((byte)0x00);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteBytesTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
bool write = StreamWriterExtensions.Write(stream, [0x00, 0x01, 0x02, 0x03]);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteSByteTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(1).ToArray();
|
||||
bool write = stream.Write((sbyte)0x00);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteCharTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(1).ToArray();
|
||||
bool write = stream.Write('\0');
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt16Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
bool write = stream.Write((short)0x0100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt16BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
bool write = stream.WriteBigEndian((short)0x0001);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt16Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
bool write = stream.Write((ushort)0x0100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt16BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
bool write = stream.WriteBigEndian((ushort)0x0001);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
[Fact]
|
||||
public void WriteHalfTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
bool write = stream.Write(BitConverter.Int16BitsToHalf(0x0100));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteHalfBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
bool write = stream.WriteBigEndian(BitConverter.Int16BitsToHalf(0x0001));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void WriteInt24Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(3).ToArray();
|
||||
bool write = stream.WriteAsInt24(0x020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt24BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(3).ToArray();
|
||||
bool write = stream.WriteAsInt24BigEndian(0x000102);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt24Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(3).ToArray();
|
||||
bool write = stream.WriteAsUInt24(0x020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt24BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(3).ToArray();
|
||||
bool write = stream.WriteAsUInt24BigEndian(0x000102);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt32Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
bool write = stream.Write(0x03020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt32BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
bool write = stream.WriteBigEndian(0x00010203);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt32Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
bool write = stream.Write((uint)0x03020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt32BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
bool write = stream.WriteBigEndian((uint)0x00010203);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteSingleTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
bool write = stream.Write(BitConverter.Int32BitsToSingle(0x03020100));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteSingleBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
bool write = stream.WriteBigEndian(BitConverter.Int32BitsToSingle(0x00010203));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt48Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(6).ToArray();
|
||||
bool write = stream.WriteAsInt48(0x050403020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt48BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(6).ToArray();
|
||||
bool write = stream.WriteAsInt48BigEndian(0x000102030405);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt48Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(6).ToArray();
|
||||
bool write = stream.WriteAsUInt48(0x050403020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt48BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(6).ToArray();
|
||||
bool write = stream.WriteAsUInt48BigEndian(0x000102030405);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt64Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
bool write = stream.Write(0x0706050403020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt64BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
bool write = stream.WriteBigEndian(0x0001020304050607);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt64Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
bool write = stream.Write((ulong)0x0706050403020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt64BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
bool write = stream.WriteBigEndian((ulong)0x0001020304050607);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteDecimalTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _decimalBytes.Take(16).ToArray();
|
||||
bool write = stream.Write(0.0123456789M);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteDecimalBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _decimalBytes.Take(16).Reverse().ToArray();
|
||||
bool write = stream.WriteBigEndian(0.0123456789M);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteGuidTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = stream.Write(new Guid(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteGuidBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = stream.WriteBigEndian(new Guid(_bytes.Reverse().ToArray()));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
[Fact]
|
||||
public void WriteInt128Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = stream.Write((Int128)new BigInteger(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt128BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = stream.WriteBigEndian((Int128)new BigInteger(_bytes.Reverse().ToArray()));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt128Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = stream.Write((UInt128)new BigInteger(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt128BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = stream.WriteBigEndian((UInt128)new BigInteger(_bytes.Reverse().ToArray()));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void WriteTypeExplicitTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var obj = new TestStructExplicit
|
||||
{
|
||||
FirstValue = 0x03020100,
|
||||
SecondValue = 0x07060504,
|
||||
};
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
bool write = stream.WriteType(obj);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteTypeSequentialTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var obj = new TestStructSequential
|
||||
{
|
||||
FirstValue = 0x03020100,
|
||||
SecondValue = 0x07060504,
|
||||
ThirdValue = 0x0908,
|
||||
FourthValue = 0x0B0A,
|
||||
};
|
||||
byte[] expected = _bytes.Take(12).ToArray();
|
||||
bool write = stream.WriteType(obj);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate that a set of actual bytes matches the expected bytes
|
||||
/// </summary>
|
||||
private static void ValidateBytes(byte[] expected, byte[] actual)
|
||||
{
|
||||
for (int i = 0; i < expected.Length; i++)
|
||||
{
|
||||
Assert.Equal(expected[i], actual[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ namespace SabreTools.IO.Test.Streams
|
||||
Assert.Equal(0, stream.Length);
|
||||
Assert.Equal(0, stream.Position);
|
||||
|
||||
stream = new ReadOnlyBitStream(new MemoryStream(new byte[16]));
|
||||
stream = new ReadOnlyBitStream(new MemoryStream(new byte[16], 0, 16, true, true));
|
||||
Assert.Equal(16, stream.Length);
|
||||
Assert.Equal(0, stream.Position);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
#if NET7_0_OR_GREATER
|
||||
using System.Numerics;
|
||||
#endif
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
@@ -9,7 +12,7 @@ namespace SabreTools.IO.Extensions
|
||||
/// <summary>
|
||||
/// Extensions for BinaryReader
|
||||
/// </summary>
|
||||
/// <remarks>TODO: Add U/Int24 and U/Int48 methods</remarks>
|
||||
/// TODO: Handle proper negative values for Int24 and Int48
|
||||
public static class BinaryReaderExtensions
|
||||
{
|
||||
/// <inheritdoc cref="BinaryReader.Read(byte[], int, int)"/>
|
||||
@@ -66,6 +69,70 @@ namespace SabreTools.IO.Extensions
|
||||
return BitConverter.ToUInt16(buffer, 0);
|
||||
}
|
||||
|
||||
// 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"/>
|
||||
/// <remarks>Reads in big-endian format</remarks>
|
||||
public static Half ReadHalfBigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] buffer = reader.ReadBytes(2);
|
||||
Array.Reverse(buffer);
|
||||
return BitConverter.ToHalf(buffer, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int24 encoded as an Int32
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int24 encoded as an Int32
|
||||
/// </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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt24 encoded as a UInt32
|
||||
/// </summary>
|
||||
public static uint ReadUInt24(this BinaryReader reader)
|
||||
{
|
||||
byte[] buffer = reader.ReadBytes(3);
|
||||
|
||||
byte[] padded = new byte[4];
|
||||
Array.Copy(buffer, padded, 3);
|
||||
return BitConverter.ToUInt32(padded, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt24 encoded as a UInt32
|
||||
/// </summary>
|
||||
/// <remarks>Reads in big-endian format</remarks>
|
||||
public static uint ReadUInt24BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] buffer = reader.ReadBytes(3);
|
||||
Array.Reverse(buffer);
|
||||
|
||||
byte[] padded = new byte[4];
|
||||
Array.Copy(buffer, padded, 3);
|
||||
return BitConverter.ToUInt32(padded, 0);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="BinaryReader.ReadInt32"/>
|
||||
/// <remarks>Reads in big-endian format</remarks>
|
||||
public static int ReadInt32BigEndian(this BinaryReader reader)
|
||||
@@ -92,6 +159,58 @@ namespace SabreTools.IO.Extensions
|
||||
return BitConverter.ToSingle(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int48 encoded as an Int64
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int48 encoded as an Int64
|
||||
/// </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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt48 encoded as a UInt64
|
||||
/// </summary>
|
||||
public static ulong ReadUInt48(this BinaryReader reader)
|
||||
{
|
||||
byte[] buffer = reader.ReadBytes(6);
|
||||
|
||||
byte[] padded = new byte[8];
|
||||
Array.Copy(buffer, padded, 6);
|
||||
return BitConverter.ToUInt64(padded, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt48 encoded as a UInt64
|
||||
/// </summary>
|
||||
/// <remarks>Reads in big-endian format</remarks>
|
||||
public static ulong ReadUInt48BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] buffer = reader.ReadBytes(6);
|
||||
Array.Reverse(buffer);
|
||||
|
||||
byte[] padded = new byte[8];
|
||||
Array.Copy(buffer, padded, 6);
|
||||
return BitConverter.ToUInt64(padded, 0);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="BinaryReader.ReadInt64"/>
|
||||
/// <remarks>Reads in big-endian format</remarks>
|
||||
public static long ReadInt64BigEndian(this BinaryReader reader)
|
||||
@@ -126,12 +245,12 @@ namespace SabreTools.IO.Extensions
|
||||
byte[] buffer = reader.ReadBytes(16);
|
||||
Array.Reverse(buffer);
|
||||
|
||||
int i1 = BitConverter.ToInt32(buffer, 0);
|
||||
int i2 = BitConverter.ToInt32(buffer, 4);
|
||||
int i3 = BitConverter.ToInt32(buffer, 8);
|
||||
int i4 = BitConverter.ToInt32(buffer, 12);
|
||||
int lo = BitConverter.ToInt32(buffer, 0);
|
||||
int mid = BitConverter.ToInt32(buffer, 4);
|
||||
int hi = BitConverter.ToInt32(buffer, 8);
|
||||
int flags = BitConverter.ToInt32(buffer, 12);
|
||||
|
||||
return new decimal([i1, i2, i3, i4]);
|
||||
return new decimal([lo, mid, hi, flags]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -162,7 +281,7 @@ namespace SabreTools.IO.Extensions
|
||||
public static Int128 ReadInt128(this BinaryReader reader)
|
||||
{
|
||||
byte[] buffer = reader.ReadBytes(16);
|
||||
return new Int128(BitConverter.ToUInt64(buffer, 0), BitConverter.ToUInt64(buffer, 8));
|
||||
return (Int128)new BigInteger(buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -173,7 +292,7 @@ namespace SabreTools.IO.Extensions
|
||||
{
|
||||
byte[] buffer = reader.ReadBytes(16);
|
||||
Array.Reverse(buffer);
|
||||
return new Int128(BitConverter.ToUInt64(buffer, 0), BitConverter.ToUInt64(buffer, 8));
|
||||
return (Int128)new BigInteger(buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -182,7 +301,7 @@ namespace SabreTools.IO.Extensions
|
||||
public static UInt128 ReadUInt128(this BinaryReader reader)
|
||||
{
|
||||
byte[] buffer = reader.ReadBytes(16);
|
||||
return new UInt128(BitConverter.ToUInt64(buffer, 0), BitConverter.ToUInt64(buffer, 8));
|
||||
return (UInt128)new BigInteger(buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -193,7 +312,7 @@ namespace SabreTools.IO.Extensions
|
||||
{
|
||||
byte[] buffer = reader.ReadBytes(16);
|
||||
Array.Reverse(buffer);
|
||||
return new UInt128(BitConverter.ToUInt64(buffer, 0), BitConverter.ToUInt64(buffer, 8));
|
||||
return (UInt128)new BigInteger(buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
452
SabreTools.IO/Extensions/BinaryWriterExtensions.cs
Normal file
452
SabreTools.IO/Extensions/BinaryWriterExtensions.cs
Normal file
@@ -0,0 +1,452 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
#if NET7_0_OR_GREATER
|
||||
using System.Numerics;
|
||||
#endif
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace SabreTools.IO.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions for BinaryWriter
|
||||
/// </summary>
|
||||
/// <remarks>TODO: Add WriteDecimal methods</remarks>
|
||||
/// TODO: Handle proper negative values for Int24 and Int48
|
||||
public static class BinaryWriterExtensions
|
||||
{
|
||||
#region Write
|
||||
|
||||
/// <inheritdoc cref="BinaryWriter.Write(byte[])"/>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this BinaryWriter writer, byte[] value)
|
||||
{
|
||||
Array.Reverse(value);
|
||||
return WriteFromBuffer(writer, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="BinaryWriter.Write(char)"/>
|
||||
public static bool Write(this BinaryWriter writer, char value, Encoding encoding)
|
||||
{
|
||||
byte[] buffer = encoding.GetBytes($"{value}");
|
||||
return WriteFromBuffer(writer, buffer);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="BinaryWriter.Write(short)"/>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this BinaryWriter writer, short value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(writer, buffer);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="BinaryWriter.Write(ushort)"/>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this BinaryWriter writer, ushort value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(writer, buffer);
|
||||
}
|
||||
|
||||
// Half was introduced in net5.0 but doesn't have a BitConverter implementation until net6.0
|
||||
#if NET6_0_OR_GREATER
|
||||
/// <inheritdoc cref="BinaryWriter.Write(Half)"/>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this BinaryWriter writer, Half value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(writer, buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int32 as an Int24 to the underlying stream
|
||||
/// </summary>
|
||||
/// <remarks>Throws away top byte</remarks>
|
||||
public static bool WriteAsInt24(this BinaryWriter writer, int value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
|
||||
byte[] reduced = new byte[3];
|
||||
Array.Copy(buffer, reduced, 3);
|
||||
return WriteFromBuffer(writer, reduced);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int32 as an Int24 to the underlying stream
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
/// <remarks>Throws away top byte</remarks>
|
||||
public static bool WriteAsInt24BigEndian(this BinaryWriter writer, int value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
|
||||
byte[] reduced = new byte[3];
|
||||
Array.Copy(buffer, 1, reduced, 0, 3);
|
||||
return WriteFromBuffer(writer, reduced);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt32 as a UInt24 to the underlying stream
|
||||
/// </summary>
|
||||
/// <remarks>Throws away top byte</remarks>
|
||||
public static bool WriteAsUInt24(this BinaryWriter writer, uint value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
|
||||
byte[] reduced = new byte[3];
|
||||
Array.Copy(buffer, reduced, 3);
|
||||
return WriteFromBuffer(writer, reduced);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt32 as a UInt24 to the underlying stream
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
/// <remarks>Throws away top byte</remarks>
|
||||
public static bool WriteAsUInt24BigEndian(this BinaryWriter writer, uint value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
|
||||
byte[] reduced = new byte[3];
|
||||
Array.Copy(buffer, 1, reduced, 0, 3);
|
||||
return WriteFromBuffer(writer, reduced);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="BinaryWriter.Write(int)"/>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this BinaryWriter writer, int value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(writer, buffer);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="BinaryWriter.Write(uint)"/>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this BinaryWriter writer, uint value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(writer, buffer);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="BinaryWriter.Write(float)"/>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this BinaryWriter writer, float value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(writer, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int64 as an Int48 to the underlying stream
|
||||
/// </summary>
|
||||
/// <remarks>Throws away top 2 bytes</remarks>
|
||||
public static bool WriteAsInt48(this BinaryWriter writer, long value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
|
||||
byte[] reduced = new byte[6];
|
||||
Array.Copy(buffer, reduced, 6);
|
||||
return WriteFromBuffer(writer, reduced);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int64 as an Int48 to the underlying stream
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
/// <remarks>Throws away top 2 bytes</remarks>
|
||||
public static bool WriteAsInt48BigEndian(this BinaryWriter writer, long value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
|
||||
byte[] reduced = new byte[6];
|
||||
Array.Copy(buffer, 2, reduced, 0, 6);
|
||||
return WriteFromBuffer(writer, reduced);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt64 as a UInt48 to the underlying stream
|
||||
/// </summary>
|
||||
/// <remarks>Throws away top 2 bytes</remarks>
|
||||
public static bool WriteAsUInt48(this BinaryWriter writer, ulong value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
|
||||
byte[] reduced = new byte[6];
|
||||
Array.Copy(buffer, reduced, 6);
|
||||
return WriteFromBuffer(writer, reduced);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt64 as a UInt48 to the underlying stream
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
/// <remarks>Throws away top 2 bytes</remarks>
|
||||
public static bool WriteAsUInt48BigEndian(this BinaryWriter writer, ulong value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
|
||||
byte[] reduced = new byte[6];
|
||||
Array.Copy(buffer, 2, reduced, 0, 6);
|
||||
return WriteFromBuffer(writer, reduced);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="BinaryWriter.Write(long)"/>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this BinaryWriter writer, long value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(writer, buffer);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="BinaryWriter.Write(ulong)"/>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this BinaryWriter writer, ulong value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(writer, buffer);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="BinaryWriter.Write(double)"/>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this BinaryWriter writer, double value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(writer, buffer);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="BinaryWriter.Write(decimal)"/>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this BinaryWriter writer, decimal value)
|
||||
{
|
||||
int[] bits = decimal.GetBits(value);
|
||||
|
||||
byte[] lo = BitConverter.GetBytes(bits[0]);
|
||||
byte[] mid = BitConverter.GetBytes(bits[1]);
|
||||
byte[] hi = BitConverter.GetBytes(bits[2]);
|
||||
byte[] flags = BitConverter.GetBytes(bits[3]);
|
||||
|
||||
byte[] buffer = new byte[16];
|
||||
Array.Copy(lo, 0, buffer, 0, 4);
|
||||
Array.Copy(mid, 0, buffer, 4, 4);
|
||||
Array.Copy(hi, 0, buffer, 8, 4);
|
||||
Array.Copy(flags, 0, buffer, 12, 4);
|
||||
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(writer, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a Guid
|
||||
/// </summary>
|
||||
public static bool Write(this BinaryWriter writer, Guid value)
|
||||
{
|
||||
byte[] buffer = value.ToByteArray();
|
||||
return WriteFromBuffer(writer, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a Guid
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this BinaryWriter writer, Guid value)
|
||||
{
|
||||
byte[] buffer = value.ToByteArray();
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(writer, buffer);
|
||||
}
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
/// <summary>
|
||||
/// Write an Int128
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int128
|
||||
/// </summary>
|
||||
/// <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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt128
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt128
|
||||
/// </summary>
|
||||
/// <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);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Write a null-terminated string to the underlying stream
|
||||
/// </summary>
|
||||
public static bool WriteNullTerminatedString(this BinaryWriter writer, string? value, Encoding encoding)
|
||||
{
|
||||
// If the value is null
|
||||
if (value == null)
|
||||
return false;
|
||||
|
||||
// Add the null terminator and write
|
||||
value += "\0";
|
||||
byte[] buffer = encoding.GetBytes(value);
|
||||
return WriteFromBuffer(writer, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a null-terminated ASCII string to the underlying stream
|
||||
/// </summary>
|
||||
public static bool WriteNullTerminatedAnsiString(this BinaryWriter writer, string? value)
|
||||
=> writer.WriteNullTerminatedString(value, Encoding.ASCII);
|
||||
|
||||
/// <summary>
|
||||
/// Write a null-terminated Unicode string to the underlying stream
|
||||
/// </summary>
|
||||
public static bool WriteNullTerminatedUnicodeString(this BinaryWriter writer, string? value)
|
||||
=> writer.WriteNullTerminatedString(value, Encoding.Unicode);
|
||||
|
||||
/// <summary>
|
||||
/// Write a byte-prefixed ASCII string to the underlying stream
|
||||
/// </summary>
|
||||
public static bool WritePrefixedAnsiString(this BinaryWriter writer, string? value)
|
||||
{
|
||||
// If the value is null
|
||||
if (value == null)
|
||||
return false;
|
||||
|
||||
// Get the buffer
|
||||
byte[] buffer = Encoding.ASCII.GetBytes(value);
|
||||
|
||||
// Write the length as a byte
|
||||
writer.Write((byte)buffer.Length);
|
||||
|
||||
// Write the buffer
|
||||
return WriteFromBuffer(writer, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a ushort-prefixed Unicode string to the underlying stream
|
||||
/// </summary>
|
||||
public static bool WritePrefixedUnicodeString(this BinaryWriter writer, string? value)
|
||||
{
|
||||
// If the value is null
|
||||
if (value == null)
|
||||
return false;
|
||||
|
||||
// Get the buffer
|
||||
byte[] buffer = Encoding.Unicode.GetBytes(value);
|
||||
|
||||
// Write the length as a ushort
|
||||
writer.Write((ushort)buffer.Length);
|
||||
|
||||
// Write the buffer
|
||||
return WriteFromBuffer(writer, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a string that is terminated by a newline but contains a quoted portion that
|
||||
/// may also contain a newline to the underlying stream
|
||||
/// </summary>
|
||||
public static bool WriteQuotedString(this BinaryWriter writer, string? value)
|
||||
=> writer.WriteQuotedString(value, Encoding.UTF8);
|
||||
|
||||
/// <summary>
|
||||
/// Write a string that is terminated by a newline but contains a quoted portion that
|
||||
/// may also contain a newline to the underlying stream
|
||||
/// </summary>
|
||||
public static bool WriteQuotedString(this BinaryWriter writer, string? value, Encoding encoding)
|
||||
{
|
||||
// If the value is null
|
||||
if (value == null)
|
||||
return false;
|
||||
|
||||
// Write without the null terminator
|
||||
byte[] buffer = encoding.GetBytes(value);
|
||||
return WriteFromBuffer(writer, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a <typeparamref name="T"/> to the underlying stream
|
||||
/// </summary>
|
||||
public static bool WriteType<T>(this BinaryWriter writer, T? value)
|
||||
{
|
||||
// Handle the null case
|
||||
if (value == null)
|
||||
return false;
|
||||
|
||||
int typeSize = Marshal.SizeOf(typeof(T));
|
||||
|
||||
var buffer = new byte[typeSize];
|
||||
var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
|
||||
Marshal.StructureToPtr(value, handle.AddrOfPinnedObject(), false);
|
||||
handle.Free();
|
||||
|
||||
return WriteFromBuffer(writer, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an array of bytes to the underlying stream
|
||||
/// </summary>
|
||||
private static bool WriteFromBuffer(BinaryWriter writer, byte[] value)
|
||||
{
|
||||
// If the stream is not writable
|
||||
if (!writer.BaseStream.CanWrite)
|
||||
return false;
|
||||
|
||||
// Handle the 0-byte case
|
||||
if (value.Length == 0)
|
||||
return true;
|
||||
|
||||
// Handle the general case, forcing a write of the correct length
|
||||
writer.Write(value, 0, value.Length);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
#if NET7_0_OR_GREATER
|
||||
using System.Numerics;
|
||||
#endif
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
@@ -8,8 +11,8 @@ namespace SabreTools.IO.Extensions
|
||||
/// <summary>
|
||||
/// Extensions for byte arrays
|
||||
/// </summary>
|
||||
/// <remarks>TODO: Add U/Int24 and U/Int48 methods</remarks>
|
||||
public static class ByteArrayExtensions
|
||||
/// TODO: Handle proper negative values for Int24 and Int48
|
||||
public static class ByteArrayReaderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Read a UInt8 and increment the pointer to an array
|
||||
@@ -101,6 +104,81 @@ namespace SabreTools.IO.Extensions
|
||||
return BitConverter.ToUInt16(buffer, 0);
|
||||
}
|
||||
|
||||
// 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>
|
||||
public static Half ReadHalf(this byte[] content, ref int offset)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(content, ref offset, 2);
|
||||
return BitConverter.ToHalf(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Half and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <remarks>Reads in big-endian format</remarks>
|
||||
public static Half ReadHalfBigEndian(this byte[] content, ref int offset)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(content, ref offset, 2);
|
||||
Array.Reverse(buffer);
|
||||
return BitConverter.ToHalf(buffer, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int24 encoded as an Int32 and increment the pointer to an array
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int24 encoded as an Int32 and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <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[] padded = new byte[4];
|
||||
Array.Copy(buffer, padded, 3);
|
||||
return BitConverter.ToInt32(padded, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt24 encoded as a UInt32 and increment the pointer to an array
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt24 encoded as a UInt32 and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <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[] padded = new byte[4];
|
||||
Array.Copy(buffer, padded, 3);
|
||||
return BitConverter.ToUInt32(padded, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int32 and increment the pointer to an array
|
||||
/// </summary>
|
||||
@@ -161,6 +239,58 @@ namespace SabreTools.IO.Extensions
|
||||
return BitConverter.ToSingle(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int48 encoded as an Int64 and increment the pointer to an array
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int48 encoded as an Int64 and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <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[] padded = new byte[8];
|
||||
Array.Copy(buffer, padded, 6);
|
||||
return BitConverter.ToInt64(padded, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt48 encoded as a UInt64 and increment the pointer to an array
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt48 encoded as a 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[] padded = new byte[8];
|
||||
Array.Copy(buffer, padded, 6);
|
||||
return BitConverter.ToUInt64(padded, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int64 and increment the pointer to an array
|
||||
/// </summary>
|
||||
@@ -228,12 +358,12 @@ namespace SabreTools.IO.Extensions
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(content, ref offset, 16);
|
||||
|
||||
int i1 = BitConverter.ToInt32(buffer, 0);
|
||||
int i2 = BitConverter.ToInt32(buffer, 4);
|
||||
int i3 = BitConverter.ToInt32(buffer, 8);
|
||||
int i4 = BitConverter.ToInt32(buffer, 12);
|
||||
int lo = BitConverter.ToInt32(buffer, 0);
|
||||
int mid = BitConverter.ToInt32(buffer, 4);
|
||||
int hi = BitConverter.ToInt32(buffer, 8);
|
||||
int flags = BitConverter.ToInt32(buffer, 12);
|
||||
|
||||
return new decimal([i1, i2, i3, i4]);
|
||||
return new decimal([lo, mid, hi, flags]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -245,12 +375,12 @@ namespace SabreTools.IO.Extensions
|
||||
byte[] buffer = ReadToBuffer(content, ref offset, 16);
|
||||
Array.Reverse(buffer);
|
||||
|
||||
int i1 = BitConverter.ToInt32(buffer, 0);
|
||||
int i2 = BitConverter.ToInt32(buffer, 4);
|
||||
int i3 = BitConverter.ToInt32(buffer, 8);
|
||||
int i4 = BitConverter.ToInt32(buffer, 12);
|
||||
int lo = BitConverter.ToInt32(buffer, 0);
|
||||
int mid = BitConverter.ToInt32(buffer, 4);
|
||||
int hi = BitConverter.ToInt32(buffer, 8);
|
||||
int flags = BitConverter.ToInt32(buffer, 12);
|
||||
|
||||
return new decimal([i1, i2, i3, i4]);
|
||||
return new decimal([lo, mid, hi, flags]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -273,7 +403,6 @@ 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 and increment the pointer to an array
|
||||
@@ -281,7 +410,7 @@ namespace SabreTools.IO.Extensions
|
||||
public static Int128 ReadInt128(this byte[] content, ref int offset)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(content, ref offset, 16);
|
||||
return new Int128(BitConverter.ToUInt64(buffer, 0), BitConverter.ToUInt64(buffer, 8));
|
||||
return (Int128)new BigInteger(buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -292,7 +421,7 @@ namespace SabreTools.IO.Extensions
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(content, ref offset, 16);
|
||||
Array.Reverse(buffer);
|
||||
return new Int128(BitConverter.ToUInt64(buffer, 0), BitConverter.ToUInt64(buffer, 8));
|
||||
return (Int128)new BigInteger(buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -301,7 +430,7 @@ namespace SabreTools.IO.Extensions
|
||||
public static UInt128 ReadUInt128(this byte[] content, ref int offset)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(content, ref offset, 16);
|
||||
return new UInt128(BitConverter.ToUInt64(buffer, 0), BitConverter.ToUInt64(buffer, 8));
|
||||
return (UInt128)new BigInteger(buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -312,7 +441,7 @@ namespace SabreTools.IO.Extensions
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(content, ref offset, 16);
|
||||
Array.Reverse(buffer);
|
||||
return new UInt128(BitConverter.ToUInt64(buffer, 0), BitConverter.ToUInt64(buffer, 8));
|
||||
return (UInt128)new BigInteger(buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -416,14 +545,14 @@ namespace SabreTools.IO.Extensions
|
||||
|
||||
/// <summary>
|
||||
/// Read a string that is terminated by a newline but contains a quoted portion that
|
||||
/// may also contain a newline from the stream
|
||||
/// may also contain a newline from the byte array
|
||||
/// </summary>
|
||||
public static string? ReadQuotedString(this byte[] content, ref int offset)
|
||||
=> content.ReadQuotedString(ref offset, Encoding.Default);
|
||||
|
||||
/// <summary>
|
||||
/// Read a string that is terminated by a newline but contains a quoted portion that
|
||||
/// may also contain a newline from the stream
|
||||
/// may also contain a newline from the byte array
|
||||
/// </summary>
|
||||
public static string? ReadQuotedString(this byte[] content, ref int offset, Encoding encoding)
|
||||
{
|
||||
@@ -454,7 +583,7 @@ namespace SabreTools.IO.Extensions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a <typeparamref name="T"/> from the underlying stream
|
||||
/// Read a <typeparamref name="T"/> from the byte array
|
||||
/// </summary>
|
||||
public static T? ReadType<T>(this byte[] content, ref int offset)
|
||||
{
|
||||
@@ -469,7 +598,7 @@ namespace SabreTools.IO.Extensions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a number of bytes from the current byte array to a buffer
|
||||
/// Read a number of bytes from the byte array to a buffer
|
||||
/// </summary>
|
||||
private static byte[] ReadToBuffer(byte[] content, ref int offset, int length)
|
||||
{
|
||||
603
SabreTools.IO/Extensions/ByteArrayWriterExtensions.cs
Normal file
603
SabreTools.IO/Extensions/ByteArrayWriterExtensions.cs
Normal file
@@ -0,0 +1,603 @@
|
||||
using System;
|
||||
#if NET7_0_OR_GREATER
|
||||
using System.Numerics;
|
||||
#endif
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace SabreTools.IO.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions for byte arrays
|
||||
/// </summary>
|
||||
/// TODO: Handle proper negative values for Int24 and Int48
|
||||
public static class ByteArrayWriterExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Write a UInt8 and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static bool Write(this byte[] content, ref int offset, byte value)
|
||||
=> WriteFromBuffer(content, ref offset, [value]);
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt8[] and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static bool Write(this byte[] content, ref int offset, byte[] value)
|
||||
=> WriteFromBuffer(content, ref offset, value);
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt8[] and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this byte[] content, ref int offset, byte[] value)
|
||||
{
|
||||
Array.Reverse(value);
|
||||
return WriteFromBuffer(content, ref offset, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int8 and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static bool Write(this byte[] content, ref int offset, sbyte value)
|
||||
=> WriteFromBuffer(content, ref offset, [(byte)value]);
|
||||
|
||||
/// <summary>
|
||||
/// Write a Char and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static bool Write(this byte[] content, ref int offset, char value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a Char with an Encoding and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static bool Write(this byte[] content, ref int offset, char value, Encoding encoding)
|
||||
{
|
||||
byte[] buffer = encoding.GetBytes($"{value}");
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int16 and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static bool Write(this byte[] content, ref int offset, short value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int16 and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this byte[] content, ref int offset, short value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt16 and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static bool Write(this byte[] content, ref int offset, ushort value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt16 and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this byte[] content, ref int offset, ushort value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
// Half was introduced in net5.0 but doesn't have a BitConverter implementation until net6.0
|
||||
#if NET6_0_OR_GREATER
|
||||
/// <summary>
|
||||
/// Write a Half and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static bool Write(this byte[] content, ref int offset, Half value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a Half and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this byte[] content, ref int offset, Half value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int32 as an Int24 and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <remarks>Throws away top byte</remarks>
|
||||
public static bool WriteAsInt24(this byte[] content, ref int offset, int value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
|
||||
byte[] reduced = new byte[3];
|
||||
Array.Copy(buffer, reduced, 3);
|
||||
return WriteFromBuffer(content, ref offset, reduced);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int32 as an Int24 and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
/// <remarks>Throws away top byte</remarks>
|
||||
public static bool WriteAsInt24BigEndian(this byte[] content, ref int offset, int value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
|
||||
byte[] reduced = new byte[3];
|
||||
Array.Copy(buffer, 1, reduced, 0, 3);
|
||||
return WriteFromBuffer(content, ref offset, reduced);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt32 as a UInt24 and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <remarks>Throws away top byte</remarks>
|
||||
public static bool WriteAsUInt24(this byte[] content, ref int offset, uint value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
|
||||
byte[] reduced = new byte[3];
|
||||
Array.Copy(buffer, reduced, 3);
|
||||
return WriteFromBuffer(content, ref offset, reduced);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt32 as a UInt24 and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
/// <remarks>Throws away top byte</remarks>
|
||||
public static bool WriteAsUInt24BigEndian(this byte[] content, ref int offset, uint value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
|
||||
byte[] reduced = new byte[3];
|
||||
Array.Copy(buffer, 1, reduced, 0, 3);
|
||||
return WriteFromBuffer(content, ref offset, reduced);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int32 and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static bool Write(this byte[] content, ref int offset, int value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int32 and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this byte[] content, ref int offset, int value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt32 and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static bool Write(this byte[] content, ref int offset, uint value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt32 and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this byte[] content, ref int offset, uint value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a Single and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static bool Write(this byte[] content, ref int offset, float value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a Single and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this byte[] content, ref int offset, float value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int64 as an Int48 and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <remarks>Throws away top 2 bytes</remarks>
|
||||
public static bool WriteAsInt48(this byte[] content, ref int offset, long value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
|
||||
byte[] reduced = new byte[6];
|
||||
Array.Copy(buffer, reduced, 6);
|
||||
return WriteFromBuffer(content, ref offset, reduced);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int64 as an Int48 and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
/// <remarks>Throws away top 2 bytes</remarks>
|
||||
public static bool WriteAsInt48BigEndian(this byte[] content, ref int offset, long value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
|
||||
byte[] reduced = new byte[6];
|
||||
Array.Copy(buffer, 2, reduced, 0, 6);
|
||||
return WriteFromBuffer(content, ref offset, reduced);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt64 as a UInt48 and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <remarks>Throws away top 2 bytes</remarks>
|
||||
public static bool WriteAsUInt48(this byte[] content, ref int offset, ulong value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
|
||||
byte[] reduced = new byte[6];
|
||||
Array.Copy(buffer, reduced, 6);
|
||||
return WriteFromBuffer(content, ref offset, reduced);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt64 as a UInt48 and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
/// <remarks>Throws away top 2 bytes</remarks>
|
||||
public static bool WriteAsUInt48BigEndian(this byte[] content, ref int offset, ulong value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
|
||||
byte[] reduced = new byte[6];
|
||||
Array.Copy(buffer, 2, reduced, 0, 6);
|
||||
return WriteFromBuffer(content, ref offset, reduced);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int64 and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static bool Write(this byte[] content, ref int offset, long value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int64 and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this byte[] content, ref int offset, long value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt64 and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static bool Write(this byte[] content, ref int offset, ulong value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt64 and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this byte[] content, ref int offset, ulong value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a Double and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static bool Write(this byte[] content, ref int offset, double value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a Double and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this byte[] content, ref int offset, double value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a Decimal and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static bool Write(this byte[] content, ref int offset, decimal value)
|
||||
{
|
||||
int[] bits = decimal.GetBits(value);
|
||||
|
||||
byte[] lo = BitConverter.GetBytes(bits[0]);
|
||||
byte[] mid = BitConverter.GetBytes(bits[1]);
|
||||
byte[] hi = BitConverter.GetBytes(bits[2]);
|
||||
byte[] flags = BitConverter.GetBytes(bits[3]);
|
||||
|
||||
byte[] buffer = new byte[16];
|
||||
Array.Copy(lo, 0, buffer, 0, 4);
|
||||
Array.Copy(mid, 0, buffer, 4, 4);
|
||||
Array.Copy(hi, 0, buffer, 8, 4);
|
||||
Array.Copy(flags, 0, buffer, 12, 4);
|
||||
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a Decimal and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this byte[] content, ref int offset, decimal value)
|
||||
{
|
||||
int[] bits = decimal.GetBits(value);
|
||||
|
||||
byte[] lo = BitConverter.GetBytes(bits[0]);
|
||||
byte[] mid = BitConverter.GetBytes(bits[1]);
|
||||
byte[] hi = BitConverter.GetBytes(bits[2]);
|
||||
byte[] flags = BitConverter.GetBytes(bits[3]);
|
||||
|
||||
byte[] buffer = new byte[16];
|
||||
Array.Copy(lo, 0, buffer, 0, 4);
|
||||
Array.Copy(mid, 0, buffer, 4, 4);
|
||||
Array.Copy(hi, 0, buffer, 8, 4);
|
||||
Array.Copy(flags, 0, buffer, 12, 4);
|
||||
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a Guid and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static bool Write(this byte[] content, ref int offset, Guid value)
|
||||
{
|
||||
byte[] buffer = value.ToByteArray();
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a Guid and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this byte[] content, ref int offset, Guid value)
|
||||
{
|
||||
byte[] buffer = value.ToByteArray();
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
/// <summary>
|
||||
/// Write an Int128 and increment the pointer to an array
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int128 and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt128 and increment the pointer to an array
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt128 and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <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);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Write a null-terminated string to the array
|
||||
/// </summary>
|
||||
public static bool WriteNullTerminatedString(this byte[] content, ref int offset, string? value, Encoding encoding)
|
||||
{
|
||||
// If the value is null
|
||||
if (value == null)
|
||||
return false;
|
||||
|
||||
// Add the null terminator and write
|
||||
value += "\0";
|
||||
byte[] buffer = encoding.GetBytes(value);
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a null-terminated ASCII string to the byte array
|
||||
/// </summary>
|
||||
public static bool WriteNullTerminatedAnsiString(this byte[] content, ref int offset, string? value)
|
||||
=> content.WriteNullTerminatedString(ref offset, value, Encoding.ASCII);
|
||||
|
||||
/// <summary>
|
||||
/// Write a null-terminated Unicode string to the byte array
|
||||
/// </summary>
|
||||
public static bool WriteNullTerminatedUnicodeString(this byte[] content, ref int offset, string? value)
|
||||
=> content.WriteNullTerminatedString(ref offset, value, Encoding.Unicode);
|
||||
|
||||
/// <summary>
|
||||
/// Write a byte-prefixed ASCII string to the byte array
|
||||
/// </summary>
|
||||
public static bool WritePrefixedAnsiString(this byte[] content, ref int offset, string? value)
|
||||
{
|
||||
// If the value is null
|
||||
if (value == null)
|
||||
return false;
|
||||
|
||||
// Get the buffer
|
||||
byte[] buffer = Encoding.ASCII.GetBytes(value);
|
||||
|
||||
// Write the length as a byte
|
||||
if (!content.Write(ref offset, (byte)buffer.Length))
|
||||
return false;
|
||||
|
||||
// Write the buffer
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a ushort-prefixed Unicode string to the byte array
|
||||
/// </summary>
|
||||
public static bool WritePrefixedUnicodeString(this byte[] content, ref int offset, string? value)
|
||||
{
|
||||
// If the value is null
|
||||
if (value == null)
|
||||
return false;
|
||||
|
||||
// Get the buffer
|
||||
byte[] buffer = Encoding.Unicode.GetBytes(value);
|
||||
|
||||
// Write the length as a ushort
|
||||
if (!content.Write(ref offset, (ushort)buffer.Length))
|
||||
return false;
|
||||
|
||||
// Write the buffer
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a string that is terminated by a newline but contains a quoted portion that
|
||||
/// may also contain a newline to the byte array
|
||||
/// </summary>
|
||||
public static bool WriteQuotedString(this byte[] content, ref int offset, string? value)
|
||||
=> content.WriteQuotedString(ref offset, value, Encoding.UTF8);
|
||||
|
||||
/// <summary>
|
||||
/// Write a string that is terminated by a newline but contains a quoted portion that
|
||||
/// may also contain a newline to the byte array
|
||||
/// </summary>
|
||||
public static bool WriteQuotedString(this byte[] content, ref int offset, string? value, Encoding encoding)
|
||||
{
|
||||
// If the value is null
|
||||
if (value == null)
|
||||
return false;
|
||||
|
||||
// Write without the null terminator
|
||||
byte[] buffer = encoding.GetBytes(value);
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a <typeparamref name="T"/> to the byte array
|
||||
/// </summary>
|
||||
public static bool WriteType<T>(this byte[] content, ref int offset, T? value)
|
||||
{
|
||||
// Handle the null case
|
||||
if (value == null)
|
||||
return false;
|
||||
|
||||
int typeSize = Marshal.SizeOf(typeof(T));
|
||||
|
||||
var buffer = new byte[typeSize];
|
||||
var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
|
||||
Marshal.StructureToPtr(value, handle.AddrOfPinnedObject(), false);
|
||||
handle.Free();
|
||||
|
||||
return WriteFromBuffer(content, ref offset, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an array of bytes to the byte array
|
||||
/// </summary>
|
||||
private static bool WriteFromBuffer(byte[] content, ref int offset, byte[] value)
|
||||
{
|
||||
// Handle the 0-byte case
|
||||
if (value.Length == 0)
|
||||
return true;
|
||||
|
||||
// If there are not enough bytes
|
||||
if (offset + value.Length > content.Length)
|
||||
throw new System.IO.EndOfStreamException(nameof(content));
|
||||
|
||||
// Handle the general case, forcing a write of the correct length
|
||||
Array.Copy(value, 0, content, offset, value.Length);
|
||||
offset += value.Length;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,457 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace SabreTools.IO.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions for Streams
|
||||
/// </summary>
|
||||
/// <remarks>TODO: Add U/Int24 and U/Int48 methods</remarks>
|
||||
public static class StreamExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Read a UInt8 from the stream
|
||||
/// </summary>
|
||||
public static byte ReadByteValue(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 1);
|
||||
return buffer[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt8[] from the stream
|
||||
/// </summary>
|
||||
public static byte[] ReadBytes(this Stream stream, int count)
|
||||
=> ReadToBuffer(stream, count);
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int8 from the stream
|
||||
/// </summary>
|
||||
public static sbyte ReadSByte(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 1);
|
||||
return (sbyte)buffer[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Char from the stream
|
||||
/// </summary>
|
||||
public static char ReadChar(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 1);
|
||||
return (char)buffer[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int16 from the stream
|
||||
/// </summary>
|
||||
public static short ReadInt16(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 2);
|
||||
return BitConverter.ToInt16(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int16 from the stream
|
||||
/// </summary>
|
||||
/// <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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt16 from the stream
|
||||
/// </summary>
|
||||
public static ushort ReadUInt16(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 2);
|
||||
return BitConverter.ToUInt16(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt16 from the stream
|
||||
/// </summary>
|
||||
/// <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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int32 from the stream
|
||||
/// </summary>
|
||||
public static int ReadInt32(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 4);
|
||||
return BitConverter.ToInt32(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int32 from the stream
|
||||
/// </summary>
|
||||
/// <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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt32 from the stream
|
||||
/// </summary>
|
||||
public static uint ReadUInt32(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 4);
|
||||
return BitConverter.ToUInt32(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt32 from the stream
|
||||
/// </summary>
|
||||
/// <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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Single from the stream
|
||||
/// </summary>
|
||||
public static float ReadSingle(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 4);
|
||||
return BitConverter.ToSingle(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Single from the stream
|
||||
/// </summary>
|
||||
/// <remarks>Reads in big-endian format</remarks>
|
||||
public static float ReadSingleBigEndian(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 4);
|
||||
Array.Reverse(buffer);
|
||||
return BitConverter.ToSingle(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int64 from the stream
|
||||
/// </summary>
|
||||
public static long ReadInt64(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 8);
|
||||
return BitConverter.ToInt64(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int64 from the stream
|
||||
/// </summary>
|
||||
/// <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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt64 from the stream
|
||||
/// </summary>
|
||||
public static ulong ReadUInt64(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 8);
|
||||
return BitConverter.ToUInt64(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt64 from the stream
|
||||
/// </summary>
|
||||
/// <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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Double from the stream
|
||||
/// </summary>
|
||||
public static double ReadDouble(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 8);
|
||||
return BitConverter.ToDouble(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Double from the stream
|
||||
/// </summary>
|
||||
/// <remarks>Reads in big-endian format</remarks>
|
||||
public static double ReadDoubleBigEndian(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 8);
|
||||
Array.Reverse(buffer);
|
||||
return BitConverter.ToDouble(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Decimal from the stream
|
||||
/// </summary>
|
||||
public static decimal ReadDecimal(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 16);
|
||||
|
||||
int i1 = BitConverter.ToInt32(buffer, 0);
|
||||
int i2 = BitConverter.ToInt32(buffer, 4);
|
||||
int i3 = BitConverter.ToInt32(buffer, 8);
|
||||
int i4 = BitConverter.ToInt32(buffer, 12);
|
||||
|
||||
return new decimal([i1, i2, i3, i4]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Decimal from the stream
|
||||
/// </summary>
|
||||
/// <remarks>Reads in big-endian format</remarks>
|
||||
public static decimal ReadDecimalBigEndian(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 16);
|
||||
Array.Reverse(buffer);
|
||||
|
||||
int i1 = BitConverter.ToInt32(buffer, 0);
|
||||
int i2 = BitConverter.ToInt32(buffer, 4);
|
||||
int i3 = BitConverter.ToInt32(buffer, 8);
|
||||
int i4 = BitConverter.ToInt32(buffer, 12);
|
||||
|
||||
return new decimal([i1, i2, i3, i4]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Guid from the stream
|
||||
/// </summary>
|
||||
public static Guid ReadGuid(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 16);
|
||||
return new Guid(buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Guid from the stream
|
||||
/// </summary>
|
||||
/// <remarks>Reads in big-endian format</remarks>
|
||||
public static Guid ReadGuidBigEndian(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 16);
|
||||
Array.Reverse(buffer);
|
||||
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 stream
|
||||
/// </summary>
|
||||
public static Int128 ReadInt128(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 16);
|
||||
return new Int128(BitConverter.ToUInt64(buffer, 0), BitConverter.ToUInt64(buffer, 8));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int128 from the stream
|
||||
/// </summary>
|
||||
/// <remarks>Reads in big-endian format</remarks>
|
||||
public static Int128 ReadInt128BigEndian(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 16);
|
||||
Array.Reverse(buffer);
|
||||
return new Int128(BitConverter.ToUInt64(buffer, 0), BitConverter.ToUInt64(buffer, 8));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt128 from the stream
|
||||
/// </summary>
|
||||
public static UInt128 ReadUInt128(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 16);
|
||||
return new UInt128(BitConverter.ToUInt64(buffer, 0), BitConverter.ToUInt64(buffer, 8));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt128 from the stream
|
||||
/// </summary>
|
||||
/// <remarks>Reads in big-endian format</remarks>
|
||||
public static UInt128 ReadUInt128BigEndian(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 16);
|
||||
Array.Reverse(buffer);
|
||||
return new UInt128(BitConverter.ToUInt64(buffer, 0), BitConverter.ToUInt64(buffer, 8));
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Read a null-terminated string from the stream
|
||||
/// </summary>
|
||||
public static string? ReadNullTerminatedString(this Stream stream, Encoding encoding)
|
||||
{
|
||||
// Short-circuit to explicit implementations
|
||||
if (encoding.Equals(Encoding.ASCII))
|
||||
return stream.ReadNullTerminatedAnsiString();
|
||||
else if (encoding.Equals(Encoding.Unicode))
|
||||
return stream.ReadNullTerminatedUnicodeString();
|
||||
|
||||
if (stream.Position >= stream.Length)
|
||||
return null;
|
||||
|
||||
List<byte> buffer = [];
|
||||
while (stream.Position < stream.Length)
|
||||
{
|
||||
byte ch = stream.ReadByteValue();
|
||||
buffer.Add(ch);
|
||||
if (ch == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
return encoding.GetString([.. buffer]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a null-terminated ASCII string from the stream
|
||||
/// </summary>
|
||||
public static string? ReadNullTerminatedAnsiString(this Stream stream)
|
||||
{
|
||||
if (stream.Position >= stream.Length)
|
||||
return null;
|
||||
|
||||
List<byte> buffer = [];
|
||||
while (stream.Position < stream.Length)
|
||||
{
|
||||
byte ch = stream.ReadByteValue();
|
||||
buffer.Add(ch);
|
||||
if (ch == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
return Encoding.ASCII.GetString([.. buffer]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a null-terminated Unicode string from the stream
|
||||
/// </summary>
|
||||
public static string? ReadNullTerminatedUnicodeString(this Stream stream)
|
||||
{
|
||||
if (stream.Position >= stream.Length)
|
||||
return null;
|
||||
|
||||
List<byte> buffer = [];
|
||||
while (stream.Position < stream.Length)
|
||||
{
|
||||
byte[] ch = stream.ReadBytes(2);
|
||||
buffer.AddRange(ch);
|
||||
if (ch[0] == '\0' && ch[1] == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
return Encoding.Unicode.GetString([.. buffer]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a byte-prefixed ASCII string from the stream
|
||||
/// </summary>
|
||||
public static string? ReadPrefixedAnsiString(this Stream stream)
|
||||
{
|
||||
if (stream.Position >= stream.Length)
|
||||
return null;
|
||||
|
||||
byte size = stream.ReadByteValue();
|
||||
if (stream.Position + size >= stream.Length)
|
||||
return null;
|
||||
|
||||
byte[] buffer = stream.ReadBytes(size);
|
||||
return Encoding.ASCII.GetString(buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a ushort-prefixed Unicode string from the stream
|
||||
/// </summary>
|
||||
public static string? ReadPrefixedUnicodeString(this Stream stream)
|
||||
{
|
||||
if (stream.Position >= stream.Length)
|
||||
return null;
|
||||
|
||||
ushort size = stream.ReadUInt16();
|
||||
if (stream.Position + size >= stream.Length)
|
||||
return null;
|
||||
|
||||
byte[] buffer = stream.ReadBytes(size);
|
||||
return Encoding.Unicode.GetString(buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a string that is terminated by a newline but contains a quoted portion that
|
||||
/// may also contain a newline from the stream
|
||||
/// </summary>
|
||||
public static string? ReadQuotedString(this Stream stream)
|
||||
=> stream.ReadQuotedString(Encoding.Default);
|
||||
|
||||
/// <summary>
|
||||
/// Read a string that is terminated by a newline but contains a quoted portion that
|
||||
/// may also contain a newline from the stream
|
||||
/// </summary>
|
||||
public static string? ReadQuotedString(this Stream stream, Encoding encoding)
|
||||
{
|
||||
if (stream.Position >= stream.Length)
|
||||
return null;
|
||||
|
||||
var bytes = new List<byte>();
|
||||
bool openQuote = false;
|
||||
while (stream.Position < stream.Length)
|
||||
{
|
||||
// Read the byte value
|
||||
byte b = stream.ReadByteValue();
|
||||
|
||||
// If we have a quote, flip the flag
|
||||
if (b == (byte)'"')
|
||||
openQuote = !openQuote;
|
||||
|
||||
// If we have a newline not in a quoted string, exit the loop
|
||||
else if (b == (byte)'\n' && !openQuote)
|
||||
break;
|
||||
|
||||
// Add the byte to the set
|
||||
bytes.Add(b);
|
||||
}
|
||||
|
||||
var line = encoding.GetString([.. bytes]);
|
||||
return line.TrimEnd();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a <typeparamref name="T"/> from the stream
|
||||
/// </summary>
|
||||
public static T? ReadType<T>(this Stream stream)
|
||||
{
|
||||
int typeSize = Marshal.SizeOf(typeof(T));
|
||||
byte[] buffer = ReadToBuffer(stream, typeSize);
|
||||
|
||||
var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
|
||||
var data = (T?)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
|
||||
handle.Free();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Seek to a specific point in the stream, if possible
|
||||
/// </summary>
|
||||
@@ -490,27 +42,5 @@ namespace SabreTools.IO.Extensions
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a number of bytes from the current Stream to a buffer
|
||||
/// </summary>
|
||||
private static byte[] ReadToBuffer(Stream stream, int length)
|
||||
{
|
||||
// If we have an invalid length
|
||||
if (length < 0)
|
||||
throw new ArgumentOutOfRangeException($"{nameof(length)} must be 0 or a positive value");
|
||||
|
||||
// Handle the 0-byte case
|
||||
if (length == 0)
|
||||
return [];
|
||||
|
||||
// Handle the general case, forcing a read of the correct length
|
||||
byte[] buffer = new byte[length];
|
||||
int read = stream.Read(buffer, 0, length);
|
||||
if (read < length)
|
||||
throw new EndOfStreamException(nameof(stream));
|
||||
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
606
SabreTools.IO/Extensions/StreamReaderExtensions.cs
Normal file
606
SabreTools.IO/Extensions/StreamReaderExtensions.cs
Normal file
@@ -0,0 +1,606 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
#if NET7_0_OR_GREATER
|
||||
using System.Numerics;
|
||||
#endif
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace SabreTools.IO.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions for Streams
|
||||
/// </summary>
|
||||
/// TODO: Handle proper negative values for Int24 and Int48
|
||||
public static class StreamReaderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Read a UInt8 from the stream
|
||||
/// </summary>
|
||||
public static byte ReadByteValue(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 1);
|
||||
return buffer[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt8[] from the stream
|
||||
/// </summary>
|
||||
public static byte[] ReadBytes(this Stream stream, int count)
|
||||
=> ReadToBuffer(stream, count);
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int8 from the stream
|
||||
/// </summary>
|
||||
public static sbyte ReadSByte(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 1);
|
||||
return (sbyte)buffer[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Char from the stream
|
||||
/// </summary>
|
||||
public static char ReadChar(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 1);
|
||||
return (char)buffer[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int16 from the stream
|
||||
/// </summary>
|
||||
public static short ReadInt16(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 2);
|
||||
return BitConverter.ToInt16(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int16 from the stream
|
||||
/// </summary>
|
||||
/// <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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt16 from the stream
|
||||
/// </summary>
|
||||
public static ushort ReadUInt16(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 2);
|
||||
return BitConverter.ToUInt16(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt16 from the stream
|
||||
/// </summary>
|
||||
/// <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);
|
||||
}
|
||||
|
||||
// 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>
|
||||
public static Half ReadHalf(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 2);
|
||||
return BitConverter.ToHalf(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Half from the stream
|
||||
/// </summary>
|
||||
/// <remarks>Reads in big-endian format</remarks>
|
||||
public static Half ReadHalfBigEndian(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 2);
|
||||
Array.Reverse(buffer);
|
||||
return BitConverter.ToHalf(buffer, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int24 encoded as an Int32
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int24 encoded as an Int32
|
||||
/// </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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt24 encoded as a UInt32
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt24 encoded as a UInt32
|
||||
/// </summary>
|
||||
/// <remarks>Reads in big-endian format</remarks>
|
||||
public static uint ReadUInt24BigEndian(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 3);
|
||||
Array.Reverse(buffer);
|
||||
|
||||
byte[] padded = new byte[4];
|
||||
Array.Copy(buffer, padded, 3);
|
||||
return BitConverter.ToUInt32(padded, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int32 from the stream
|
||||
/// </summary>
|
||||
public static int ReadInt32(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 4);
|
||||
return BitConverter.ToInt32(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int32 from the stream
|
||||
/// </summary>
|
||||
/// <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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt32 from the stream
|
||||
/// </summary>
|
||||
public static uint ReadUInt32(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 4);
|
||||
return BitConverter.ToUInt32(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt32 from the stream
|
||||
/// </summary>
|
||||
/// <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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Single from the stream
|
||||
/// </summary>
|
||||
public static float ReadSingle(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 4);
|
||||
return BitConverter.ToSingle(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Single from the stream
|
||||
/// </summary>
|
||||
/// <remarks>Reads in big-endian format</remarks>
|
||||
public static float ReadSingleBigEndian(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 4);
|
||||
Array.Reverse(buffer);
|
||||
return BitConverter.ToSingle(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int48 encoded as an Int64
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int48 encoded as an Int64
|
||||
/// </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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt48 encoded as a UInt64
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt48 encoded as a UInt64
|
||||
/// </summary>
|
||||
/// <remarks>Reads in big-endian format</remarks>
|
||||
public static ulong ReadUInt48BigEndian(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 6);
|
||||
Array.Reverse(buffer);
|
||||
|
||||
byte[] padded = new byte[8];
|
||||
Array.Copy(buffer, padded, 6);
|
||||
return BitConverter.ToUInt64(padded, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int64 from the stream
|
||||
/// </summary>
|
||||
public static long ReadInt64(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 8);
|
||||
return BitConverter.ToInt64(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int64 from the stream
|
||||
/// </summary>
|
||||
/// <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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt64 from the stream
|
||||
/// </summary>
|
||||
public static ulong ReadUInt64(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 8);
|
||||
return BitConverter.ToUInt64(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt64 from the stream
|
||||
/// </summary>
|
||||
/// <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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Double from the stream
|
||||
/// </summary>
|
||||
public static double ReadDouble(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 8);
|
||||
return BitConverter.ToDouble(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Double from the stream
|
||||
/// </summary>
|
||||
/// <remarks>Reads in big-endian format</remarks>
|
||||
public static double ReadDoubleBigEndian(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 8);
|
||||
Array.Reverse(buffer);
|
||||
return BitConverter.ToDouble(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Decimal from the stream
|
||||
/// </summary>
|
||||
public static decimal ReadDecimal(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 16);
|
||||
|
||||
int lo = BitConverter.ToInt32(buffer, 0);
|
||||
int mid = BitConverter.ToInt32(buffer, 4);
|
||||
int hi = BitConverter.ToInt32(buffer, 8);
|
||||
int flags = BitConverter.ToInt32(buffer, 12);
|
||||
|
||||
return new decimal([lo, mid, hi, flags]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Decimal from the stream
|
||||
/// </summary>
|
||||
/// <remarks>Reads in big-endian format</remarks>
|
||||
public static decimal ReadDecimalBigEndian(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 16);
|
||||
Array.Reverse(buffer);
|
||||
|
||||
int lo = BitConverter.ToInt32(buffer, 0);
|
||||
int mid = BitConverter.ToInt32(buffer, 4);
|
||||
int hi = BitConverter.ToInt32(buffer, 8);
|
||||
int flags = BitConverter.ToInt32(buffer, 12);
|
||||
|
||||
return new decimal([lo, mid, hi, flags]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Guid from the stream
|
||||
/// </summary>
|
||||
public static Guid ReadGuid(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 16);
|
||||
return new Guid(buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Guid from the stream
|
||||
/// </summary>
|
||||
/// <remarks>Reads in big-endian format</remarks>
|
||||
public static Guid ReadGuidBigEndian(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 16);
|
||||
Array.Reverse(buffer);
|
||||
return new Guid(buffer);
|
||||
}
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
/// <summary>
|
||||
/// Read an Int128 from the stream
|
||||
/// </summary>
|
||||
public static Int128 ReadInt128(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 16);
|
||||
return (Int128)new BigInteger(buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an Int128 from the stream
|
||||
/// </summary>
|
||||
/// <remarks>Reads in big-endian format</remarks>
|
||||
public static Int128 ReadInt128BigEndian(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 16);
|
||||
Array.Reverse(buffer);
|
||||
return (Int128)new BigInteger(buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt128 from the stream
|
||||
/// </summary>
|
||||
public static UInt128 ReadUInt128(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 16);
|
||||
return (UInt128)new BigInteger(buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt128 from the stream
|
||||
/// </summary>
|
||||
/// <remarks>Reads in big-endian format</remarks>
|
||||
public static UInt128 ReadUInt128BigEndian(this Stream stream)
|
||||
{
|
||||
byte[] buffer = ReadToBuffer(stream, 16);
|
||||
Array.Reverse(buffer);
|
||||
return (UInt128)new BigInteger(buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Read a null-terminated string from the stream
|
||||
/// </summary>
|
||||
public static string? ReadNullTerminatedString(this Stream stream, Encoding encoding)
|
||||
{
|
||||
// Short-circuit to explicit implementations
|
||||
if (encoding.Equals(Encoding.ASCII))
|
||||
return stream.ReadNullTerminatedAnsiString();
|
||||
else if (encoding.Equals(Encoding.Unicode))
|
||||
return stream.ReadNullTerminatedUnicodeString();
|
||||
|
||||
if (stream.Position >= stream.Length)
|
||||
return null;
|
||||
|
||||
List<byte> buffer = [];
|
||||
while (stream.Position < stream.Length)
|
||||
{
|
||||
byte ch = stream.ReadByteValue();
|
||||
buffer.Add(ch);
|
||||
if (ch == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
return encoding.GetString([.. buffer]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a null-terminated ASCII string from the stream
|
||||
/// </summary>
|
||||
public static string? ReadNullTerminatedAnsiString(this Stream stream)
|
||||
{
|
||||
if (stream.Position >= stream.Length)
|
||||
return null;
|
||||
|
||||
List<byte> buffer = [];
|
||||
while (stream.Position < stream.Length)
|
||||
{
|
||||
byte ch = stream.ReadByteValue();
|
||||
buffer.Add(ch);
|
||||
if (ch == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
return Encoding.ASCII.GetString([.. buffer]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a null-terminated Unicode string from the stream
|
||||
/// </summary>
|
||||
public static string? ReadNullTerminatedUnicodeString(this Stream stream)
|
||||
{
|
||||
if (stream.Position >= stream.Length)
|
||||
return null;
|
||||
|
||||
List<byte> buffer = [];
|
||||
while (stream.Position < stream.Length)
|
||||
{
|
||||
byte[] ch = stream.ReadBytes(2);
|
||||
buffer.AddRange(ch);
|
||||
if (ch[0] == '\0' && ch[1] == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
return Encoding.Unicode.GetString([.. buffer]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a byte-prefixed ASCII string from the stream
|
||||
/// </summary>
|
||||
public static string? ReadPrefixedAnsiString(this Stream stream)
|
||||
{
|
||||
if (stream.Position >= stream.Length)
|
||||
return null;
|
||||
|
||||
byte size = stream.ReadByteValue();
|
||||
if (stream.Position + size >= stream.Length)
|
||||
return null;
|
||||
|
||||
byte[] buffer = stream.ReadBytes(size);
|
||||
return Encoding.ASCII.GetString(buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a ushort-prefixed Unicode string from the stream
|
||||
/// </summary>
|
||||
public static string? ReadPrefixedUnicodeString(this Stream stream)
|
||||
{
|
||||
if (stream.Position >= stream.Length)
|
||||
return null;
|
||||
|
||||
ushort size = stream.ReadUInt16();
|
||||
if (stream.Position + size >= stream.Length)
|
||||
return null;
|
||||
|
||||
byte[] buffer = stream.ReadBytes(size);
|
||||
return Encoding.Unicode.GetString(buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a string that is terminated by a newline but contains a quoted portion that
|
||||
/// may also contain a newline from the stream
|
||||
/// </summary>
|
||||
public static string? ReadQuotedString(this Stream stream)
|
||||
=> stream.ReadQuotedString(Encoding.Default);
|
||||
|
||||
/// <summary>
|
||||
/// Read a string that is terminated by a newline but contains a quoted portion that
|
||||
/// may also contain a newline from the stream
|
||||
/// </summary>
|
||||
public static string? ReadQuotedString(this Stream stream, Encoding encoding)
|
||||
{
|
||||
if (stream.Position >= stream.Length)
|
||||
return null;
|
||||
|
||||
var bytes = new List<byte>();
|
||||
bool openQuote = false;
|
||||
while (stream.Position < stream.Length)
|
||||
{
|
||||
// Read the byte value
|
||||
byte b = stream.ReadByteValue();
|
||||
|
||||
// If we have a quote, flip the flag
|
||||
if (b == (byte)'"')
|
||||
openQuote = !openQuote;
|
||||
|
||||
// If we have a newline not in a quoted string, exit the loop
|
||||
else if (b == (byte)'\n' && !openQuote)
|
||||
break;
|
||||
|
||||
// Add the byte to the set
|
||||
bytes.Add(b);
|
||||
}
|
||||
|
||||
var line = encoding.GetString([.. bytes]);
|
||||
return line.TrimEnd();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a <typeparamref name="T"/> from the stream
|
||||
/// </summary>
|
||||
public static T? ReadType<T>(this Stream stream)
|
||||
{
|
||||
int typeSize = Marshal.SizeOf(typeof(T));
|
||||
byte[] buffer = ReadToBuffer(stream, typeSize);
|
||||
|
||||
var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
|
||||
var data = (T?)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
|
||||
handle.Free();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a number of bytes from the stream to a buffer
|
||||
/// </summary>
|
||||
private static byte[] ReadToBuffer(Stream stream, int length)
|
||||
{
|
||||
// If we have an invalid length
|
||||
if (length < 0)
|
||||
throw new ArgumentOutOfRangeException($"{nameof(length)} must be 0 or a positive value");
|
||||
|
||||
// Handle the 0-byte case
|
||||
if (length == 0)
|
||||
return [];
|
||||
|
||||
// Handle the general case, forcing a read of the correct length
|
||||
byte[] buffer = new byte[length];
|
||||
int read = stream.Read(buffer, 0, length);
|
||||
if (read < length)
|
||||
throw new EndOfStreamException(nameof(stream));
|
||||
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
602
SabreTools.IO/Extensions/StreamWriterExtensions.cs
Normal file
602
SabreTools.IO/Extensions/StreamWriterExtensions.cs
Normal file
@@ -0,0 +1,602 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
#if NET7_0_OR_GREATER
|
||||
using System.Numerics;
|
||||
#endif
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace SabreTools.IO.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions for Streams
|
||||
/// </summary>
|
||||
/// TODO: Handle proper negative values for Int24 and Int48
|
||||
public static class StreamWriterExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Write a UInt8
|
||||
/// </summary>
|
||||
public static bool Write(this Stream stream, byte value)
|
||||
=> WriteFromBuffer(stream, [value]);
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt8[]
|
||||
/// </summary>
|
||||
public static bool Write(this Stream stream, byte[] value)
|
||||
=> WriteFromBuffer(stream, value);
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt8[]
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this Stream stream, byte[] value)
|
||||
{
|
||||
Array.Reverse(value);
|
||||
return WriteFromBuffer(stream, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int8
|
||||
/// </summary>
|
||||
public static bool Write(this Stream stream, sbyte value)
|
||||
=> WriteFromBuffer(stream, [(byte)value]);
|
||||
|
||||
/// <summary>
|
||||
/// Write a Char
|
||||
/// </summary>
|
||||
public static bool Write(this Stream stream, char value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a Char with an Encoding
|
||||
/// </summary>
|
||||
public static bool Write(this Stream stream, char value, Encoding encoding)
|
||||
{
|
||||
byte[] buffer = encoding.GetBytes($"{value}");
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int16
|
||||
/// </summary>
|
||||
public static bool Write(this Stream stream, short value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int16
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this Stream stream, short value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt16
|
||||
/// </summary>
|
||||
public static bool Write(this Stream stream, ushort value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt16
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this Stream stream, ushort value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
// Half was introduced in net5.0 but doesn't have a BitConverter implementation until net6.0
|
||||
#if NET6_0_OR_GREATER
|
||||
/// <summary>
|
||||
/// Write a Half
|
||||
/// </summary>
|
||||
public static bool Write(this Stream stream, Half value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a Half
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this Stream stream, Half value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int32 as an Int24
|
||||
/// </summary>
|
||||
/// <remarks>Throws away top byte</remarks>
|
||||
public static bool WriteAsInt24(this Stream stream, int value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
|
||||
byte[] reduced = new byte[3];
|
||||
Array.Copy(buffer, reduced, 3);
|
||||
return WriteFromBuffer(stream, reduced);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int32 as an Int24
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
/// <remarks>Throws away top byte</remarks>
|
||||
public static bool WriteAsInt24BigEndian(this Stream stream, int value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
|
||||
byte[] reduced = new byte[3];
|
||||
Array.Copy(buffer, 1, reduced, 0, 3);
|
||||
return WriteFromBuffer(stream, reduced);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt32 as a UInt24
|
||||
/// </summary>
|
||||
/// <remarks>Throws away top byte</remarks>
|
||||
public static bool WriteAsUInt24(this Stream stream, uint value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
|
||||
byte[] reduced = new byte[3];
|
||||
Array.Copy(buffer, reduced, 3);
|
||||
return WriteFromBuffer(stream, reduced);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt32 as a UInt24
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
/// <remarks>Throws away top byte</remarks>
|
||||
public static bool WriteAsUInt24BigEndian(this Stream stream, uint value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
|
||||
byte[] reduced = new byte[3];
|
||||
Array.Copy(buffer, 1, reduced, 0, 3);
|
||||
return WriteFromBuffer(stream, reduced);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int32
|
||||
/// </summary>
|
||||
public static bool Write(this Stream stream, int value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int32
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this Stream stream, int value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt32
|
||||
/// </summary>
|
||||
public static bool Write(this Stream stream, uint value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt32
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this Stream stream, uint value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a Single
|
||||
/// </summary>
|
||||
public static bool Write(this Stream stream, float value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a Single
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this Stream stream, float value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int64 as an Int48
|
||||
/// </summary>
|
||||
/// <remarks>Throws away top 2 bytes</remarks>
|
||||
public static bool WriteAsInt48(this Stream stream, long value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
|
||||
byte[] reduced = new byte[6];
|
||||
Array.Copy(buffer, reduced, 6);
|
||||
return WriteFromBuffer(stream, reduced);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int64 as an Int48
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
/// <remarks>Throws away top 2 bytes</remarks>
|
||||
public static bool WriteAsInt48BigEndian(this Stream stream, long value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
|
||||
byte[] reduced = new byte[6];
|
||||
Array.Copy(buffer, 2, reduced, 0, 6);
|
||||
return WriteFromBuffer(stream, reduced);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt64 as a UInt48
|
||||
/// </summary>
|
||||
/// <remarks>Throws away top 2 bytes</remarks>
|
||||
public static bool WriteAsUInt48(this Stream stream, ulong value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
|
||||
byte[] reduced = new byte[6];
|
||||
Array.Copy(buffer, reduced, 6);
|
||||
return WriteFromBuffer(stream, reduced);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt64 as a UInt48
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
/// <remarks>Throws away top 2 bytes</remarks>
|
||||
public static bool WriteAsUInt48BigEndian(this Stream stream, ulong value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
|
||||
byte[] reduced = new byte[6];
|
||||
Array.Copy(buffer, 2, reduced, 0, 6);
|
||||
return WriteFromBuffer(stream, reduced);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int64
|
||||
/// </summary>
|
||||
public static bool Write(this Stream stream, long value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int64
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this Stream stream, long value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt64
|
||||
/// </summary>
|
||||
public static bool Write(this Stream stream, ulong value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt64
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this Stream stream, ulong value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a Double
|
||||
/// </summary>
|
||||
public static bool Write(this Stream stream, double value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a Double
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this Stream stream, double value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a Decimal and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static bool Write(this Stream stream, decimal value)
|
||||
{
|
||||
int[] bits = decimal.GetBits(value);
|
||||
|
||||
byte[] lo = BitConverter.GetBytes(bits[0]);
|
||||
byte[] mid = BitConverter.GetBytes(bits[1]);
|
||||
byte[] hi = BitConverter.GetBytes(bits[2]);
|
||||
byte[] flags = BitConverter.GetBytes(bits[3]);
|
||||
|
||||
byte[] buffer = new byte[16];
|
||||
Array.Copy(lo, 0, buffer, 0, 4);
|
||||
Array.Copy(mid, 0, buffer, 4, 4);
|
||||
Array.Copy(hi, 0, buffer, 8, 4);
|
||||
Array.Copy(flags, 0, buffer, 12, 4);
|
||||
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a Decimal and increment the pointer to an array
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this Stream stream, decimal value)
|
||||
{
|
||||
int[] bits = decimal.GetBits(value);
|
||||
|
||||
byte[] lo = BitConverter.GetBytes(bits[0]);
|
||||
byte[] mid = BitConverter.GetBytes(bits[1]);
|
||||
byte[] hi = BitConverter.GetBytes(bits[2]);
|
||||
byte[] flags = BitConverter.GetBytes(bits[3]);
|
||||
|
||||
byte[] buffer = new byte[16];
|
||||
Array.Copy(lo, 0, buffer, 0, 4);
|
||||
Array.Copy(mid, 0, buffer, 4, 4);
|
||||
Array.Copy(hi, 0, buffer, 8, 4);
|
||||
Array.Copy(flags, 0, buffer, 12, 4);
|
||||
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a Guid
|
||||
/// </summary>
|
||||
public static bool Write(this Stream stream, Guid value)
|
||||
{
|
||||
byte[] buffer = value.ToByteArray();
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a Guid
|
||||
/// </summary>
|
||||
/// <remarks>Writes in big-endian format</remarks>
|
||||
public static bool WriteBigEndian(this Stream stream, Guid value)
|
||||
{
|
||||
byte[] buffer = value.ToByteArray();
|
||||
Array.Reverse(buffer);
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
/// <summary>
|
||||
/// Write an Int128
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an Int128
|
||||
/// </summary>
|
||||
/// <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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt128
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a UInt128
|
||||
/// </summary>
|
||||
/// <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);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Write a null-terminated string to the stream
|
||||
/// </summary>
|
||||
public static bool WriteNullTerminatedString(this Stream stream, string? value, Encoding encoding)
|
||||
{
|
||||
// If the value is null
|
||||
if (value == null)
|
||||
return false;
|
||||
|
||||
// Add the null terminator and write
|
||||
value += "\0";
|
||||
byte[] buffer = encoding.GetBytes(value);
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a null-terminated ASCII string to the stream
|
||||
/// </summary>
|
||||
public static bool WriteNullTerminatedAnsiString(this Stream stream, string? value)
|
||||
=> stream.WriteNullTerminatedString(value, Encoding.ASCII);
|
||||
|
||||
/// <summary>
|
||||
/// Write a null-terminated Unicode string to the stream
|
||||
/// </summary>
|
||||
public static bool WriteNullTerminatedUnicodeString(this Stream stream, string? value)
|
||||
=> stream.WriteNullTerminatedString(value, Encoding.Unicode);
|
||||
|
||||
/// <summary>
|
||||
/// Write a byte-prefixed ASCII string to the stream
|
||||
/// </summary>
|
||||
public static bool WritePrefixedAnsiString(this Stream stream, string? value)
|
||||
{
|
||||
// If the value is null
|
||||
if (value == null)
|
||||
return false;
|
||||
|
||||
// Get the buffer
|
||||
byte[] buffer = Encoding.ASCII.GetBytes(value);
|
||||
|
||||
// Write the length as a byte
|
||||
if (!stream.Write((byte)buffer.Length))
|
||||
return false;
|
||||
|
||||
// Write the buffer
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a ushort-prefixed Unicode string to the stream
|
||||
/// </summary>
|
||||
public static bool WritePrefixedUnicodeString(this Stream stream, string? value)
|
||||
{
|
||||
// If the value is null
|
||||
if (value == null)
|
||||
return false;
|
||||
|
||||
// Get the buffer
|
||||
byte[] buffer = Encoding.Unicode.GetBytes(value);
|
||||
|
||||
// Write the length as a ushort
|
||||
if (!stream.Write((ushort)buffer.Length))
|
||||
return false;
|
||||
|
||||
// Write the buffer
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a string that is terminated by a newline but contains a quoted portion that
|
||||
/// may also contain a newline to the stream
|
||||
/// </summary>
|
||||
public static bool WriteQuotedString(this Stream stream, string? value)
|
||||
=> stream.WriteQuotedString(value, Encoding.UTF8);
|
||||
|
||||
/// <summary>
|
||||
/// Write a string that is terminated by a newline but contains a quoted portion that
|
||||
/// may also contain a newline to the stream
|
||||
/// </summary>
|
||||
public static bool WriteQuotedString(this Stream stream, string? value, Encoding encoding)
|
||||
{
|
||||
// If the value is null
|
||||
if (value == null)
|
||||
return false;
|
||||
|
||||
// Write without the null terminator
|
||||
byte[] buffer = encoding.GetBytes(value);
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a <typeparamref name="T"/> to the stream
|
||||
/// </summary>
|
||||
public static bool WriteType<T>(this Stream stream, T? value)
|
||||
{
|
||||
// Handle the null case
|
||||
if (value == null)
|
||||
return false;
|
||||
|
||||
int typeSize = Marshal.SizeOf(typeof(T));
|
||||
|
||||
var buffer = new byte[typeSize];
|
||||
var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
|
||||
Marshal.StructureToPtr(value, handle.AddrOfPinnedObject(), false);
|
||||
handle.Free();
|
||||
|
||||
return WriteFromBuffer(stream, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write an array of bytes to the stream
|
||||
/// </summary>
|
||||
private static bool WriteFromBuffer(Stream stream, byte[] value)
|
||||
{
|
||||
// If the stream is not writable
|
||||
if (!stream.CanWrite)
|
||||
return false;
|
||||
|
||||
// Handle the 0-byte case
|
||||
if (value.Length == 0)
|
||||
return true;
|
||||
|
||||
// Handle the general case, forcing a write of the correct length
|
||||
stream.Write(value, 0, value.Length);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>1.4.0</Version>
|
||||
<Version>1.4.5</Version>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski</Authors>
|
||||
|
||||
Reference in New Issue
Block a user