mirror of
https://github.com/SabreTools/SabreTools.IO.git
synced 2026-10-01 19:12:59 +00:00
275 lines
8.2 KiB
C#
275 lines
8.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
#if !NET20
|
|
using System.Linq;
|
|
#endif
|
|
using System.Text;
|
|
|
|
namespace SabreTools.IO
|
|
{
|
|
/// <summary>
|
|
/// Extensions for Streams
|
|
/// </summary>
|
|
/// <remarks>TODO: Add U/Int24 and U/Int48 methods</remarks>
|
|
public static class StreamExtensions
|
|
{
|
|
/// <summary>
|
|
/// Read a UInt8 from the stream
|
|
/// </summary>
|
|
public static byte ReadByteValue(this Stream stream)
|
|
{
|
|
byte[] buffer = new byte[1];
|
|
stream.Read(buffer, 0, 1);
|
|
return buffer[0];
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read a UInt8[] from the stream
|
|
/// </summary>
|
|
public static byte[]? ReadBytes(this Stream stream, int count)
|
|
{
|
|
// If there's an invalid byte count, don't do anything
|
|
if (count <= 0)
|
|
return null;
|
|
|
|
byte[] buffer = new byte[count];
|
|
stream.Read(buffer, 0, count);
|
|
return buffer;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read a Int8 from the stream
|
|
/// </summary>
|
|
public static sbyte ReadSByte(this Stream stream)
|
|
{
|
|
byte[] buffer = new byte[1];
|
|
stream.Read(buffer, 0, 1);
|
|
return (sbyte)buffer[0];
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read a Char from the stream
|
|
/// </summary>
|
|
public static char ReadChar(this Stream stream)
|
|
{
|
|
byte[] buffer = new byte[1];
|
|
stream.Read(buffer, 0, 1);
|
|
return (char)buffer[0];
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read a Int16 from the stream
|
|
/// </summary>
|
|
public static short ReadInt16(this Stream stream)
|
|
{
|
|
byte[] buffer = new byte[2];
|
|
stream.Read(buffer, 0, 2);
|
|
return BitConverter.ToInt16(buffer, 0);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read a Int16 from the stream in big-endian format
|
|
/// </summary>
|
|
public static short ReadInt16BigEndian(this Stream stream)
|
|
{
|
|
byte[] buffer = new byte[2];
|
|
stream.Read(buffer, 0, 2);
|
|
Array.Reverse(buffer);
|
|
return BitConverter.ToInt16(buffer, 0);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read a UInt16 from the stream
|
|
/// </summary>
|
|
public static ushort ReadUInt16(this Stream stream)
|
|
{
|
|
byte[] buffer = new byte[2];
|
|
stream.Read(buffer, 0, 2);
|
|
return BitConverter.ToUInt16(buffer, 0);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read a UInt16 from the stream in big-endian format
|
|
/// </summary>
|
|
public static ushort ReadUInt16BigEndian(this Stream stream)
|
|
{
|
|
byte[] buffer = new byte[2];
|
|
stream.Read(buffer, 0, 2);
|
|
Array.Reverse(buffer);
|
|
return BitConverter.ToUInt16(buffer, 0);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read an Int32 from the stream
|
|
/// </summary>
|
|
public static int ReadInt32(this Stream stream)
|
|
{
|
|
byte[] buffer = new byte[4];
|
|
stream.Read(buffer, 0, 4);
|
|
return BitConverter.ToInt32(buffer, 0);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read an Int32 from the stream in big-endian format
|
|
/// </summary>
|
|
public static int ReadInt32BigEndian(this Stream stream)
|
|
{
|
|
byte[] buffer = new byte[4];
|
|
stream.Read(buffer, 0, 4);
|
|
Array.Reverse(buffer);
|
|
return BitConverter.ToInt32(buffer, 0);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read a UInt32 from the stream
|
|
/// </summary>
|
|
public static uint ReadUInt32(this Stream stream)
|
|
{
|
|
byte[] buffer = new byte[4];
|
|
stream.Read(buffer, 0, 4);
|
|
return BitConverter.ToUInt32(buffer, 0);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read a UInt32 from the stream in big-endian format
|
|
/// </summary>
|
|
public static uint ReadUInt32BigEndian(this Stream stream)
|
|
{
|
|
byte[] buffer = new byte[4];
|
|
stream.Read(buffer, 0, 4);
|
|
Array.Reverse(buffer);
|
|
return BitConverter.ToUInt32(buffer, 0);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read a Int64 from the stream
|
|
/// </summary>
|
|
public static long ReadInt64(this Stream stream)
|
|
{
|
|
byte[] buffer = new byte[8];
|
|
stream.Read(buffer, 0, 8);
|
|
return BitConverter.ToInt64(buffer, 0);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read a Int64 from the stream in big-endian format
|
|
/// </summary>
|
|
public static long ReadInt64BigEndian(this Stream stream)
|
|
{
|
|
byte[] buffer = new byte[8];
|
|
stream.Read(buffer, 0, 8);
|
|
Array.Reverse(buffer);
|
|
return BitConverter.ToInt64(buffer, 0);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read a UInt64 from the stream
|
|
/// </summary>
|
|
public static ulong ReadUInt64(this Stream stream)
|
|
{
|
|
byte[] buffer = new byte[8];
|
|
stream.Read(buffer, 0, 8);
|
|
return BitConverter.ToUInt64(buffer, 0);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read a UInt64 from the stream in big-endian format
|
|
/// </summary>
|
|
public static ulong ReadUInt64BigEndian(this Stream stream)
|
|
{
|
|
byte[] buffer = new byte[8];
|
|
stream.Read(buffer, 0, 8);
|
|
Array.Reverse(buffer);
|
|
return BitConverter.ToUInt64(buffer, 0);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read a Guid from the stream
|
|
/// </summary>
|
|
public static Guid ReadGuid(this Stream stream)
|
|
{
|
|
byte[] buffer = new byte[16];
|
|
stream.Read(buffer, 0, 16);
|
|
return new Guid(buffer);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read a Guid from the stream in big-endian format
|
|
/// </summary>
|
|
public static Guid ReadGuidBigEndian(this Stream stream)
|
|
{
|
|
byte[] buffer = new byte[16];
|
|
stream.Read(buffer, 0, 16);
|
|
Array.Reverse(buffer);
|
|
return new Guid(buffer);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read a null-terminated string from the stream
|
|
/// </summary>
|
|
public static string? ReadString(this Stream stream) => stream.ReadString(Encoding.Default);
|
|
|
|
/// <summary>
|
|
/// Read a null-terminated string from the stream
|
|
/// </summary>
|
|
public static string? ReadString(this Stream stream, Encoding encoding)
|
|
{
|
|
if (stream.Position >= stream.Length)
|
|
return null;
|
|
|
|
byte[] nullTerminator = encoding.GetBytes(new char[] { '\0' });
|
|
int charWidth = nullTerminator.Length;
|
|
|
|
List<byte> tempBuffer = new List<byte>();
|
|
|
|
byte[] buffer = new byte[charWidth];
|
|
while (stream.Position < stream.Length && stream.Read(buffer, 0, charWidth) != 0 && !buffer.SequenceEqual(nullTerminator))
|
|
{
|
|
tempBuffer.AddRange(buffer);
|
|
}
|
|
|
|
return encoding.GetString(tempBuffer.ToArray());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Seek to a specific point in the stream, if possible
|
|
/// </summary>
|
|
/// <param name="input">Input stream to try seeking on</param>
|
|
/// <param name="offset">Optional offset to seek to</param>
|
|
public static long SeekIfPossible(this Stream input, long offset = 0)
|
|
{
|
|
// If the stream is null, don't even try
|
|
if (input == null)
|
|
return -1;
|
|
|
|
// If the input is not seekable, just return the current position
|
|
if (!input.CanSeek)
|
|
{
|
|
try
|
|
{
|
|
return input.Position;
|
|
}
|
|
catch
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
// Attempt to seek to the offset
|
|
try
|
|
{
|
|
if (offset < 0)
|
|
return input.Seek(offset, SeekOrigin.End);
|
|
else if (offset >= 0)
|
|
return input.Seek(offset, SeekOrigin.Begin);
|
|
|
|
return input.Position;
|
|
}
|
|
catch
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
}
|