diff --git a/ByteArrayExtensions.cs b/ByteArrayExtensions.cs
new file mode 100644
index 0000000..8941e50
--- /dev/null
+++ b/ByteArrayExtensions.cs
@@ -0,0 +1,166 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace SabreTools.IO
+{
+ ///
+ /// Extensions for byte arrays
+ ///
+ /// TODO: Add U/Int24 and U/Int48 methods
+ /// TODO: Add big-endian methods
+ public static class ByteArrayExtensions
+ {
+ ///
+ /// Read a byte and increment the pointer to an array
+ ///
+ public static byte ReadByte(this byte[] content, ref int offset)
+ {
+ return content[offset++];
+ }
+
+ ///
+ /// Read a byte array and increment the pointer to an array
+ ///
+#if NET48
+ public static byte[] ReadBytes(this byte[] content, ref int offset, int count)
+#else
+ public static byte[]? ReadBytes(this byte[] content, ref int offset, int count)
+#endif
+ {
+ // If there's an invalid byte count, don't do anything
+ if (count <= 0)
+ return null;
+
+ byte[] buffer = new byte[count];
+ Array.Copy(content, offset, buffer, 0, Math.Min(count, content.Length - offset));
+ offset += count;
+ return buffer;
+ }
+
+ ///
+ /// Read an sbyte and increment the pointer to an array
+ ///
+ public static sbyte ReadSByte(this byte[] content, ref int offset)
+ {
+ return (sbyte)content[offset++];
+ }
+
+ ///
+ /// Read a char and increment the pointer to an array
+ ///
+ public static char ReadChar(this byte[] content, ref int offset)
+ {
+ return (char)content[offset++];
+ }
+
+ ///
+ /// Read a short and increment the pointer to an array
+ ///
+ public static short ReadInt16(this byte[] content, ref int offset)
+ {
+ short value = BitConverter.ToInt16(content, offset);
+ offset += 2;
+ return value;
+ }
+
+ ///
+ /// Read a ushort and increment the pointer to an array
+ ///
+ public static ushort ReadUInt16(this byte[] content, ref int offset)
+ {
+ ushort value = BitConverter.ToUInt16(content, offset);
+ offset += 2;
+ return value;
+ }
+
+ ///
+ /// Read a int and increment the pointer to an array
+ ///
+ public static int ReadInt32(this byte[] content, ref int offset)
+ {
+ int value = BitConverter.ToInt32(content, offset);
+ offset += 4;
+ return value;
+ }
+
+ ///
+ /// Read a uint and increment the pointer to an array
+ ///
+ public static uint ReadUInt32(this byte[] content, ref int offset)
+ {
+ uint value = BitConverter.ToUInt32(content, offset);
+ offset += 4;
+ return value;
+ }
+
+ ///
+ /// Read a long and increment the pointer to an array
+ ///
+ public static long ReadInt64(this byte[] content, ref int offset)
+ {
+ long value = BitConverter.ToInt64(content, offset);
+ offset += 8;
+ return value;
+ }
+
+ ///
+ /// Read a ulong and increment the pointer to an array
+ ///
+ public static ulong ReadUInt64(this byte[] content, ref int offset)
+ {
+ ulong value = BitConverter.ToUInt64(content, offset);
+ offset += 8;
+ return value;
+ }
+
+ ///
+ /// Read a Guid from the stream
+ ///
+ public static Guid ReadGuid(this byte[] content, ref int offset)
+ {
+ byte[] buffer = new byte[16];
+ Array.Copy(content, offset, buffer, 0, 16);
+ offset += 16;
+ return new Guid(buffer);
+ }
+
+ ///
+ /// Read a null-terminated string from the stream
+ ///
+#if NET48
+ public static string ReadString(this byte[] content, ref int offset) => content.ReadString(ref offset, Encoding.Default);
+#else
+ public static string? ReadString(this byte[] content, ref int offset) => content.ReadString(ref offset, Encoding.Default);
+#endif
+
+ ///
+ /// Read a null-terminated string from the stream
+ ///
+#if NET48
+ public static string ReadString(this byte[] content, ref int offset, Encoding encoding)
+#else
+ public static string? ReadString(this byte[] content, ref int offset, Encoding encoding)
+#endif
+ {
+ if (offset >= content.Length)
+ return null;
+
+ byte[] nullTerminator = encoding.GetBytes(new char[] { '\0' });
+ int charWidth = nullTerminator.Length;
+
+ List keyChars = new List();
+ while (offset < content.Length)
+ {
+ char c = encoding.GetChars(content, offset, charWidth)[0];
+ keyChars.Add(c);
+ offset += charWidth;
+
+ if (c == '\0')
+ break;
+ }
+
+ return new string(keyChars.ToArray()).TrimEnd('\0');
+ }
+ }
+}
\ No newline at end of file
diff --git a/StreamExtensions.cs b/StreamExtensions.cs
index c6286be..d8f400b 100644
--- a/StreamExtensions.cs
+++ b/StreamExtensions.cs
@@ -1,12 +1,247 @@
-using System.IO;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
namespace SabreTools.IO
{
///
- /// Extensions to Stream functionality
+ /// Extensions for Streams
///
+ /// TODO: Add U/Int24 and U/Int48 methods
public static class StreamExtensions
{
+ ///
+ /// Read a byte from the stream
+ ///
+ public static byte ReadByteValue(this Stream stream)
+ {
+ byte[] buffer = new byte[1];
+ stream.Read(buffer, 0, 1);
+ return buffer[0];
+ }
+
+ ///
+ /// Read a byte array from the stream
+ ///
+#if NET48
+ public static byte[] ReadBytes(this Stream stream, int count)
+#else
+ public static byte[]? ReadBytes(this Stream stream, int count)
+#endif
+ {
+ // 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;
+ }
+
+ ///
+ /// Read an sbyte from the stream
+ ///
+ public static sbyte ReadSByte(this Stream stream)
+ {
+ byte[] buffer = new byte[1];
+ stream.Read(buffer, 0, 1);
+ return (sbyte)buffer[0];
+ }
+
+ ///
+ /// Read a character from the stream
+ ///
+ public static char ReadChar(this Stream stream)
+ {
+ byte[] buffer = new byte[1];
+ stream.Read(buffer, 0, 1);
+ return (char)buffer[0];
+ }
+
+ ///
+ /// Read a short from the stream
+ ///
+ public static short ReadInt16(this Stream stream)
+ {
+ byte[] buffer = new byte[2];
+ stream.Read(buffer, 0, 2);
+ return BitConverter.ToInt16(buffer, 0);
+ }
+
+ ///
+ /// Read a short from the stream in big-endian format
+ ///
+ 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);
+ }
+
+ ///
+ /// Read a ushort from the stream
+ ///
+ public static ushort ReadUInt16(this Stream stream)
+ {
+ byte[] buffer = new byte[2];
+ stream.Read(buffer, 0, 2);
+ return BitConverter.ToUInt16(buffer, 0);
+ }
+
+ ///
+ /// Read a ushort from the stream in big-endian format
+ ///
+ 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);
+ }
+
+ ///
+ /// Read an int from the stream
+ ///
+ public static int ReadInt32(this Stream stream)
+ {
+ byte[] buffer = new byte[4];
+ stream.Read(buffer, 0, 4);
+ return BitConverter.ToInt32(buffer, 0);
+ }
+
+ ///
+ /// Read an int from the stream in big-endian format
+ ///
+ 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);
+ }
+
+ ///
+ /// Read a uint from the stream
+ ///
+ public static uint ReadUInt32(this Stream stream)
+ {
+ byte[] buffer = new byte[4];
+ stream.Read(buffer, 0, 4);
+ return BitConverter.ToUInt32(buffer, 0);
+ }
+
+ ///
+ /// Read a uint from the stream in big-endian format
+ ///
+ 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);
+ }
+
+ ///
+ /// Read a long from the stream
+ ///
+ public static long ReadInt64(this Stream stream)
+ {
+ byte[] buffer = new byte[8];
+ stream.Read(buffer, 0, 8);
+ return BitConverter.ToInt64(buffer, 0);
+ }
+
+ ///
+ /// Read a long from the stream in big-endian format
+ ///
+ 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);
+ }
+
+ ///
+ /// Read a ulong from the stream
+ ///
+ public static ulong ReadUInt64(this Stream stream)
+ {
+ byte[] buffer = new byte[8];
+ stream.Read(buffer, 0, 8);
+ return BitConverter.ToUInt64(buffer, 0);
+ }
+
+ ///
+ /// Read a ulong from the stream in big-endian format
+ ///
+ 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);
+ }
+
+ ///
+ /// Read a Guid from the stream
+ ///
+ public static Guid ReadGuid(this Stream stream)
+ {
+ byte[] buffer = new byte[16];
+ stream.Read(buffer, 0, 16);
+ return new Guid(buffer);
+ }
+
+ ///
+ /// Read a Guid from the stream in big-endian format
+ ///
+ public static Guid ReadGuidBigEndian(this Stream stream)
+ {
+ byte[] buffer = new byte[16];
+ stream.Read(buffer, 0, 16);
+ Array.Reverse(buffer);
+ return new Guid(buffer);
+ }
+
+ ///
+ /// Read a null-terminated string from the stream
+ ///
+#if NET48
+ public static string ReadString(this Stream stream) => stream.ReadString(Encoding.Default);
+#else
+ public static string? ReadString(this Stream stream) => stream.ReadString(Encoding.Default);
+#endif
+
+ ///
+ /// Read a null-terminated string from the stream
+ ///
+#if NET48
+ public static string ReadString(this Stream stream, Encoding encoding)
+#else
+ public static string? ReadString(this Stream stream, Encoding encoding)
+#endif
+ {
+ if (stream.Position >= stream.Length)
+ return null;
+
+ byte[] nullTerminator = encoding.GetBytes(new char[] { '\0' });
+ int charWidth = nullTerminator.Length;
+
+ List tempBuffer = new List();
+
+ 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());
+ }
+
///
/// Seek to a specific point in the stream, if possible
///