From 6f217fe2cae9eeed59bf88865af2580d85d5f334 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Mon, 16 Mar 2026 10:03:00 -0400 Subject: [PATCH] Add GUID numeric extensions --- .../Extensions/BinaryReaderExtensionsTests.cs | 44 +++++++- .../Extensions/BinaryWriterExtensionsTests.cs | 22 +++- .../ByteArrayReaderExtensionsTests.cs | 41 ++++++- .../ByteArrayWriterExtensionsTests.cs | 22 +++- .../Extensions/StreamReaderExtensionsTests.cs | 41 ++++++- .../Extensions/StreamWriterExtensionsTests.cs | 21 +++- .../Extensions/BinaryReaderExtensions.cs | 67 +++++++++--- .../Extensions/BinaryWriterExtensions.cs | 20 +++- .../Extensions/ByteArrayReaderExtensions.cs | 65 ++++++++--- .../Extensions/ByteArrayWriterExtensions.cs | 20 +++- SabreTools.IO/Extensions/NumericExtensions.cs | 103 +++++++++++++++++- .../Extensions/StreamReaderExtensions.cs | 66 ++++++++--- .../Extensions/StreamWriterExtensions.cs | 20 +++- 13 files changed, 485 insertions(+), 67 deletions(-) diff --git a/SabreTools.IO.Test/Extensions/BinaryReaderExtensionsTests.cs b/SabreTools.IO.Test/Extensions/BinaryReaderExtensionsTests.cs index 5964120..deb4745 100644 --- a/SabreTools.IO.Test/Extensions/BinaryReaderExtensionsTests.cs +++ b/SabreTools.IO.Test/Extensions/BinaryReaderExtensionsTests.cs @@ -29,6 +29,15 @@ namespace SabreTools.IO.Test.Extensions 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, ]; + /// + /// Test pattern for big-endian GUID created from + /// + private static readonly byte[] _guidBigEndianbytes = + [ + 0x03, 0x02, 0x01, 0x00, 0x05, 0x04, 0x07, 0x06, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + ]; + #region Exact Read [Fact] @@ -668,11 +677,21 @@ namespace SabreTools.IO.Test.Extensions { var stream = new MemoryStream(_bytes); var br = new BinaryReader(stream); - var expected = new Guid([.. Enumerable.Reverse(_bytes)]); + var expected = new Guid(_guidBigEndianbytes); Guid read = br.ReadGuidBigEndian(); Assert.Equal(expected, read); } + [Fact] + public void ReadGuidLittleEndianTest() + { + var stream = new MemoryStream(_bytes); + var br = new BinaryReader(stream); + var expected = new Guid(_bytes); + Guid read = br.ReadGuidLittleEndian(); + Assert.Equal(expected, read); + } + [Fact] public void ReadInt128Test() { @@ -1722,12 +1741,23 @@ namespace SabreTools.IO.Test.Extensions { var stream = new MemoryStream(_bytes); var br = new BinaryReader(stream); - var expected = new Guid([.. Enumerable.Reverse(_bytes)]); + var expected = new Guid(_guidBigEndianbytes); Guid read = br.PeekGuidBigEndian(); Assert.Equal(expected, read); Assert.Equal(0, br.BaseStream.Position); } + [Fact] + public void PeekGuidLittleEndianTest() + { + var stream = new MemoryStream(_bytes); + var br = new BinaryReader(stream); + var expected = new Guid(_bytes); + Guid read = br.PeekGuidLittleEndian(); + Assert.Equal(expected, read); + Assert.Equal(0, br.BaseStream.Position); + } + [Fact] public void PeekInt128Test() { @@ -2505,6 +2535,16 @@ namespace SabreTools.IO.Test.Extensions Assert.Equal(default, read); } + [Fact] + public void TryReadGuidLittleEndianTest() + { + var stream = new MemoryStream([]); + var br = new BinaryReader(stream); + bool actual = br.TryReadGuidLittleEndian(out Guid read); + Assert.False(actual); + Assert.Equal(default, read); + } + [Fact] public void TryReadInt128Test() { diff --git a/SabreTools.IO.Test/Extensions/BinaryWriterExtensionsTests.cs b/SabreTools.IO.Test/Extensions/BinaryWriterExtensionsTests.cs index 9d08f7e..a386334 100644 --- a/SabreTools.IO.Test/Extensions/BinaryWriterExtensionsTests.cs +++ b/SabreTools.IO.Test/Extensions/BinaryWriterExtensionsTests.cs @@ -28,6 +28,15 @@ namespace SabreTools.IO.Test.Extensions 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, ]; + /// + /// Test pattern for big-endian GUID created from + /// + private static readonly byte[] _guidBigEndianbytes = + [ + 0x03, 0x02, 0x01, 0x00, 0x05, 0x04, 0x07, 0x06, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + ]; + [Fact] public void WriteByteValueTest() { @@ -602,11 +611,22 @@ namespace SabreTools.IO.Test.Extensions [Fact] public void WriteGuidBigEndianTest() + { + var stream = new MemoryStream(new byte[16], 0, 16, true, true); + var bw = new BinaryWriter(stream); + byte[] expected = [.. _guidBigEndianbytes.Take(16)]; + bool write = bw.WriteBigEndian(new Guid(_bytes)); + Assert.True(write); + ValidateBytes(expected, stream.GetBuffer()); + } + + [Fact] + public void WriteGuidLittleEndianTest() { var stream = new MemoryStream(new byte[16], 0, 16, true, true); var bw = new BinaryWriter(stream); byte[] expected = [.. _bytes.Take(16)]; - bool write = bw.WriteBigEndian(new Guid([.. Enumerable.Reverse(_bytes)])); + bool write = bw.WriteLittleEndian(new Guid(_bytes)); Assert.True(write); ValidateBytes(expected, stream.GetBuffer()); } diff --git a/SabreTools.IO.Test/Extensions/ByteArrayReaderExtensionsTests.cs b/SabreTools.IO.Test/Extensions/ByteArrayReaderExtensionsTests.cs index 44c952b..2f4abfc 100644 --- a/SabreTools.IO.Test/Extensions/ByteArrayReaderExtensionsTests.cs +++ b/SabreTools.IO.Test/Extensions/ByteArrayReaderExtensionsTests.cs @@ -28,6 +28,15 @@ namespace SabreTools.IO.Test.Extensions 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, ]; + /// + /// Test pattern for big-endian GUID created from + /// + private static readonly byte[] _guidBigEndianbytes = + [ + 0x03, 0x02, 0x01, 0x00, 0x05, 0x04, 0x07, 0x06, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + ]; + #region Exact Read [Fact] @@ -576,11 +585,20 @@ namespace SabreTools.IO.Test.Extensions public void ReadGuidBigEndianTest() { int offset = 0; - var expected = new Guid([.. Enumerable.Reverse(_bytes)]); + var expected = new Guid(_guidBigEndianbytes); Guid read = _bytes.ReadGuidBigEndian(ref offset); Assert.Equal(expected, read); } + [Fact] + public void ReadGuidLittleEndianTest() + { + int offset = 0; + var expected = new Guid(_bytes); + Guid read = _bytes.ReadGuidLittleEndian(ref offset); + Assert.Equal(expected, read); + } + [Fact] public void ReadInt128Test() { @@ -1556,12 +1574,22 @@ namespace SabreTools.IO.Test.Extensions public void PeekGuidBigEndianTest() { int offset = 0; - var expected = new Guid([.. Enumerable.Reverse(_bytes)]); + var expected = new Guid(_guidBigEndianbytes); Guid read = _bytes.PeekGuidBigEndian(ref offset); Assert.Equal(expected, read); Assert.Equal(0, offset); } + [Fact] + public void PeekGuidLittleEndianTest() + { + int offset = 0; + var expected = new Guid(_bytes); + Guid read = _bytes.PeekGuidLittleEndian(ref offset); + Assert.Equal(expected, read); + Assert.Equal(0, offset); + } + [Fact] public void PeekInt128Test() { @@ -2263,6 +2291,15 @@ namespace SabreTools.IO.Test.Extensions Assert.Equal(default, read); } + [Fact] + public void TryReadGuidLittleEndianTest() + { + int offset = 0; + bool actual = Array.Empty().TryReadGuidLittleEndian(ref offset, out Guid read); + Assert.False(actual); + Assert.Equal(default, read); + } + [Fact] public void TryReadInt128Test() { diff --git a/SabreTools.IO.Test/Extensions/ByteArrayWriterExtensionsTests.cs b/SabreTools.IO.Test/Extensions/ByteArrayWriterExtensionsTests.cs index 7e3a8a6..7e36954 100644 --- a/SabreTools.IO.Test/Extensions/ByteArrayWriterExtensionsTests.cs +++ b/SabreTools.IO.Test/Extensions/ByteArrayWriterExtensionsTests.cs @@ -27,6 +27,15 @@ namespace SabreTools.IO.Test.Extensions 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, ]; + /// + /// Test pattern for big-endian GUID created from + /// + private static readonly byte[] _guidBigEndianbytes = + [ + 0x03, 0x02, 0x01, 0x00, 0x05, 0x04, 0x07, 0x06, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + ]; + [Fact] public void WriteByteTest() { @@ -631,11 +640,22 @@ namespace SabreTools.IO.Test.Extensions [Fact] public void WriteGuidBigEndianTest() + { + byte[] buffer = new byte[16]; + int offset = 0; + byte[] expected = [.. _guidBigEndianbytes.Take(16)]; + bool write = buffer.WriteBigEndian(ref offset, new Guid(_bytes)); + Assert.True(write); + ValidateBytes(expected, buffer); + } + + [Fact] + public void WriteGuidLittleEndianTest() { byte[] buffer = new byte[16]; int offset = 0; byte[] expected = [.. _bytes.Take(16)]; - bool write = buffer.WriteBigEndian(ref offset, new Guid([.. Enumerable.Reverse(_bytes)])); + bool write = buffer.WriteLittleEndian(ref offset, new Guid(_bytes)); Assert.True(write); ValidateBytes(expected, buffer); } diff --git a/SabreTools.IO.Test/Extensions/StreamReaderExtensionsTests.cs b/SabreTools.IO.Test/Extensions/StreamReaderExtensionsTests.cs index 04f58b1..45aa495 100644 --- a/SabreTools.IO.Test/Extensions/StreamReaderExtensionsTests.cs +++ b/SabreTools.IO.Test/Extensions/StreamReaderExtensionsTests.cs @@ -29,6 +29,15 @@ namespace SabreTools.IO.Test.Extensions 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, ]; + /// + /// Test pattern for big-endian GUID created from + /// + private static readonly byte[] _guidBigEndianbytes = + [ + 0x03, 0x02, 0x01, 0x00, 0x05, 0x04, 0x07, 0x06, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + ]; + #region Exact Read [Fact] @@ -580,11 +589,20 @@ namespace SabreTools.IO.Test.Extensions public void ReadGuidBigEndianTest() { var stream = new MemoryStream(_bytes); - var expected = new Guid([.. Enumerable.Reverse(_bytes)]); + var expected = new Guid(_guidBigEndianbytes); Guid read = stream.ReadGuidBigEndian(); Assert.Equal(expected, read); } + [Fact] + public void ReadGuidLittleEndianTest() + { + var stream = new MemoryStream(_bytes); + var expected = new Guid(_bytes); + Guid read = stream.ReadGuidLittleEndian(); + Assert.Equal(expected, read); + } + [Fact] public void ReadInt128Test() { @@ -1552,12 +1570,22 @@ namespace SabreTools.IO.Test.Extensions public void PeekGuidBigEndianTest() { var stream = new MemoryStream(_bytes); - var expected = new Guid([.. Enumerable.Reverse(_bytes)]); + var expected = new Guid(_guidBigEndianbytes); Guid read = stream.PeekGuidBigEndian(); Assert.Equal(expected, read); Assert.Equal(0, stream.Position); } + [Fact] + public void PeekGuidLittleEndianTest() + { + var stream = new MemoryStream(_bytes); + var expected = new Guid(_bytes); + Guid read = stream.PeekGuidLittleEndian(); + Assert.Equal(expected, read); + Assert.Equal(0, stream.Position); + } + [Fact] public void PeekInt128Test() { @@ -2251,6 +2279,15 @@ namespace SabreTools.IO.Test.Extensions Assert.Equal(default, read); } + [Fact] + public void TryReadGuidLittleEndianTest() + { + var stream = new MemoryStream([]); + bool actual = stream.TryReadGuidLittleEndian(out Guid read); + Assert.False(actual); + Assert.Equal(default, read); + } + [Fact] public void TryReadInt128Test() { diff --git a/SabreTools.IO.Test/Extensions/StreamWriterExtensionsTests.cs b/SabreTools.IO.Test/Extensions/StreamWriterExtensionsTests.cs index ba18ba4..563777f 100644 --- a/SabreTools.IO.Test/Extensions/StreamWriterExtensionsTests.cs +++ b/SabreTools.IO.Test/Extensions/StreamWriterExtensionsTests.cs @@ -28,6 +28,15 @@ namespace SabreTools.IO.Test.Extensions 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, ]; + /// + /// Test pattern for big-endian GUID created from + /// + private static readonly byte[] _guidBigEndianbytes = + [ + 0x03, 0x02, 0x01, 0x00, 0x05, 0x04, 0x07, 0x06, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + ]; + [Fact] public void WriteByteValueTest() { @@ -576,10 +585,20 @@ namespace SabreTools.IO.Test.Extensions [Fact] public void WriteGuidBigEndianTest() + { + var stream = new MemoryStream(new byte[16], 0, 16, true, true); + byte[] expected = [.. _guidBigEndianbytes.Take(16)]; + bool write = stream.WriteBigEndian(new Guid(_bytes)); + Assert.True(write); + ValidateBytes(expected, stream.GetBuffer()); + } + + [Fact] + public void WriteGuidLittleEndianTest() { var stream = new MemoryStream(new byte[16], 0, 16, true, true); byte[] expected = [.. _bytes.Take(16)]; - bool write = stream.WriteBigEndian(new Guid([.. Enumerable.Reverse(_bytes)])); + bool write = stream.WriteLittleEndian(new Guid(_bytes)); Assert.True(write); ValidateBytes(expected, stream.GetBuffer()); } diff --git a/SabreTools.IO/Extensions/BinaryReaderExtensions.cs b/SabreTools.IO/Extensions/BinaryReaderExtensions.cs index ec4d89a..8cf6956 100644 --- a/SabreTools.IO/Extensions/BinaryReaderExtensions.cs +++ b/SabreTools.IO/Extensions/BinaryReaderExtensions.cs @@ -458,10 +458,13 @@ namespace SabreTools.IO.Extensions /// /// Read a Guid from the underlying stream /// + /// Reads in machine native format public static Guid ReadGuid(this BinaryReader reader) { - byte[] buffer = reader.ReadBytes(16); - return new Guid(buffer); + if (BitConverter.IsLittleEndian) + return reader.ReadGuidLittleEndian(); + else + return reader.ReadGuidBigEndian(); } /// @@ -471,8 +474,17 @@ namespace SabreTools.IO.Extensions public static Guid ReadGuidBigEndian(this BinaryReader reader) { byte[] buffer = reader.ReadBytes(16); - Array.Reverse(buffer); - return new Guid(buffer); + return buffer.ToGuidBigEndian(); + } + + /// + /// Read a Guid from the underlying stream + /// + /// Reads in little-endian format + public static Guid ReadGuidLittleEndian(this BinaryReader reader) + { + byte[] buffer = reader.ReadBytes(16); + return buffer.ToGuidLittleEndian(); } #if NET7_0_OR_GREATER @@ -1719,9 +1731,10 @@ namespace SabreTools.IO.Extensions /// Only works properly on seekable streams public static Guid PeekGuid(this BinaryReader reader) { - Guid value = reader.ReadGuid(); - reader.BaseStream.SeekIfPossible(-16, SeekOrigin.Current); - return value; + if (BitConverter.IsLittleEndian) + return reader.PeekGuidLittleEndian(); + else + return reader.PeekGuidBigEndian(); } /// @@ -1736,6 +1749,18 @@ namespace SabreTools.IO.Extensions return value; } + /// + /// Peek a Guid from the base stream + /// + /// Reads in little-endian format + /// Only works properly on seekable streams + public static Guid PeekGuidLittleEndian(this BinaryReader reader) + { + Guid value = reader.ReadGuidLittleEndian(); + reader.BaseStream.SeekIfPossible(-16, SeekOrigin.Current); + return value; + } + #if NET7_0_OR_GREATER /// /// Peek an Int128 from the base stream @@ -2705,14 +2730,10 @@ namespace SabreTools.IO.Extensions /// Reads in machine native format public static bool TryReadGuid(this BinaryReader reader, out Guid value) { - if (reader.BaseStream.Position > reader.BaseStream.Length - 16) - { - value = default; - return false; - } - - value = reader.ReadGuid(); - return true; + if (BitConverter.IsLittleEndian) + return reader.TryReadGuidLittleEndian(out value); + else + return reader.TryReadGuidBigEndian(out value); } /// @@ -2731,6 +2752,22 @@ namespace SabreTools.IO.Extensions return true; } + /// + /// Read a Guid from the base stream + /// + /// Reads in big-endian format + public static bool TryReadGuidLittleEndian(this BinaryReader reader, out Guid value) + { + if (reader.BaseStream.Position > reader.BaseStream.Length - 16) + { + value = default; + return false; + } + + value = reader.ReadGuidLittleEndian(); + return true; + } + #if NET7_0_OR_GREATER /// /// Read an Int128 from the base stream diff --git a/SabreTools.IO/Extensions/BinaryWriterExtensions.cs b/SabreTools.IO/Extensions/BinaryWriterExtensions.cs index 98062de..fb2b3e6 100644 --- a/SabreTools.IO/Extensions/BinaryWriterExtensions.cs +++ b/SabreTools.IO/Extensions/BinaryWriterExtensions.cs @@ -401,10 +401,13 @@ namespace SabreTools.IO.Extensions /// /// Write a Guid /// + /// Writes in machine native format public static bool Write(this BinaryWriter writer, Guid value) { - byte[] buffer = value.ToByteArray(); - return WriteFromBuffer(writer, buffer); + if (BitConverter.IsLittleEndian) + return writer.WriteLittleEndian(value); + else + return writer.WriteBigEndian(value); } /// @@ -413,8 +416,17 @@ namespace SabreTools.IO.Extensions /// Writes in big-endian format public static bool WriteBigEndian(this BinaryWriter writer, Guid value) { - byte[] buffer = value.ToByteArray(); - Array.Reverse(buffer); + byte[] buffer = value.GetBytesBigEndian(); + return WriteFromBuffer(writer, buffer); + } + + /// + /// Write a Guid + /// + /// Writes in big-endian format + public static bool WriteLittleEndian(this BinaryWriter writer, Guid value) + { + byte[] buffer = value.GetBytesLittleEndian(); return WriteFromBuffer(writer, buffer); } diff --git a/SabreTools.IO/Extensions/ByteArrayReaderExtensions.cs b/SabreTools.IO/Extensions/ByteArrayReaderExtensions.cs index d2e6430..fef1339 100644 --- a/SabreTools.IO/Extensions/ByteArrayReaderExtensions.cs +++ b/SabreTools.IO/Extensions/ByteArrayReaderExtensions.cs @@ -649,8 +649,10 @@ namespace SabreTools.IO.Extensions /// Reads in machine native format public static Guid ReadGuid(this byte[] content, ref int offset) { - byte[] buffer = ReadExactlyToBuffer(content, ref offset, 16); - return new Guid(buffer); + if (BitConverter.IsLittleEndian) + return content.ReadGuidLittleEndian(ref offset); + else + return content.ReadGuidBigEndian(ref offset); } /// @@ -660,8 +662,17 @@ namespace SabreTools.IO.Extensions public static Guid ReadGuidBigEndian(this byte[] content, ref int offset) { byte[] buffer = ReadExactlyToBuffer(content, ref offset, 16); - Array.Reverse(buffer); - return new Guid(buffer); + return buffer.ToGuidBigEndian(); + } + + /// + /// Read a Guid and increment the pointer to an array + /// + /// Reads in little-endian format + public static Guid ReadGuidLittleEndian(this byte[] content, ref int offset) + { + byte[] buffer = ReadExactlyToBuffer(content, ref offset, 16); + return buffer.ToGuidLittleEndian(); } #if NET7_0_OR_GREATER @@ -1917,9 +1928,10 @@ namespace SabreTools.IO.Extensions /// Reads in machine native format public static Guid PeekGuid(this byte[] content, ref int offset) { - Guid value = content.ReadGuid(ref offset); - offset -= 16; - return value; + if (BitConverter.IsLittleEndian) + return content.PeekGuidLittleEndian(ref offset); + else + return content.PeekGuidBigEndian(ref offset); } /// @@ -1933,6 +1945,17 @@ namespace SabreTools.IO.Extensions return value; } + /// + /// Peek a Guid without incrementing the pointer to an array + /// + /// Reads in big-endian format + public static Guid PeekGuidLittleEndian(this byte[] content, ref int offset) + { + Guid value = content.ReadGuidLittleEndian(ref offset); + offset -= 16; + return value; + } + #if NET7_0_OR_GREATER /// /// Peek an Int128 without incrementing the pointer to an array @@ -2908,14 +2931,10 @@ namespace SabreTools.IO.Extensions /// Reads in machine native format public static bool TryReadGuid(this byte[] content, ref int offset, out Guid value) { - if (offset > content.Length - 16) - { - value = default; - return false; - } - - value = content.ReadGuid(ref offset); - return true; + if (BitConverter.IsLittleEndian) + return content.TryReadGuidLittleEndian(ref offset, out value); + else + return content.TryReadGuidBigEndian(ref offset, out value); } /// @@ -2934,6 +2953,22 @@ namespace SabreTools.IO.Extensions return true; } + /// + /// Read a Guid and increment the pointer to an array + /// + /// Reads in little-endian format + public static bool TryReadGuidLittleEndian(this byte[] content, ref int offset, out Guid value) + { + if (offset > content.Length - 16) + { + value = default; + return false; + } + + value = content.ReadGuidLittleEndian(ref offset); + return true; + } + #if NET7_0_OR_GREATER /// /// Read an Int128 and increment the pointer to an array diff --git a/SabreTools.IO/Extensions/ByteArrayWriterExtensions.cs b/SabreTools.IO/Extensions/ByteArrayWriterExtensions.cs index 38e4cc6..9be0e02 100644 --- a/SabreTools.IO/Extensions/ByteArrayWriterExtensions.cs +++ b/SabreTools.IO/Extensions/ByteArrayWriterExtensions.cs @@ -579,10 +579,13 @@ namespace SabreTools.IO.Extensions /// /// Write a Guid and increment the pointer to an array /// + /// Writes in machine native format public static bool Write(this byte[] content, ref int offset, Guid value) { - byte[] buffer = value.ToByteArray(); - return WriteFromBuffer(content, ref offset, buffer); + if (BitConverter.IsLittleEndian) + return content.WriteLittleEndian(ref offset, value); + else + return content.WriteBigEndian(ref offset, value); } /// @@ -591,8 +594,17 @@ namespace SabreTools.IO.Extensions /// Writes in big-endian format public static bool WriteBigEndian(this byte[] content, ref int offset, Guid value) { - byte[] buffer = value.ToByteArray(); - Array.Reverse(buffer); + byte[] buffer = value.GetBytesBigEndian(); + return WriteFromBuffer(content, ref offset, buffer); + } + + /// + /// Write a Guid and increment the pointer to an array + /// + /// Writes in little-endian format + public static bool WriteLittleEndian(this byte[] content, ref int offset, Guid value) + { + byte[] buffer = value.GetBytesLittleEndian(); return WriteFromBuffer(content, ref offset, buffer); } diff --git a/SabreTools.IO/Extensions/NumericExtensions.cs b/SabreTools.IO/Extensions/NumericExtensions.cs index 2608d35..a00f525 100644 --- a/SabreTools.IO/Extensions/NumericExtensions.cs +++ b/SabreTools.IO/Extensions/NumericExtensions.cs @@ -6,7 +6,6 @@ namespace SabreTools.IO.Extensions /// /// Extensions for numeric conversion /// - /// TODO: Add GUID public static class NumericExtensions { #region From Byte Array @@ -553,6 +552,48 @@ namespace SabreTools.IO.Extensions return output; } + /// + /// Convert a byte array to a Guid + /// + /// Reads in big-endian format + public static Guid ToGuidBigEndian(this byte[] value) + => value.ToGuidBigEndian(0); + + /// + /// Convert a byte array to a Guid + /// + /// Reads in big-endian format + public static Guid ToGuidBigEndian(this byte[] value, int offset) + { + int a = value.ReadInt32BigEndian(ref offset); + short b = value.ReadInt16BigEndian(ref offset); + short c = value.ReadInt16BigEndian(ref offset); + byte[] d = value.ReadBytes(ref offset, 8); + + return new Guid(a, b, c, d); + } + + /// + /// Convert a byte array to a Guid + /// + /// Reads in little-endian format + public static Guid ToGuidLittleEndian(this byte[] value) + => value.ToGuidLittleEndian(0); + + /// + /// Convert a byte array to a Guid + /// + /// Reads in little-endian format + public static Guid ToGuidLittleEndian(this byte[] value, int offset) + { + int a = value.ReadInt32LittleEndian(ref offset); + short b = value.ReadInt16LittleEndian(ref offset); + short c = value.ReadInt16LittleEndian(ref offset); + byte[] d = value.ReadBytes(ref offset, 8); + + return new Guid(a, b, c, d); + } + #if NET7_0_OR_GREATER /// /// Convert a byte array to an Int128 @@ -1209,6 +1250,66 @@ namespace SabreTools.IO.Extensions return [.. output]; } + /// + /// Convert a Guid to a byte array + /// + /// Reads in big-endian format + public static byte[] GetBytesBigEndian(this Guid value) + { + byte[] bytes = value.ToByteArray(); + if (BitConverter.IsLittleEndian) + { + int offset = 0; + + int aInt = bytes.ReadInt32LittleEndian(ref offset); + byte[] aBytes = aInt.GetBytesBigEndian(); + + short bShort = bytes.ReadInt16LittleEndian(ref offset); + byte[] bBytes = bShort.GetBytesBigEndian(); + + short cShort = bytes.ReadInt16LittleEndian(ref offset); + byte[] cBytes = cShort.GetBytesBigEndian(); + + byte[] dBytes = bytes.ReadBytes(ref offset, 8); + + return [.. aBytes, .. bBytes, .. cBytes, .. dBytes]; + } + else + { + return bytes; + } + } + + /// + /// Convert a Decimal to a byte array + /// + /// Reads in little-endian format + public static byte[] GetBytesLittleEndian(this Guid value) + { + byte[] bytes = value.ToByteArray(); + if (BitConverter.IsLittleEndian) + { + return bytes; + } + else + { + int offset = 0; + + int aInt = bytes.ReadInt32BigEndian(ref offset); + byte[] aBytes = aInt.GetBytesLittleEndian(); + + short bShort = bytes.ReadInt16BigEndian(ref offset); + byte[] bBytes = bShort.GetBytesLittleEndian(); + + short cShort = bytes.ReadInt16BigEndian(ref offset); + byte[] cBytes = cShort.GetBytesLittleEndian(); + + byte[] dBytes = bytes.ReadBytes(ref offset, 8); + + return [.. aBytes, .. bBytes, .. cBytes, .. dBytes]; + } + } + #if NET7_0_OR_GREATER /// /// Convert an Int64 to a byte array diff --git a/SabreTools.IO/Extensions/StreamReaderExtensions.cs b/SabreTools.IO/Extensions/StreamReaderExtensions.cs index 7478d8b..eacd4b7 100644 --- a/SabreTools.IO/Extensions/StreamReaderExtensions.cs +++ b/SabreTools.IO/Extensions/StreamReaderExtensions.cs @@ -644,8 +644,10 @@ namespace SabreTools.IO.Extensions /// Reads in machine native format public static Guid ReadGuid(this Stream stream) { - byte[] buffer = ReadExactlyToBuffer(stream, 16); - return new Guid(buffer); + if (BitConverter.IsLittleEndian) + return stream.ReadGuidLittleEndian(); + else + return stream.ReadGuidBigEndian(); } /// @@ -655,8 +657,17 @@ namespace SabreTools.IO.Extensions public static Guid ReadGuidBigEndian(this Stream stream) { byte[] buffer = ReadExactlyToBuffer(stream, 16); - Array.Reverse(buffer); - return new Guid(buffer); + return buffer.ToGuidBigEndian(); + } + + /// + /// Read a Guid from the stream + /// + /// Reads in little-endian format + public static Guid ReadGuidLittleEndian(this Stream stream) + { + byte[] buffer = ReadExactlyToBuffer(stream, 16); + return buffer.ToGuidLittleEndian(); } #if NET7_0_OR_GREATER @@ -1969,9 +1980,10 @@ namespace SabreTools.IO.Extensions /// Only works properly on seekable streams public static Guid PeekGuid(this Stream stream) { - Guid value = stream.ReadGuid(); - stream.SeekIfPossible(-16, SeekOrigin.Current); - return value; + if (BitConverter.IsLittleEndian) + return stream.PeekGuidLittleEndian(); + else + return stream.PeekGuidBigEndian(); } /// @@ -1986,6 +1998,18 @@ namespace SabreTools.IO.Extensions return value; } + /// + /// Peek a Guid from the stream + /// + /// Reads in little-endian format + /// Only works properly on seekable streams + public static Guid PeekGuidLittleEndian(this Stream stream) + { + Guid value = stream.ReadGuidLittleEndian(); + stream.SeekIfPossible(-16, SeekOrigin.Current); + return value; + } + #if NET7_0_OR_GREATER /// /// Peek an Int128 from the stream @@ -2955,14 +2979,10 @@ namespace SabreTools.IO.Extensions /// Reads in machine native format public static bool TryReadGuid(this Stream stream, out Guid value) { - if (stream.Position > stream.Length - 16) - { - value = default; - return false; - } - - value = stream.ReadGuid(); - return true; + if (BitConverter.IsLittleEndian) + return stream.TryReadGuidLittleEndian(out value); + else + return stream.TryReadGuidBigEndian(out value); } /// @@ -2981,6 +3001,22 @@ namespace SabreTools.IO.Extensions return true; } + /// + /// Read a Guid from the stream + /// + /// Reads in little-endian format + public static bool TryReadGuidLittleEndian(this Stream stream, out Guid value) + { + if (stream.Position > stream.Length - 16) + { + value = default; + return false; + } + + value = stream.ReadGuidLittleEndian(); + return true; + } + #if NET7_0_OR_GREATER /// /// Read an Int128 from the stream diff --git a/SabreTools.IO/Extensions/StreamWriterExtensions.cs b/SabreTools.IO/Extensions/StreamWriterExtensions.cs index bb660ea..fedaa62 100644 --- a/SabreTools.IO/Extensions/StreamWriterExtensions.cs +++ b/SabreTools.IO/Extensions/StreamWriterExtensions.cs @@ -579,10 +579,13 @@ namespace SabreTools.IO.Extensions /// /// Write a Guid /// + /// Writes in machine native format public static bool Write(this Stream stream, Guid value) { - byte[] buffer = value.ToByteArray(); - return WriteFromBuffer(stream, buffer); + if (BitConverter.IsLittleEndian) + return stream.WriteLittleEndian(value); + else + return stream.WriteBigEndian(value); } /// @@ -591,8 +594,17 @@ namespace SabreTools.IO.Extensions /// Writes in big-endian format public static bool WriteBigEndian(this Stream stream, Guid value) { - byte[] buffer = value.ToByteArray(); - Array.Reverse(buffer); + byte[] buffer = value.GetBytesBigEndian(); + return WriteFromBuffer(stream, buffer); + } + + /// + /// Write a Guid + /// + /// Writes in little-endian format + public static bool WriteLittleEndian(this Stream stream, Guid value) + { + byte[] buffer = value.GetBytesLittleEndian(); return WriteFromBuffer(stream, buffer); }