diff --git a/BitStream.cs b/BitStream.cs
deleted file mode 100644
index 3d54d86..0000000
--- a/BitStream.cs
+++ /dev/null
@@ -1,239 +0,0 @@
-using System;
-using System.IO;
-using SabreTools.IO;
-
-// TODO: Add more complete implementation to SabreTools.IO
-namespace SabreTools.Compression
-{
- ///
- /// Wrapper to allow reading bits from a source stream
- ///
- public class BitStream
- {
- ///
- public long Position => _source.Position;
-
- ///
- public long Length => _source.Length;
-
- ///
- /// Original stream source
- ///
- private readonly Stream _source;
-
- ///
- /// Last read byte value from the stream
- ///
- private byte? _bitBuffer;
-
- ///
- /// Index in the byte of the current bit
- ///
- private int _bitIndex;
-
- ///
- /// Create a new BitStream from a source Stream
- ///
- public BitStream(Stream? source)
- {
- if (source == null || !source.CanRead || !source.CanSeek)
- throw new ArgumentException(nameof(source));
-
- _source = source;
- _bitBuffer = null;
- _bitIndex = 0;
- }
-
- ///
- /// Discard the current cached byte
- ///
- public void Discard()
- {
- _bitBuffer = null;
- _bitIndex = 0;
- }
-
- ///
- /// Read a single bit, if possible
- ///
- /// The next bit encoded in a byte, null on error or end of stream
- public byte? ReadBit()
- {
- // If we reached the end of the stream
- if (_source.Position >= _source.Length)
- return null;
-
- // If we don't have a value cached
- if (_bitBuffer == null)
- {
- // Read the next byte, if possible
- _bitBuffer = ReadSourceByte();
- if (_bitBuffer == null)
- return null;
-
- // Reset the bit index
- _bitIndex = 0;
- }
-
- // Get the value by bit-shifting
- int value = _bitBuffer.Value & 0x01;
- _bitBuffer = (byte?)(_bitBuffer >> 1);
- _bitIndex++;
-
- // Reset the byte if we're at the end
- if (_bitIndex >= 8)
- Discard();
-
- return (byte)value;
- }
-
- ///
- /// Read a multiple bits in LSB, if possible
- ///
- /// The next bits encoded in a UInt32, null on error or end of stream
- public uint? ReadBitsLSB(int bits)
- {
- uint value = 0;
- for (int i = 0; i < bits; i++)
- {
- // Read the next bit
- byte? bitValue = ReadBit();
- if (bitValue == null)
- return null;
-
- // Add the bit shifted by the current index
- value += (uint)(bitValue.Value << i);
- }
-
- return value;
- }
-
- ///
- /// Read a multiple bits in MSB, if possible
- ///
- /// The next bits encoded in a UInt32, null on error or end of stream
- public uint? ReadBitsMSB(int bits)
- {
- uint value = 0;
- for (int i = 0; i < bits; i++)
- {
- // Read the next bit
- byte? bitValue = ReadBit();
- if (bitValue == null)
- return null;
-
- // Add the bit shifted by the current index
- value += (value << 1) + bitValue.Value;
- }
-
- return value;
- }
-
- ///
- /// Read a byte, if possible
- ///
- /// The next byte, null on error or end of stream
- /// Assumes the stream is byte-aligned
- public byte? ReadByte()
- {
- try
- {
- Discard();
- return _source.ReadByteValue();
- }
- catch
- {
- return null;
- }
- }
-
- ///
- /// Read a UInt16, if possible
- ///
- /// The next UInt16, null on error or end of stream
- /// Assumes the stream is byte-aligned
- public ushort? ReadUInt16()
- {
- try
- {
- Discard();
- return _source.ReadUInt16();
- }
- catch
- {
- return null;
- }
- }
-
- ///
- /// Read a UInt32, if possible
- ///
- /// The next UInt32, null on error or end of stream
- /// Assumes the stream is byte-aligned
- public uint? ReadUInt32()
- {
- try
- {
- Discard();
- return _source.ReadUInt32();
- }
- catch
- {
- return null;
- }
- }
-
- ///
- /// Read a UInt64, if possible
- ///
- /// The next UInt64, null on error or end of stream
- /// Assumes the stream is byte-aligned
- public ulong? ReadUInt64()
- {
- try
- {
- Discard();
- return _source.ReadUInt64();
- }
- catch
- {
- return null;
- }
- }
-
- ///
- /// Read bytes, if possible
- ///
- /// Number of bytes to read
- /// The next bytes, null on error or end of stream
- /// Assumes the stream is byte-aligned
- public byte[]? ReadBytes(int bytes)
- {
- try
- {
- Discard();
- return _source.ReadBytes(bytes);
- }
- catch
- {
- return null;
- }
- }
-
- ///
- /// Read a single byte from the underlying stream, if possible
- ///
- /// The next full byte from the stream, null on error or end of stream
- private byte? ReadSourceByte()
- {
- try
- {
- return _source.ReadByteValue();
- }
- catch
- {
- return null;
- }
- }
- }
-}
\ No newline at end of file
diff --git a/LZ/Decompressor.cs b/LZ/Decompressor.cs
index 3d7aae5..70543fd 100644
--- a/LZ/Decompressor.cs
+++ b/LZ/Decompressor.cs
@@ -1,7 +1,7 @@
using System.IO;
using System.Linq;
using System.Text;
-using SabreTools.IO;
+using SabreTools.IO.Extensions;
using SabreTools.Models.Compression.LZ;
using static SabreTools.Models.Compression.LZ.Constants;
diff --git a/MSZIP/DeflateDecompressor.cs b/MSZIP/DeflateDecompressor.cs
index aba582e..34d8060 100644
--- a/MSZIP/DeflateDecompressor.cs
+++ b/MSZIP/DeflateDecompressor.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using SabreTools.IO.Streams;
using SabreTools.Models.Compression.MSZIP;
using static SabreTools.Models.Compression.MSZIP.Constants;
@@ -13,7 +14,7 @@ namespace SabreTools.Compression.MSZIP
///
/// Internal bitstream to use for decompression
///
- private readonly BitStream _bitStream;
+ private readonly ReadOnlyBitStream _bitStream;
///
/// Create a new Decompressor from a byte array
@@ -28,8 +29,8 @@ namespace SabreTools.Compression.MSZIP
// Create a memory stream to wrap
var ms = new MemoryStream(input);
- // Wrap the stream in a BitStream
- _bitStream = new BitStream(ms);
+ // Wrap the stream in a ReadOnlyBitStream
+ _bitStream = new ReadOnlyBitStream(ms);
}
///
@@ -42,8 +43,8 @@ namespace SabreTools.Compression.MSZIP
if (input == null || !input.CanRead || !input.CanSeek)
throw new ArgumentException(nameof(input));
- // Wrap the stream in a BitStream
- _bitStream = new BitStream(input);
+ // Wrap the stream in a ReadOnlyBitStream
+ _bitStream = new ReadOnlyBitStream(input);
}
///
diff --git a/MSZIP/HuffmanDecoder.cs b/MSZIP/HuffmanDecoder.cs
index 8dbb8d0..1f954b8 100644
--- a/MSZIP/HuffmanDecoder.cs
+++ b/MSZIP/HuffmanDecoder.cs
@@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Linq;
+using SabreTools.IO.Streams;
namespace SabreTools.Compression.MSZIP
{
@@ -83,7 +84,7 @@ namespace SabreTools.Compression.MSZIP
///
/// BitStream representing the input
/// Value of the node described by the input
- public int Decode(BitStream input)
+ public int Decode(ReadOnlyBitStream input)
{
// Start at the root of the tree
var node = _root;
diff --git a/Quantum/Decompressor.cs b/Quantum/Decompressor.cs
index abdd674..dc7d752 100644
--- a/Quantum/Decompressor.cs
+++ b/Quantum/Decompressor.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using SabreTools.IO.Streams;
using SabreTools.Models.Compression.Quantum;
using static SabreTools.Compression.Quantum.Constants;
@@ -12,7 +13,7 @@ namespace SabreTools.Compression.Quantum
///
/// Internal bitstream to use for decompression
///
- private BitStream _bitStream;
+ private readonly ReadOnlyBitStream _bitStream;
#region Models
@@ -100,8 +101,8 @@ namespace SabreTools.Compression.Quantum
// Create a memory stream to wrap
var ms = new MemoryStream(input);
- // Wrap the stream in a BitStream
- _bitStream = new BitStream(ms);
+ // Wrap the stream in a ReadOnlyBitStream
+ _bitStream = new ReadOnlyBitStream(ms);
// Initialize literal models
this._model0 = CreateModel(0, 64);
@@ -140,8 +141,8 @@ namespace SabreTools.Compression.Quantum
if (windowBits < 10 || windowBits > 21)
throw new ArgumentOutOfRangeException(nameof(windowBits));
- // Wrap the stream in a BitStream
- _bitStream = new BitStream(input);
+ // Wrap the stream in a ReadOnlyBitStream
+ _bitStream = new ReadOnlyBitStream(input);
// Initialize literal models
this._model0 = CreateModel(0, 64);