diff --git a/X10D/src/Endianness.cs b/X10D/src/Endianness.cs
new file mode 100644
index 0000000..8b7202e
--- /dev/null
+++ b/X10D/src/Endianness.cs
@@ -0,0 +1,16 @@
+using System.ComponentModel;
+
+namespace X10D
+{
+ ///
+ /// Represents an enumeration of endianness values.
+ ///
+ public enum Endianness
+ {
+ [Description("The value should be read as though it uses little endian encoding.")]
+ LittleEndian,
+
+ [Description("The value should be read as though it uses big endian encoding.")]
+ BigEndian
+ }
+}
diff --git a/X10D/src/StreamExtensions/StreamExtensions.cs b/X10D/src/StreamExtensions/StreamExtensions.cs
index 18dc5ad..20e4e48 100644
--- a/X10D/src/StreamExtensions/StreamExtensions.cs
+++ b/X10D/src/StreamExtensions/StreamExtensions.cs
@@ -9,6 +9,9 @@ namespace X10D.StreamExtensions
///
public static class StreamExtensions
{
+ private static readonly Endianness DefaultEndianness =
+ BitConverter.IsLittleEndian ? Endianness.LittleEndian : Endianness.BigEndian;
+
///
/// Returns the hash of a stream using the specified hash algorithm.
///
@@ -49,5 +52,359 @@ namespace X10D.StreamExtensions
return crypt.ComputeHash(stream);
}
+
+ ///
+ /// Reads a 2-byte signed integer from the current stream and advances the current position of the stream by two
+ /// bytes using the default endian encoding.
+ ///
+ /// The stream to read.
+ /// A 2-byte signed integer read from the current stream.
+ public static short ReadInt16(this Stream stream)
+ {
+ return stream.ReadInt16(DefaultEndianness);
+ }
+
+ ///
+ /// Reads a 2-byte signed integer from the current stream and advances the current position of the stream by two
+ /// bytes using a specified endian encoding.
+ ///
+ /// The stream to read.
+ /// The endian encoding to use.
+ /// A 2-byte signed integer read from the current stream.
+ public static short ReadInt16(this Stream stream, Endianness endianness)
+ {
+ var value = ReadInternal(stream, endianness);
+ return BitConverter.ToInt16(value, 0);
+ }
+
+ ///
+ /// Reads a 4-byte signed integer from the current stream and advances the current position of the stream by four
+ /// bytes using the default endian encoding.
+ ///
+ /// The stream to read.
+ /// A 4-byte signed integer read from the current stream.
+ public static int ReadInt32(this Stream stream)
+ {
+ return stream.ReadInt32(DefaultEndianness);
+ }
+
+ ///
+ /// Reads a 4-byte signed integer from the current stream and advances the current position of the stream by four
+ /// bytes using a specified endian encoding.
+ ///
+ /// The stream to read.
+ /// The endian encoding to use.
+ /// A 4-byte signed integer read from the current stream.
+ public static int ReadInt32(this Stream stream, Endianness endianness)
+ {
+ var value = ReadInternal(stream, endianness);
+ return BitConverter.ToInt32(value, 0);
+ }
+
+ ///
+ /// Reads an 8-byte signed integer from the current stream and advances the current position of the stream by eight
+ /// bytes using the default endian encoding.
+ ///
+ /// The stream to read.
+ /// An 8-byte signed integer read from the current stream.
+ public static long ReadInt64(this Stream stream)
+ {
+ return stream.ReadInt64(DefaultEndianness);
+ }
+
+ ///
+ /// Reads an 8-byte signed integer from the current stream and advances the current position of the stream by eight
+ /// bytes using a specified endian encoding.
+ ///
+ /// The stream to read.
+ /// The endian encoding to use.
+ /// An 8-byte signed integer read from the current stream.
+ public static long ReadInt64(this Stream stream, Endianness endianness)
+ {
+ var value = ReadInternal(stream, endianness);
+ return BitConverter.ToInt64(value, 0);
+ }
+
+ ///
+ /// Reads a 2-byte unsigned integer from the current stream and advances the current position of the stream by two
+ /// bytes using the default endian encoding.
+ ///
+ /// The stream to read.
+ /// A 2-byte unsigned integer read from the current stream.
+ public static ushort ReadUInt16(this Stream stream)
+ {
+ return stream.ReadUInt16(DefaultEndianness);
+ }
+
+ ///
+ /// Reads a 2-byte unsigned integer from the current stream and advances the current position of the stream by two
+ /// bytes using a specified endian encoding.
+ ///
+ /// The stream to read.
+ /// The endian encoding to use.
+ /// A 2-byte unsigned integer read from the current stream.
+ public static ushort ReadUInt16(this Stream stream, Endianness endianness)
+ {
+ var value = ReadInternal(stream, endianness);
+ return BitConverter.ToUInt16(value, 0);
+ }
+
+ ///
+ /// Reads a 4-byte unsigned integer from the current stream and advances the current position of the stream by four
+ /// bytes using the default endian encoding.
+ ///
+ /// The stream to read.
+ /// A 4-byte unsigned integer read from the current stream.
+ public static uint ReadUInt32(this Stream stream)
+ {
+ return stream.ReadUInt32(DefaultEndianness);
+ }
+
+ ///
+ /// Reads a 4-byte unsigned integer from the current stream and advances the current position of the stream by four
+ /// bytes using a specified endian encoding.
+ ///
+ /// The stream to read.
+ /// The endian encoding to use.
+ /// A 4-byte unsigned integer read from the current stream.
+ public static uint ReadUInt32(this Stream stream, Endianness endianness)
+ {
+ var value = ReadInternal(stream, endianness);
+ return BitConverter.ToUInt32(value, 0);
+ }
+
+ ///
+ /// Reads an 8-byte unsigned integer from the current stream and advances the current position of the stream by eight
+ /// bytes using the default endian encoding.
+ ///
+ /// The stream to read.
+ /// An 8-byte unsigned integer read from the current stream.
+ public static ulong ReadUInt64(this Stream stream)
+ {
+ return stream.ReadUInt64(DefaultEndianness);
+ }
+
+ ///
+ /// Reads an 8-byte unsigned integer from the current stream and advances the current position of the stream by eight
+ /// bytes using a specified endian encoding.
+ ///
+ /// The stream to read.
+ /// The endian encoding to use.
+ /// An 8-byte unsigned integer read from the current stream.
+ public static ulong ReadUInt64(this Stream stream, Endianness endianness)
+ {
+ var value = ReadInternal(stream, endianness);
+ return BitConverter.ToUInt64(value, 0);
+ }
+
+ ///
+ /// Writes a two-byte signed integer to the current stream using the system's default endian encoding, and advances
+ /// the stream position by two bytes.
+ ///
+ /// The stream to which the value should be written.
+ /// The two-byte signed integer to write.
+ /// The number of bytes written to the stream.
+ public static int Write(this Stream stream, short value)
+ {
+ return stream.Write(value, DefaultEndianness);
+ }
+
+ ///
+ /// Writes a two-byte signed integer to the current stream using the specified endian encoding, and advances the
+ /// stream position by two bytes.
+ ///
+ /// The stream to which the value should be written.
+ /// The two-byte signed integer to write.
+ /// The endian encoding to use.
+ /// The number of bytes written to the stream.
+ public static int Write(this Stream stream, short value, Endianness endianness)
+ {
+ var buffer = BitConverter.GetBytes(value);
+ return stream.WriteInternal(buffer, endianness);
+ }
+
+ ///
+ /// Writes a four-byte signed integer to the current stream using the system's default endian encoding, and advances
+ /// the stream position by four bytes.
+ ///
+ /// The stream to which the value should be written.
+ /// The four-byte signed integer to write.
+ /// The number of bytes written to the stream.
+ public static int Write(this Stream stream, int value)
+ {
+ return stream.Write(value, DefaultEndianness);
+ }
+
+ ///
+ /// Writes a four-byte signed integer to the current stream using the specified endian encoding, and advances the
+ /// stream position by four bytes.
+ ///
+ /// The stream to which the value should be written.
+ /// The four-byte signed integer to write.
+ /// The endian encoding to use.
+ /// The number of bytes written to the stream.
+ public static int Write(this Stream stream, int value, Endianness endianness)
+ {
+ var buffer = BitConverter.GetBytes(value);
+ return stream.WriteInternal(buffer, endianness);
+ }
+
+ ///
+ /// Writes an eight-byte signed integer to the current stream using the system's default endian encoding, and advances
+ /// the stream position by eight bytes.
+ ///
+ /// The stream to which the value should be written.
+ /// The eight-byte signed integer to write.
+ /// The number of bytes written to the stream.
+ public static int Write(this Stream stream, long value)
+ {
+ return stream.Write(value, DefaultEndianness);
+ }
+
+ ///
+ /// Writes an eight-byte signed integer to the current stream using the specified endian encoding, and advances the
+ /// stream position by eight bytes.
+ ///
+ /// The stream to which the value should be written.
+ /// The eight-byte signed integer to write.
+ /// The endian encoding to use.
+ /// The number of bytes written to the stream.
+ public static int Write(this Stream stream, long value, Endianness endianness)
+ {
+ var buffer = BitConverter.GetBytes(value);
+ return stream.WriteInternal(buffer, endianness);
+ }
+
+ ///
+ /// Writes a two-byte unsigned integer to the current stream using the system's default endian encoding, and advances
+ /// the stream position by two bytes.
+ ///
+ /// The stream to which the value should be written.
+ /// The two-byte unsigned integer to write.
+ /// The number of bytes written to the stream.
+ [CLSCompliant(false)]
+ public static int Write(this Stream stream, ushort value)
+ {
+ return stream.Write(value, DefaultEndianness);
+ }
+
+ ///
+ /// Writes a two-byte unsigned integer to the current stream using the specified endian encoding, and advances the
+ /// stream position by two bytes.
+ ///
+ /// The stream to which the value should be written.
+ /// The two-byte unsigned integer to write.
+ /// The endian encoding to use.
+ /// The number of bytes written to the stream.
+ [CLSCompliant(false)]
+ public static int Write(this Stream stream, ushort value, Endianness endianness)
+ {
+ var buffer = BitConverter.GetBytes(value);
+ return stream.WriteInternal(buffer, endianness);
+ }
+
+ ///
+ /// Writes a four-byte unsigned integer to the current stream using the system's default endian encoding, and advances
+ /// the stream position by four bytes.
+ ///
+ /// The stream to which the value should be written.
+ /// The four-byte unsigned integer to write.
+ /// The number of bytes written to the stream.
+ [CLSCompliant(false)]
+ public static int Write(this Stream stream, uint value)
+ {
+ return stream.Write(value, DefaultEndianness);
+ }
+
+ ///
+ /// Writes a four-byte unsigned integer to the current stream using the specified endian encoding, and advances the
+ /// stream position by four bytes.
+ ///
+ /// The stream to which the value should be written.
+ /// The four-byte unsigned integer to write.
+ /// The endian encoding to use.
+ /// The number of bytes written to the stream.
+ [CLSCompliant(false)]
+ public static int Write(this Stream stream, uint value, Endianness endianness)
+ {
+ var buffer = BitConverter.GetBytes(value);
+ return stream.WriteInternal(buffer, endianness);
+ }
+
+ ///
+ /// Writes an eight-byte unsigned integer to the current stream using the system's default endian encoding, and
+ /// advances the stream position by eight bytes.
+ ///
+ /// The stream to which the value should be written.
+ /// The eight-byte unsigned integer to write.
+ /// The number of bytes written to the stream.
+ [CLSCompliant(false)]
+ public static int Write(this Stream stream, ulong value)
+ {
+ return stream.Write(value, DefaultEndianness);
+ }
+
+ ///
+ /// Writes an eight-byte signed integer to the current stream using the specified endian encoding, and advances the
+ /// stream position by eight bytes.
+ ///
+ /// The stream to which the value should be written.
+ /// The eight-byte signed integer to write.
+ /// The endian encoding to use.
+ /// The number of bytes written to the stream.
+ [CLSCompliant(false)]
+ public static int Write(this Stream stream, ulong value, Endianness endianness)
+ {
+ var buffer = BitConverter.GetBytes(value);
+ return stream.WriteInternal(buffer, endianness);
+ }
+
+ private static unsafe byte[] ReadInternal(this Stream stream, Endianness endianness)
+ where T : unmanaged
+ {
+ if (stream is null)
+ {
+ throw new ArgumentNullException(nameof(stream));
+ }
+
+ if (!stream.CanRead)
+ {
+ throw new ArgumentException(ExceptionMessages.StreamDoesNotSupportReading, nameof(stream));
+ }
+
+ if (!Enum.IsDefined(typeof(Endianness), endianness))
+ {
+ throw new ArgumentOutOfRangeException(nameof(endianness));
+ }
+
+ var buffer = new byte[sizeof(T)];
+ stream.Read(buffer, 0, buffer.Length);
+ Util.SwapIfNeeded(ref buffer, endianness);
+ return buffer;
+ }
+
+ private static int WriteInternal(this Stream stream, byte[] value, Endianness endianness)
+ {
+ if (stream is null)
+ {
+ throw new ArgumentNullException(nameof(stream));
+ }
+
+ if (!stream.CanWrite)
+ {
+ throw new ArgumentException(ExceptionMessages.StreamDoesNotSupportWriting, nameof(stream));
+ }
+
+ if (!Enum.IsDefined(typeof(Endianness), endianness))
+ {
+ throw new ArgumentOutOfRangeException(nameof(endianness));
+ }
+
+ byte[] clone = (byte[])value.Clone();
+ Util.SwapIfNeeded(ref clone, endianness);
+ var preWritePosition = stream.Position;
+ stream.Write(clone, 0, clone.Length);
+ return (int)(stream.Position - preWritePosition);
+ }
}
}
diff --git a/X10D/src/Util.cs b/X10D/src/Util.cs
new file mode 100644
index 0000000..e7cf77d
--- /dev/null
+++ b/X10D/src/Util.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace X10D
+{
+ internal static class Util
+ {
+ public static void SwapIfNeeded(ref byte[] buffer, Endianness endianness)
+ {
+ if (buffer is null)
+ {
+ throw new ArgumentNullException(nameof(buffer));
+ }
+
+ var swapNeeded = BitConverter.IsLittleEndian == (endianness == Endianness.BigEndian);
+ if (swapNeeded)
+ {
+ Array.Reverse(buffer);
+ }
+ }
+ }
+}