mirror of https://github.com/oliverbooth/X10D
Introduces type: - Endianness Introduces Read methods: - ReadInt16 - ReadInt32 - ReadInt64 - ReadUInt16 - ReadUInt32 - ReadUInt64 Introduces Write methods: - Write(short) - Write(int) - Write(long) - Write(ushort) - Write(uint) - Write(ulong) Introduces internal "Util" class to provide internal-only helper methods - SwapIfNeeded (reverse a buffer on Endianness mismatch)
This commit is contained in:
parent
ef9dc29e42
commit
99fd511714
|
@ -0,0 +1,16 @@
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
|
namespace X10D
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an enumeration of endianness values.
|
||||||
|
/// </summary>
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,9 @@ namespace X10D.StreamExtensions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class StreamExtensions
|
public static class StreamExtensions
|
||||||
{
|
{
|
||||||
|
private static readonly Endianness DefaultEndianness =
|
||||||
|
BitConverter.IsLittleEndian ? Endianness.LittleEndian : Endianness.BigEndian;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the hash of a stream using the specified hash algorithm.
|
/// Returns the hash of a stream using the specified hash algorithm.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -49,5 +52,359 @@ namespace X10D.StreamExtensions
|
||||||
|
|
||||||
return crypt.ComputeHash(stream);
|
return crypt.ComputeHash(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream to read.</param>
|
||||||
|
/// <returns>A 2-byte signed integer read from the current stream.</returns>
|
||||||
|
public static short ReadInt16(this Stream stream)
|
||||||
|
{
|
||||||
|
return stream.ReadInt16(DefaultEndianness);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream to read.</param>
|
||||||
|
/// <param name="endianness">The endian encoding to use.</param>
|
||||||
|
/// <returns>A 2-byte signed integer read from the current stream.</returns>
|
||||||
|
public static short ReadInt16(this Stream stream, Endianness endianness)
|
||||||
|
{
|
||||||
|
var value = ReadInternal<short>(stream, endianness);
|
||||||
|
return BitConverter.ToInt16(value, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream to read.</param>
|
||||||
|
/// <returns>A 4-byte signed integer read from the current stream.</returns>
|
||||||
|
public static int ReadInt32(this Stream stream)
|
||||||
|
{
|
||||||
|
return stream.ReadInt32(DefaultEndianness);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream to read.</param>
|
||||||
|
/// <param name="endianness">The endian encoding to use.</param>
|
||||||
|
/// <returns>A 4-byte signed integer read from the current stream.</returns>
|
||||||
|
public static int ReadInt32(this Stream stream, Endianness endianness)
|
||||||
|
{
|
||||||
|
var value = ReadInternal<int>(stream, endianness);
|
||||||
|
return BitConverter.ToInt32(value, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream to read.</param>
|
||||||
|
/// <returns>An 8-byte signed integer read from the current stream.</returns>
|
||||||
|
public static long ReadInt64(this Stream stream)
|
||||||
|
{
|
||||||
|
return stream.ReadInt64(DefaultEndianness);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream to read.</param>
|
||||||
|
/// <param name="endianness">The endian encoding to use.</param>
|
||||||
|
/// <returns>An 8-byte signed integer read from the current stream.</returns>
|
||||||
|
public static long ReadInt64(this Stream stream, Endianness endianness)
|
||||||
|
{
|
||||||
|
var value = ReadInternal<long>(stream, endianness);
|
||||||
|
return BitConverter.ToInt64(value, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream to read.</param>
|
||||||
|
/// <returns>A 2-byte unsigned integer read from the current stream.</returns>
|
||||||
|
public static ushort ReadUInt16(this Stream stream)
|
||||||
|
{
|
||||||
|
return stream.ReadUInt16(DefaultEndianness);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream to read.</param>
|
||||||
|
/// <param name="endianness">The endian encoding to use.</param>
|
||||||
|
/// <returns>A 2-byte unsigned integer read from the current stream.</returns>
|
||||||
|
public static ushort ReadUInt16(this Stream stream, Endianness endianness)
|
||||||
|
{
|
||||||
|
var value = ReadInternal<ushort>(stream, endianness);
|
||||||
|
return BitConverter.ToUInt16(value, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream to read.</param>
|
||||||
|
/// <returns>A 4-byte unsigned integer read from the current stream.</returns>
|
||||||
|
public static uint ReadUInt32(this Stream stream)
|
||||||
|
{
|
||||||
|
return stream.ReadUInt32(DefaultEndianness);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream to read.</param>
|
||||||
|
/// <param name="endianness">The endian encoding to use.</param>
|
||||||
|
/// <returns>A 4-byte unsigned integer read from the current stream.</returns>
|
||||||
|
public static uint ReadUInt32(this Stream stream, Endianness endianness)
|
||||||
|
{
|
||||||
|
var value = ReadInternal<uint>(stream, endianness);
|
||||||
|
return BitConverter.ToUInt32(value, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream to read.</param>
|
||||||
|
/// <returns>An 8-byte unsigned integer read from the current stream.</returns>
|
||||||
|
public static ulong ReadUInt64(this Stream stream)
|
||||||
|
{
|
||||||
|
return stream.ReadUInt64(DefaultEndianness);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream to read.</param>
|
||||||
|
/// <param name="endianness">The endian encoding to use.</param>
|
||||||
|
/// <returns>An 8-byte unsigned integer read from the current stream.</returns>
|
||||||
|
public static ulong ReadUInt64(this Stream stream, Endianness endianness)
|
||||||
|
{
|
||||||
|
var value = ReadInternal<ulong>(stream, endianness);
|
||||||
|
return BitConverter.ToUInt64(value, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream to which the value should be written.</param>
|
||||||
|
/// <param name="value">The two-byte signed integer to write.</param>
|
||||||
|
/// <returns>The number of bytes written to the stream.</returns>
|
||||||
|
public static int Write(this Stream stream, short value)
|
||||||
|
{
|
||||||
|
return stream.Write(value, DefaultEndianness);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a two-byte signed integer to the current stream using the specified endian encoding, and advances the
|
||||||
|
/// stream position by two bytes.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream to which the value should be written.</param>
|
||||||
|
/// <param name="value">The two-byte signed integer to write.</param>
|
||||||
|
/// <param name="endianness">The endian encoding to use.</param>
|
||||||
|
/// <returns>The number of bytes written to the stream.</returns>
|
||||||
|
public static int Write(this Stream stream, short value, Endianness endianness)
|
||||||
|
{
|
||||||
|
var buffer = BitConverter.GetBytes(value);
|
||||||
|
return stream.WriteInternal(buffer, endianness);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream to which the value should be written.</param>
|
||||||
|
/// <param name="value">The four-byte signed integer to write.</param>
|
||||||
|
/// <returns>The number of bytes written to the stream.</returns>
|
||||||
|
public static int Write(this Stream stream, int value)
|
||||||
|
{
|
||||||
|
return stream.Write(value, DefaultEndianness);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a four-byte signed integer to the current stream using the specified endian encoding, and advances the
|
||||||
|
/// stream position by four bytes.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream to which the value should be written.</param>
|
||||||
|
/// <param name="value">The four-byte signed integer to write.</param>
|
||||||
|
/// <param name="endianness">The endian encoding to use.</param>
|
||||||
|
/// <returns>The number of bytes written to the stream.</returns>
|
||||||
|
public static int Write(this Stream stream, int value, Endianness endianness)
|
||||||
|
{
|
||||||
|
var buffer = BitConverter.GetBytes(value);
|
||||||
|
return stream.WriteInternal(buffer, endianness);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream to which the value should be written.</param>
|
||||||
|
/// <param name="value">The eight-byte signed integer to write.</param>
|
||||||
|
/// <returns>The number of bytes written to the stream.</returns>
|
||||||
|
public static int Write(this Stream stream, long value)
|
||||||
|
{
|
||||||
|
return stream.Write(value, DefaultEndianness);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes an eight-byte signed integer to the current stream using the specified endian encoding, and advances the
|
||||||
|
/// stream position by eight bytes.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream to which the value should be written.</param>
|
||||||
|
/// <param name="value">The eight-byte signed integer to write.</param>
|
||||||
|
/// <param name="endianness">The endian encoding to use.</param>
|
||||||
|
/// <returns>The number of bytes written to the stream.</returns>
|
||||||
|
public static int Write(this Stream stream, long value, Endianness endianness)
|
||||||
|
{
|
||||||
|
var buffer = BitConverter.GetBytes(value);
|
||||||
|
return stream.WriteInternal(buffer, endianness);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream to which the value should be written.</param>
|
||||||
|
/// <param name="value">The two-byte unsigned integer to write.</param>
|
||||||
|
/// <returns>The number of bytes written to the stream.</returns>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public static int Write(this Stream stream, ushort value)
|
||||||
|
{
|
||||||
|
return stream.Write(value, DefaultEndianness);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a two-byte unsigned integer to the current stream using the specified endian encoding, and advances the
|
||||||
|
/// stream position by two bytes.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream to which the value should be written.</param>
|
||||||
|
/// <param name="value">The two-byte unsigned integer to write.</param>
|
||||||
|
/// <param name="endianness">The endian encoding to use.</param>
|
||||||
|
/// <returns>The number of bytes written to the stream.</returns>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public static int Write(this Stream stream, ushort value, Endianness endianness)
|
||||||
|
{
|
||||||
|
var buffer = BitConverter.GetBytes(value);
|
||||||
|
return stream.WriteInternal(buffer, endianness);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream to which the value should be written.</param>
|
||||||
|
/// <param name="value">The four-byte unsigned integer to write.</param>
|
||||||
|
/// <returns>The number of bytes written to the stream.</returns>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public static int Write(this Stream stream, uint value)
|
||||||
|
{
|
||||||
|
return stream.Write(value, DefaultEndianness);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a four-byte unsigned integer to the current stream using the specified endian encoding, and advances the
|
||||||
|
/// stream position by four bytes.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream to which the value should be written.</param>
|
||||||
|
/// <param name="value">The four-byte unsigned integer to write.</param>
|
||||||
|
/// <param name="endianness">The endian encoding to use.</param>
|
||||||
|
/// <returns>The number of bytes written to the stream.</returns>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public static int Write(this Stream stream, uint value, Endianness endianness)
|
||||||
|
{
|
||||||
|
var buffer = BitConverter.GetBytes(value);
|
||||||
|
return stream.WriteInternal(buffer, endianness);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream to which the value should be written.</param>
|
||||||
|
/// <param name="value">The eight-byte unsigned integer to write.</param>
|
||||||
|
/// <returns>The number of bytes written to the stream.</returns>
|
||||||
|
[CLSCompliant(false)]
|
||||||
|
public static int Write(this Stream stream, ulong value)
|
||||||
|
{
|
||||||
|
return stream.Write(value, DefaultEndianness);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes an eight-byte signed integer to the current stream using the specified endian encoding, and advances the
|
||||||
|
/// stream position by eight bytes.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream to which the value should be written.</param>
|
||||||
|
/// <param name="value">The eight-byte signed integer to write.</param>
|
||||||
|
/// <param name="endianness">The endian encoding to use.</param>
|
||||||
|
/// <returns>The number of bytes written to the stream.</returns>
|
||||||
|
[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<T>(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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue