Update reader extensions and add tests

This commit is contained in:
Matt Nadareski
2024-11-25 15:03:07 -05:00
parent fa9310de39
commit 7656734bb2
9 changed files with 505 additions and 137 deletions

View File

@@ -4,12 +4,12 @@ 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 string reading tests
public class BinaryReaderExtensionsTests
{
/// <summary>
@@ -30,6 +30,50 @@ namespace SabreTools.IO.Test.Extensions
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00,
];
[Fact]
public void ReadByteArrayTest()
{
byte[] arr = new byte[4];
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
int read = br.Read(arr, 0, 4);
Assert.Equal(4, read);
Assert.True(arr.SequenceEqual(_bytes.Take(4)));
}
[Fact]
public void ReadByteArrayBigEndianTest()
{
byte[] arr = new byte[4];
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
int read = br.ReadBigEndian(arr, 0, 4);
Assert.Equal(4, read);
Assert.True(arr.SequenceEqual(_bytes.Take(4).Reverse()));
}
[Fact]
public void ReadCharArrayTest()
{
char[] arr = new char[4];
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
int read = br.Read(arr, 0, 4);
Assert.Equal(4, read);
Assert.True(arr.SequenceEqual(_bytes.Take(4).Select(b => (char)b)));
}
[Fact]
public void ReadCharArrayBigEndianTest()
{
char[] arr = new char[4];
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
int read = br.ReadBigEndian(arr, 0, 4);
Assert.Equal(4, read);
Assert.True(arr.SequenceEqual(_bytes.Take(4).Select(b => (char)b).Reverse()));
}
[Fact]
public void ReadByteTest()
{
@@ -50,6 +94,39 @@ namespace SabreTools.IO.Test.Extensions
Assert.True(read.SequenceEqual(_bytes.Take(length)));
}
[Fact]
public void ReadBytesBigEndianTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
int length = 4;
byte[] read = br.ReadBytesBigEndian(length);
Assert.Equal(length, read.Length);
Assert.True(read.SequenceEqual(_bytes.Take(length).Reverse()));
}
[Fact]
public void ReadCharsTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
int length = 4;
char[] read = br.ReadChars(length);
Assert.Equal(length, read.Length);
Assert.True(read.SequenceEqual(_bytes.Take(length).Select(b => (char)b)));
}
[Fact]
public void ReadCharsBigEndianTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
int length = 4;
char[] read = br.ReadCharsBigEndian(length);
Assert.Equal(length, read.Length);
Assert.True(read.SequenceEqual(_bytes.Take(length).Select(b => (char)b).Reverse()));
}
[Fact]
public void ReadSByteTest()
{
@@ -104,6 +181,24 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0x0001, read);
}
[Fact]
public void ReadWORDTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
ushort read = br.ReadWORD();
Assert.Equal(0x0100, read);
}
[Fact]
public void ReadWORDBigEndianTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
ushort read = br.ReadWORDBigEndian();
Assert.Equal(0x0001, read);
}
#if NET6_0_OR_GREATER
[Fact]
public void ReadHalfTest()
@@ -198,6 +293,24 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal((uint)0x00010203, read);
}
[Fact]
public void ReadDWORDTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
uint read = br.ReadDWORD();
Assert.Equal((uint)0x03020100, read);
}
[Fact]
public void ReadDWORDBigEndianTest()
{
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
uint read = br.ReadDWORDBigEndian();
Assert.Equal((uint)0x00010203, read);
}
[Fact]
public void ReadSingleTest()
{
@@ -394,6 +507,88 @@ namespace SabreTools.IO.Test.Extensions
}
#endif
[Fact]
public void ReadNullTerminatedStringTest()
{
// Encoding.ASCII
byte[] bytes = [0x41, 0x42, 0x43, 0x00];
var stream = new MemoryStream(bytes);
var br = new BinaryReader(stream);
string? actual = br.ReadNullTerminatedString(Encoding.ASCII);
Assert.Equal("ABC", actual);
// Encoding.UTF8
bytes = [0x41, 0x42, 0x43, 0x00];
stream = new MemoryStream(bytes);
br = new BinaryReader(stream);
actual = br.ReadNullTerminatedString(Encoding.UTF8);
Assert.Equal("ABC", actual);
// Encoding.Unicode
bytes = [0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x00, 0x00];
stream = new MemoryStream(bytes);
br = new BinaryReader(stream);
actual = br.ReadNullTerminatedString(Encoding.Unicode);
Assert.Equal("ABC", actual);
// Encoding.UTF32
bytes = [0x41, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
stream = new MemoryStream(bytes);
br = new BinaryReader(stream);
actual = br.ReadNullTerminatedString(Encoding.UTF32);
Assert.Equal("ABC", actual);
// Encoding.Latin1
bytes = [0x41, 0x42, 0x43, 0x00];
stream = new MemoryStream(bytes);
br = new BinaryReader(stream);
actual = br.ReadNullTerminatedString(Encoding.Latin1);
Assert.Equal("ABC", actual);
}
[Fact]
public void ReadTypeTest()
{
// Guid
var stream = new MemoryStream(_bytes);
var br = new BinaryReader(stream);
var expectedGuid = new Guid(_bytes);
Guid actualGuid = br.ReadType<Guid>();
Assert.Equal(expectedGuid, actualGuid);
#if NET6_0_OR_GREATER
// Half
stream = new MemoryStream(_bytes);
br = new BinaryReader(stream);
Half expectedHalf = BitConverter.Int16BitsToHalf(0x0100);
Half actualHalf = br.ReadType<Half>();
Assert.Equal(expectedHalf, actualHalf);
#endif
#if NET7_0_OR_GREATER
// Int128
stream = new MemoryStream(_bytes);
br = new BinaryReader(stream);
Int128 expectedInt128 = (Int128)new BigInteger(_bytes);
Int128 actualInt128 = br.ReadType<Int128>();
Assert.Equal(expectedHalf, actualHalf);
// UInt128
stream = new MemoryStream(_bytes);
br = new BinaryReader(stream);
UInt128 expectedUInt128 = (UInt128)new BigInteger(_bytes);
UInt128 actualUInt128 = br.ReadType<UInt128>();
Assert.Equal(expectedHalf, actualHalf);
#endif
// Enum
stream = new MemoryStream(_bytes);
br = new BinaryReader(stream);
TestEnum expectedTestEnum = (TestEnum)0x03020100;
TestEnum actualTestEnum = br.ReadType<TestEnum>();
Assert.Equal(expectedTestEnum, actualTestEnum);
}
[Fact]
public void ReadTypeExplicitTest()
{
@@ -492,6 +687,12 @@ namespace SabreTools.IO.Test.Extensions
0x05, 0x04, 0x03, 0x02,
0x06, 0x05, 0x04, 0x03,
// Enum Array
0x03, 0x02, 0x01, 0x00,
0x04, 0x03, 0x02, 0x01,
0x05, 0x04, 0x03, 0x02,
0x06, 0x05, 0x04, 0x03,
// Struct Array (X, Y)
0xFF, 0x00, 0x00, 0xFF,
0x00, 0xFF, 0xFF, 0x00,
@@ -509,6 +710,13 @@ namespace SabreTools.IO.Test.Extensions
{
ByteArray = [0x00, 0x01, 0x02, 0x03],
IntArray = [0x00010203, 0x01020304, 0x02030405, 0x03040506],
EnumArray =
[
(TestEnum)0x00010203,
(TestEnum)0x01020304,
(TestEnum)0x02030405,
(TestEnum)0x03040506,
],
StructArray =
[
new TestStructPoint { X = 0x00FF, Y = 0xFF00 },
@@ -524,6 +732,8 @@ namespace SabreTools.IO.Test.Extensions
Assert.True(expected.ByteArray.SequenceEqual(read.ByteArray));
Assert.NotNull(read.IntArray);
Assert.True(expected.IntArray.SequenceEqual(read.IntArray));
Assert.NotNull(read.EnumArray);
Assert.True(expected.EnumArray.SequenceEqual(read.EnumArray));
Assert.NotNull(read.StructArray);
Assert.True(expected.StructArray.SequenceEqual(read.StructArray));
Assert.Equal(expected.LPByteArrayLength, read.LPByteArrayLength);

View File

@@ -3,13 +3,13 @@ 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 string reading tests
public class ByteArrayExtensionsReadTests
public class ByteArrayReaderExtensionsTests
{
/// <summary>
/// Test pattern from 0x00-0x0F
@@ -102,6 +102,22 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0x0001, read);
}
[Fact]
public void ReadWORDTest()
{
int offset = 0;
ushort read = _bytes.ReadWORD(ref offset);
Assert.Equal(0x0100, read);
}
[Fact]
public void ReadWORDBigEndianTest()
{
int offset = 0;
ushort read = _bytes.ReadWORDBigEndian(ref offset);
Assert.Equal(0x0001, read);
}
#if NET6_0_OR_GREATER
[Fact]
public void ReadHalfTest()
@@ -186,6 +202,22 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal((uint)0x00010203, read);
}
[Fact]
public void ReadDWORDTest()
{
int offset = 0;
uint read = _bytes.ReadDWORD(ref offset);
Assert.Equal((uint)0x03020100, read);
}
[Fact]
public void ReadDWORDBigEndianTest()
{
int offset = 0;
uint read = _bytes.ReadDWORDBigEndian(ref offset);
Assert.Equal((uint)0x00010203, read);
}
[Fact]
public void ReadSingleTest()
{
@@ -362,6 +394,78 @@ namespace SabreTools.IO.Test.Extensions
}
#endif
[Fact]
public void ReadNullTerminatedStringTest()
{
// Encoding.ASCII
int offset = 0;
byte[] bytes = [0x41, 0x42, 0x43, 0x00];
string? actual = bytes.ReadNullTerminatedString(ref offset, Encoding.ASCII);
Assert.Equal("ABC", actual);
// Encoding.UTF8
offset = 0;
bytes = [0x41, 0x42, 0x43, 0x00];
actual = bytes.ReadNullTerminatedString(ref offset, Encoding.UTF8);
Assert.Equal("ABC", actual);
// Encoding.Unicode
offset = 0;
bytes = [0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x00, 0x00];
actual = bytes.ReadNullTerminatedString(ref offset, Encoding.Unicode);
Assert.Equal("ABC", actual);
// Encoding.UTF32
offset = 0;
bytes = [0x41, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
actual = bytes.ReadNullTerminatedString(ref offset, Encoding.UTF32);
Assert.Equal("ABC", actual);
// Encoding.Latin1
offset = 0;
bytes = [0x41, 0x42, 0x43, 0x00];
actual = bytes.ReadNullTerminatedString(ref offset, Encoding.Latin1);
Assert.Equal("ABC", actual);
}
[Fact]
public void ReadTypeTest()
{
// Guid
int offset = 0;
var expectedGuid = new Guid(_bytes);
Guid actualGuid = _bytes.ReadType<Guid>(ref offset);
Assert.Equal(expectedGuid, actualGuid);
#if NET6_0_OR_GREATER
// Half
offset = 0;
Half expectedHalf = BitConverter.Int16BitsToHalf(0x0100);
Half actualHalf = _bytes.ReadType<Half>(ref offset);
Assert.Equal(expectedHalf, actualHalf);
#endif
#if NET7_0_OR_GREATER
// Int128
offset = 0;
Int128 expectedInt128 = (Int128)new BigInteger(_bytes);
Int128 actualInt128 = _bytes.ReadType<Int128>(ref offset);
Assert.Equal(expectedHalf, actualHalf);
// UInt128
offset = 0;
UInt128 expectedUInt128 = (UInt128)new BigInteger(_bytes);
UInt128 actualUInt128 = _bytes.ReadType<UInt128>(ref offset);
Assert.Equal(expectedHalf, actualHalf);
#endif
// Enum
offset = 0;
TestEnum expectedTestEnum = (TestEnum)0x03020100;
TestEnum actualTestEnum = _bytes.ReadType<TestEnum>(ref offset);
Assert.Equal(expectedTestEnum, actualTestEnum);
}
[Fact]
public void ReadTypeExplicitTest()
{
@@ -456,6 +560,12 @@ namespace SabreTools.IO.Test.Extensions
0x05, 0x04, 0x03, 0x02,
0x06, 0x05, 0x04, 0x03,
// Enum Array
0x03, 0x02, 0x01, 0x00,
0x04, 0x03, 0x02, 0x01,
0x05, 0x04, 0x03, 0x02,
0x06, 0x05, 0x04, 0x03,
// Struct Array (X, Y)
0xFF, 0x00, 0x00, 0xFF,
0x00, 0xFF, 0xFF, 0x00,
@@ -472,6 +582,13 @@ namespace SabreTools.IO.Test.Extensions
{
ByteArray = [0x00, 0x01, 0x02, 0x03],
IntArray = [0x00010203, 0x01020304, 0x02030405, 0x03040506],
EnumArray =
[
(TestEnum)0x00010203,
(TestEnum)0x01020304,
(TestEnum)0x02030405,
(TestEnum)0x03040506,
],
StructArray =
[
new TestStructPoint { X = 0x00FF, Y = 0xFF00 },
@@ -487,6 +604,8 @@ namespace SabreTools.IO.Test.Extensions
Assert.True(expected.ByteArray.SequenceEqual(read.ByteArray));
Assert.NotNull(read.IntArray);
Assert.True(expected.IntArray.SequenceEqual(read.IntArray));
Assert.NotNull(read.EnumArray);
Assert.True(expected.EnumArray.SequenceEqual(read.EnumArray));
Assert.NotNull(read.StructArray);
Assert.True(expected.StructArray.SequenceEqual(read.StructArray));
Assert.Equal(expected.LPByteArrayLength, read.LPByteArrayLength);

View File

@@ -9,7 +9,7 @@ using Xunit;
namespace SabreTools.IO.Test.Extensions
{
// TODO: Add string writing tests
public class ByteArrayExtensionsWriteTests
public class ByteArrayWriterExtensionsTests
{
/// <summary>
/// Test pattern from 0x00-0x0F

View File

@@ -4,13 +4,13 @@ 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 string reading tests
public class StreamExtensionsReadTests
public class StreamReaderExtensionsTests
{
/// <summary>
/// Test pattern from 0x00-0x0F
@@ -30,6 +30,16 @@ namespace SabreTools.IO.Test.Extensions
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00,
];
[Fact]
public void ReadByteArrayTest()
{
byte[] arr = new byte[4];
var stream = new MemoryStream(_bytes);
int read = stream.Read(arr, 0, 4);
Assert.Equal(4, read);
Assert.True(arr.SequenceEqual(_bytes.Take(4)));
}
[Fact]
public void ReadByteValueTest()
{
@@ -96,6 +106,22 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(0x0001, read);
}
[Fact]
public void ReadWORDTest()
{
var stream = new MemoryStream(_bytes);
ushort read = stream.ReadWORD();
Assert.Equal(0x0100, read);
}
[Fact]
public void ReadWORDBigEndianTest()
{
var stream = new MemoryStream(_bytes);
ushort read = stream.ReadWORDBigEndian();
Assert.Equal(0x0001, read);
}
#if NET6_0_OR_GREATER
[Fact]
public void ReadHalfTest()
@@ -180,6 +206,22 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal((uint)0x00010203, read);
}
[Fact]
public void ReadDWORDTest()
{
var stream = new MemoryStream(_bytes);
uint read = stream.ReadDWORD();
Assert.Equal((uint)0x03020100, read);
}
[Fact]
public void ReadDWORDBigEndianTest()
{
var stream = new MemoryStream(_bytes);
uint read = stream.ReadDWORDBigEndian();
Assert.Equal((uint)0x00010203, read);
}
[Fact]
public void ReadSingleTest()
{
@@ -356,6 +398,78 @@ namespace SabreTools.IO.Test.Extensions
}
#endif
[Fact]
public void ReadNullTerminatedStringTest()
{
// Encoding.ASCII
byte[] bytes = [0x41, 0x42, 0x43, 0x00];
var stream = new MemoryStream(bytes);
string? actual = stream.ReadNullTerminatedString(Encoding.ASCII);
Assert.Equal("ABC", actual);
// Encoding.UTF8
bytes = [0x41, 0x42, 0x43, 0x00];
stream = new MemoryStream(bytes);
actual = stream.ReadNullTerminatedString(Encoding.UTF8);
Assert.Equal("ABC", actual);
// Encoding.Unicode
bytes = [0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x00, 0x00];
stream = new MemoryStream(bytes);
actual = stream.ReadNullTerminatedString(Encoding.Unicode);
Assert.Equal("ABC", actual);
// Encoding.UTF32
bytes = [0x41, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
stream = new MemoryStream(bytes);
actual = stream.ReadNullTerminatedString(Encoding.UTF32);
Assert.Equal("ABC", actual);
// Encoding.Latin1
bytes = [0x41, 0x42, 0x43, 0x00];
stream = new MemoryStream(bytes);
actual = stream.ReadNullTerminatedString(Encoding.Latin1);
Assert.Equal("ABC", actual);
}
[Fact]
public void ReadTypeTest()
{
// Guid
var stream = new MemoryStream(_bytes);
var expectedGuid = new Guid(_bytes);
Guid actualGuid = stream.ReadType<Guid>();
Assert.Equal(expectedGuid, actualGuid);
#if NET6_0_OR_GREATER
// Half
stream = new MemoryStream(_bytes);
Half expectedHalf = BitConverter.Int16BitsToHalf(0x0100);
Half actualHalf = stream.ReadType<Half>();
Assert.Equal(expectedHalf, actualHalf);
#endif
#if NET7_0_OR_GREATER
// Int128
stream = new MemoryStream(_bytes);
Int128 expectedInt128 = (Int128)new BigInteger(_bytes);
Int128 actualInt128 = stream.ReadType<Int128>();
Assert.Equal(expectedHalf, actualHalf);
// UInt128
stream = new MemoryStream(_bytes);
UInt128 expectedUInt128 = (UInt128)new BigInteger(_bytes);
UInt128 actualUInt128 = stream.ReadType<UInt128>();
Assert.Equal(expectedHalf, actualHalf);
#endif
// Enum
stream = new MemoryStream(_bytes);
TestEnum expectedTestEnum = (TestEnum)0x03020100;
TestEnum actualTestEnum = stream.ReadType<TestEnum>();
Assert.Equal(expectedTestEnum, actualTestEnum);
}
[Fact]
public void ReadTypeExplicitTest()
{
@@ -450,6 +564,12 @@ namespace SabreTools.IO.Test.Extensions
0x05, 0x04, 0x03, 0x02,
0x06, 0x05, 0x04, 0x03,
// Enum Array
0x03, 0x02, 0x01, 0x00,
0x04, 0x03, 0x02, 0x01,
0x05, 0x04, 0x03, 0x02,
0x06, 0x05, 0x04, 0x03,
// Struct Array (X, Y)
0xFF, 0x00, 0x00, 0xFF,
0x00, 0xFF, 0xFF, 0x00,
@@ -466,6 +586,13 @@ namespace SabreTools.IO.Test.Extensions
{
ByteArray = [0x00, 0x01, 0x02, 0x03],
IntArray = [0x00010203, 0x01020304, 0x02030405, 0x03040506],
EnumArray =
[
(TestEnum)0x00010203,
(TestEnum)0x01020304,
(TestEnum)0x02030405,
(TestEnum)0x03040506,
],
StructArray =
[
new TestStructPoint { X = 0x00FF, Y = 0xFF00 },
@@ -481,6 +608,8 @@ namespace SabreTools.IO.Test.Extensions
Assert.True(expected.ByteArray.SequenceEqual(read.ByteArray));
Assert.NotNull(read.IntArray);
Assert.True(expected.IntArray.SequenceEqual(read.IntArray));
Assert.NotNull(read.EnumArray);
Assert.True(expected.EnumArray.SequenceEqual(read.EnumArray));
Assert.NotNull(read.StructArray);
Assert.True(expected.StructArray.SequenceEqual(read.StructArray));
Assert.Equal(expected.LPByteArrayLength, read.LPByteArrayLength);

View File

@@ -10,7 +10,7 @@ using Xunit;
namespace SabreTools.IO.Test.Extensions
{
// TODO: Add string writing tests
public class StreamExtensionsWriteTests
public class StreamWriterExtensionsTests
{
/// <summary>
/// Test pattern from 0x00-0x0F

View File

@@ -17,6 +17,12 @@ namespace SabreTools.IO.Test.Extensions
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public int[]? IntArray;
/// <summary>
/// 4 entry int array
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public TestEnum[]? EnumArray;
/// <summary>
/// 4 entry struct array
/// </summary>
@@ -31,7 +37,7 @@ namespace SabreTools.IO.Test.Extensions
/// <summary>
/// 4 entry byte array whose length is defined by <see cref="LPByteArrayLength"/>
/// </summary>
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)]
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)]
public byte[]? LPByteArray;
// /// <summary>

View File

@@ -365,9 +365,10 @@ namespace SabreTools.IO.Extensions
while (reader.BaseStream.Position < reader.BaseStream.Length)
{
byte ch = reader.ReadByte();
buffer.Add(ch);
if (ch == '\0')
break;
buffer.Add(ch);
}
return encoding.GetString([.. buffer]);
@@ -418,7 +419,7 @@ namespace SabreTools.IO.Extensions
return null;
byte[] buffer = ReadUntilNull4Byte(reader);
return Encoding.Unicode.GetString(buffer);
return Encoding.UTF32.GetString(buffer);
}
/// <summary>
@@ -453,45 +454,6 @@ namespace SabreTools.IO.Extensions
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 underlying stream
/// </summary>
public static string? ReadQuotedString(this BinaryReader reader)
=> reader.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 underlying stream
/// </summary>
public static string? ReadQuotedString(this BinaryReader reader, Encoding encoding)
{
if (reader.BaseStream.Position >= reader.BaseStream.Length)
return null;
var bytes = new List<byte>();
bool openQuote = false;
while (reader.BaseStream.Position < reader.BaseStream.Length)
{
// Read the byte value
byte b = reader.ReadByte();
// 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 underlying stream
/// </summary>
@@ -620,7 +582,10 @@ namespace SabreTools.IO.Extensions
else if (fi.FieldType.IsArray)
{
var value = ReadArrayType(reader, fields, instance, fi);
fi.SetValue(instance, Convert.ChangeType(value, fi.FieldType));
if (value.GetType() == fi.FieldType)
fi.SetValue(instance, value);
else
fi.SetValue(instance, Convert.ChangeType(value, fi.FieldType));
}
else
{
@@ -651,7 +616,10 @@ namespace SabreTools.IO.Extensions
for (int i = 0; i < elementCount; i++)
{
var value = ReadType(reader, elementType);
arr.SetValue(value, i);
if (value != null && elementType.IsEnum)
arr.SetValue(Enum.ToObject(elementType, value), i);
else
arr.SetValue(value, i);
}
// Return the built array

View File

@@ -494,9 +494,10 @@ namespace SabreTools.IO.Extensions
while (offset < content.Length)
{
byte ch = content.ReadByteValue(ref offset);
buffer.Add(ch);
if (ch == '\0')
break;
buffer.Add(ch);
}
return encoding.GetString([.. buffer]);
@@ -547,7 +548,7 @@ namespace SabreTools.IO.Extensions
return null;
byte[] buffer = ReadUntilNull4Byte(content, ref offset);
return Encoding.Unicode.GetString(buffer);
return Encoding.UTF32.GetString(buffer);
}
/// <summary>
@@ -582,45 +583,6 @@ namespace SabreTools.IO.Extensions
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 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 byte array
/// </summary>
public static string? ReadQuotedString(this byte[] content, ref int offset, Encoding encoding)
{
if (offset >= content.Length)
return null;
byte[] nullTerminator = encoding.GetBytes("\0");
int charWidth = nullTerminator.Length;
var keyChars = new List<char>();
bool openQuote = false;
while (offset < content.Length)
{
char c = encoding.GetChars(content, offset, charWidth)[0];
keyChars.Add(c);
offset += charWidth;
// If we have a quote, flip the flag
if (c == '"')
openQuote = !openQuote;
// If we have a newline not in a quoted string, exit the loop
else if (c == (byte)'\n' && !openQuote)
break;
}
return new string([.. keyChars]).TrimEnd();
}
/// <summary>
/// Read a <typeparamref name="T"/> from the stream
/// </summary>
@@ -749,7 +711,10 @@ namespace SabreTools.IO.Extensions
else if (fi.FieldType.IsArray)
{
var value = ReadArrayType(content, ref offset, fields, instance, fi);
fi.SetValue(instance, Convert.ChangeType(value, fi.FieldType));
if (value.GetType() == fi.FieldType)
fi.SetValue(instance, value);
else
fi.SetValue(instance, Convert.ChangeType(value, fi.FieldType));
}
else
{
@@ -780,7 +745,10 @@ namespace SabreTools.IO.Extensions
for (int i = 0; i < elementCount; i++)
{
var value = ReadType(content, ref offset, elementType);
arr.SetValue(value, i);
if (value != null && elementType.IsEnum)
arr.SetValue(Enum.ToObject(elementType, value), i);
else
arr.SetValue(value, i);
}
// Return the built array

View File

@@ -478,9 +478,10 @@ namespace SabreTools.IO.Extensions
while (stream.Position < stream.Length)
{
byte ch = stream.ReadByteValue();
buffer.Add(ch);
if (ch == '\0')
break;
buffer.Add(ch);
}
return encoding.GetString([.. buffer]);
@@ -531,7 +532,7 @@ namespace SabreTools.IO.Extensions
return null;
byte[] buffer = ReadUntilNull4Byte(stream);
return Encoding.Unicode.GetString(buffer);
return Encoding.UTF32.GetString(buffer);
}
/// <summary>
@@ -566,45 +567,6 @@ namespace SabreTools.IO.Extensions
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>
@@ -733,7 +695,10 @@ namespace SabreTools.IO.Extensions
else if (fi.FieldType.IsArray)
{
var value = ReadArrayType(stream, fields, instance, fi);
fi.SetValue(instance, Convert.ChangeType(value, fi.FieldType));
if (value.GetType() == fi.FieldType)
fi.SetValue(instance, value);
else
fi.SetValue(instance, Convert.ChangeType(value, fi.FieldType));
}
else
{
@@ -764,7 +729,10 @@ namespace SabreTools.IO.Extensions
for (int i = 0; i < elementCount; i++)
{
var value = ReadType(stream, elementType);
arr.SetValue(value, i);
if (value != null && elementType.IsEnum)
arr.SetValue(Enum.ToObject(elementType, value), i);
else
arr.SetValue(value, i);
}
// Return the built array