From 7656734bb2c08cf337fa17099562fe224e68fcac Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Mon, 25 Nov 2024 15:03:07 -0500 Subject: [PATCH] Update reader extensions and add tests --- .../Extensions/BinaryReaderExtensionsTests.cs | 212 +++++++++++++++++- ...s.cs => ByteArrayReaderExtensionsTests.cs} | 123 +++++++++- ...s.cs => ByteArrayWriterExtensionsTests.cs} | 2 +- ...ests.cs => StreamReaderExtensionsTests.cs} | 133 ++++++++++- ...ests.cs => StreamWriterExtensionsTests.cs} | 2 +- .../Extensions/TestStructArrays.cs | 8 +- .../Extensions/BinaryReaderExtensions.cs | 54 +---- .../Extensions/ByteArrayReaderExtensions.cs | 54 +---- .../Extensions/StreamReaderExtensions.cs | 54 +---- 9 files changed, 505 insertions(+), 137 deletions(-) rename SabreTools.IO.Test/Extensions/{ByteArrayExtensionsReadTests.cs => ByteArrayReaderExtensionsTests.cs} (80%) rename SabreTools.IO.Test/Extensions/{ByteArrayExtensionsWriteTests.cs => ByteArrayWriterExtensionsTests.cs} (99%) rename SabreTools.IO.Test/Extensions/{StreamExtensionsReadTests.cs => StreamReaderExtensionsTests.cs} (79%) rename SabreTools.IO.Test/Extensions/{StreamExtensionsWriteTests.cs => StreamWriterExtensionsTests.cs} (99%) diff --git a/SabreTools.IO.Test/Extensions/BinaryReaderExtensionsTests.cs b/SabreTools.IO.Test/Extensions/BinaryReaderExtensionsTests.cs index c74009a..0154e65 100644 --- a/SabreTools.IO.Test/Extensions/BinaryReaderExtensionsTests.cs +++ b/SabreTools.IO.Test/Extensions/BinaryReaderExtensionsTests.cs @@ -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 { /// @@ -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(); + 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(); + 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(); + Assert.Equal(expectedHalf, actualHalf); + + // UInt128 + stream = new MemoryStream(_bytes); + br = new BinaryReader(stream); + UInt128 expectedUInt128 = (UInt128)new BigInteger(_bytes); + UInt128 actualUInt128 = br.ReadType(); + Assert.Equal(expectedHalf, actualHalf); +#endif + + // Enum + stream = new MemoryStream(_bytes); + br = new BinaryReader(stream); + TestEnum expectedTestEnum = (TestEnum)0x03020100; + TestEnum actualTestEnum = br.ReadType(); + 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); diff --git a/SabreTools.IO.Test/Extensions/ByteArrayExtensionsReadTests.cs b/SabreTools.IO.Test/Extensions/ByteArrayReaderExtensionsTests.cs similarity index 80% rename from SabreTools.IO.Test/Extensions/ByteArrayExtensionsReadTests.cs rename to SabreTools.IO.Test/Extensions/ByteArrayReaderExtensionsTests.cs index fe67e1b..eb5e74a 100644 --- a/SabreTools.IO.Test/Extensions/ByteArrayExtensionsReadTests.cs +++ b/SabreTools.IO.Test/Extensions/ByteArrayReaderExtensionsTests.cs @@ -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 { /// /// 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(ref offset); + Assert.Equal(expectedGuid, actualGuid); + +#if NET6_0_OR_GREATER + // Half + offset = 0; + Half expectedHalf = BitConverter.Int16BitsToHalf(0x0100); + Half actualHalf = _bytes.ReadType(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(ref offset); + Assert.Equal(expectedHalf, actualHalf); + + // UInt128 + offset = 0; + UInt128 expectedUInt128 = (UInt128)new BigInteger(_bytes); + UInt128 actualUInt128 = _bytes.ReadType(ref offset); + Assert.Equal(expectedHalf, actualHalf); +#endif + + // Enum + offset = 0; + TestEnum expectedTestEnum = (TestEnum)0x03020100; + TestEnum actualTestEnum = _bytes.ReadType(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); diff --git a/SabreTools.IO.Test/Extensions/ByteArrayExtensionsWriteTests.cs b/SabreTools.IO.Test/Extensions/ByteArrayWriterExtensionsTests.cs similarity index 99% rename from SabreTools.IO.Test/Extensions/ByteArrayExtensionsWriteTests.cs rename to SabreTools.IO.Test/Extensions/ByteArrayWriterExtensionsTests.cs index 9993c7f..0ae6b59 100644 --- a/SabreTools.IO.Test/Extensions/ByteArrayExtensionsWriteTests.cs +++ b/SabreTools.IO.Test/Extensions/ByteArrayWriterExtensionsTests.cs @@ -9,7 +9,7 @@ using Xunit; namespace SabreTools.IO.Test.Extensions { // TODO: Add string writing tests - public class ByteArrayExtensionsWriteTests + public class ByteArrayWriterExtensionsTests { /// /// Test pattern from 0x00-0x0F diff --git a/SabreTools.IO.Test/Extensions/StreamExtensionsReadTests.cs b/SabreTools.IO.Test/Extensions/StreamReaderExtensionsTests.cs similarity index 79% rename from SabreTools.IO.Test/Extensions/StreamExtensionsReadTests.cs rename to SabreTools.IO.Test/Extensions/StreamReaderExtensionsTests.cs index 544988a..37a57a1 100644 --- a/SabreTools.IO.Test/Extensions/StreamExtensionsReadTests.cs +++ b/SabreTools.IO.Test/Extensions/StreamReaderExtensionsTests.cs @@ -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 { /// /// 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(); + Assert.Equal(expectedGuid, actualGuid); + +#if NET6_0_OR_GREATER + // Half + stream = new MemoryStream(_bytes); + Half expectedHalf = BitConverter.Int16BitsToHalf(0x0100); + Half actualHalf = stream.ReadType(); + 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(); + Assert.Equal(expectedHalf, actualHalf); + + // UInt128 + stream = new MemoryStream(_bytes); + UInt128 expectedUInt128 = (UInt128)new BigInteger(_bytes); + UInt128 actualUInt128 = stream.ReadType(); + Assert.Equal(expectedHalf, actualHalf); +#endif + + // Enum + stream = new MemoryStream(_bytes); + TestEnum expectedTestEnum = (TestEnum)0x03020100; + TestEnum actualTestEnum = stream.ReadType(); + 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); diff --git a/SabreTools.IO.Test/Extensions/StreamExtensionsWriteTests.cs b/SabreTools.IO.Test/Extensions/StreamWriterExtensionsTests.cs similarity index 99% rename from SabreTools.IO.Test/Extensions/StreamExtensionsWriteTests.cs rename to SabreTools.IO.Test/Extensions/StreamWriterExtensionsTests.cs index d39b4e3..5b54866 100644 --- a/SabreTools.IO.Test/Extensions/StreamExtensionsWriteTests.cs +++ b/SabreTools.IO.Test/Extensions/StreamWriterExtensionsTests.cs @@ -10,7 +10,7 @@ using Xunit; namespace SabreTools.IO.Test.Extensions { // TODO: Add string writing tests - public class StreamExtensionsWriteTests + public class StreamWriterExtensionsTests { /// /// Test pattern from 0x00-0x0F diff --git a/SabreTools.IO.Test/Extensions/TestStructArrays.cs b/SabreTools.IO.Test/Extensions/TestStructArrays.cs index 4f94166..917330f 100644 --- a/SabreTools.IO.Test/Extensions/TestStructArrays.cs +++ b/SabreTools.IO.Test/Extensions/TestStructArrays.cs @@ -17,6 +17,12 @@ namespace SabreTools.IO.Test.Extensions [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public int[]? IntArray; + /// + /// 4 entry int array + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public TestEnum[]? EnumArray; + /// /// 4 entry struct array /// @@ -31,7 +37,7 @@ namespace SabreTools.IO.Test.Extensions /// /// 4 entry byte array whose length is defined by /// - [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] + [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] public byte[]? LPByteArray; // /// diff --git a/SabreTools.IO/Extensions/BinaryReaderExtensions.cs b/SabreTools.IO/Extensions/BinaryReaderExtensions.cs index 8ddc8d3..5a2fdda 100644 --- a/SabreTools.IO/Extensions/BinaryReaderExtensions.cs +++ b/SabreTools.IO/Extensions/BinaryReaderExtensions.cs @@ -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); } /// @@ -453,45 +454,6 @@ namespace SabreTools.IO.Extensions return Encoding.Unicode.GetString(buffer); } - /// - /// Read a string that is terminated by a newline but contains a quoted portion that - /// may also contain a newline from the underlying stream - /// - public static string? ReadQuotedString(this BinaryReader reader) - => reader.ReadQuotedString(Encoding.Default); - - /// - /// Read a string that is terminated by a newline but contains a quoted portion that - /// may also contain a newline from the underlying stream - /// - public static string? ReadQuotedString(this BinaryReader reader, Encoding encoding) - { - if (reader.BaseStream.Position >= reader.BaseStream.Length) - return null; - - var bytes = new List(); - 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(); - } - /// /// Read a from the underlying stream /// @@ -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 diff --git a/SabreTools.IO/Extensions/ByteArrayReaderExtensions.cs b/SabreTools.IO/Extensions/ByteArrayReaderExtensions.cs index 5dd99f9..3136a74 100644 --- a/SabreTools.IO/Extensions/ByteArrayReaderExtensions.cs +++ b/SabreTools.IO/Extensions/ByteArrayReaderExtensions.cs @@ -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); } /// @@ -582,45 +583,6 @@ namespace SabreTools.IO.Extensions return Encoding.Unicode.GetString(buffer); } - /// - /// Read a string that is terminated by a newline but contains a quoted portion that - /// may also contain a newline from the byte array - /// - public static string? ReadQuotedString(this byte[] content, ref int offset) - => content.ReadQuotedString(ref offset, Encoding.Default); - - /// - /// Read a string that is terminated by a newline but contains a quoted portion that - /// may also contain a newline from the byte array - /// - 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(); - 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(); - } - /// /// Read a from the stream /// @@ -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 diff --git a/SabreTools.IO/Extensions/StreamReaderExtensions.cs b/SabreTools.IO/Extensions/StreamReaderExtensions.cs index ddb161c..0516245 100644 --- a/SabreTools.IO/Extensions/StreamReaderExtensions.cs +++ b/SabreTools.IO/Extensions/StreamReaderExtensions.cs @@ -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); } /// @@ -566,45 +567,6 @@ namespace SabreTools.IO.Extensions return Encoding.Unicode.GetString(buffer); } - /// - /// Read a string that is terminated by a newline but contains a quoted portion that - /// may also contain a newline from the stream - /// - public static string? ReadQuotedString(this Stream stream) - => stream.ReadQuotedString(Encoding.Default); - - /// - /// Read a string that is terminated by a newline but contains a quoted portion that - /// may also contain a newline from the stream - /// - public static string? ReadQuotedString(this Stream stream, Encoding encoding) - { - if (stream.Position >= stream.Length) - return null; - - var bytes = new List(); - 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(); - } - /// /// Read a from the stream /// @@ -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