diff --git a/BurnOutSharp.Models/MicrosoftCabinet/MSZIP/Block.cs b/BurnOutSharp.Models/MicrosoftCabinet/MSZIP/Block.cs
index 603cc9af..e53b273f 100644
--- a/BurnOutSharp.Models/MicrosoftCabinet/MSZIP/Block.cs
+++ b/BurnOutSharp.Models/MicrosoftCabinet/MSZIP/Block.cs
@@ -3,7 +3,7 @@ namespace BurnOutSharp.Models.MicrosoftCabinet.MSZIP
///
/// Each MSZIP block MUST consist of a 2-byte MSZIP signature and one or more RFC 1951 blocks. The
/// 2-byte MSZIP signature MUST consist of the bytes 0x43 and 0x4B. The MSZIP signature MUST be
- /// the first 2 bytes in the MSZIP block.The MSZIP signature is shown in the following packet diagram.
+ /// the first 2 bytes in the MSZIP block. The MSZIP signature is shown in the following packet diagram.
///
///
public class Block
diff --git a/BurnOutSharp.Utilities/BitStream.cs b/BurnOutSharp.Utilities/BitStream.cs
new file mode 100644
index 00000000..33e046c4
--- /dev/null
+++ b/BurnOutSharp.Utilities/BitStream.cs
@@ -0,0 +1,147 @@
+using System.Collections;
+using System.IO;
+
+namespace BurnOutSharp.Utilities
+{
+ ///
+ /// Stream that allows reading bits or groups of bits at a time
+ ///
+ public class BitStream
+ {
+ ///
+ /// Underlying stream to read from
+ ///
+ private readonly Stream _stream;
+
+ ///
+ /// Bit array representing the current byte in the stream
+ ///
+ private BitArray _bitBuffer;
+
+ ///
+ /// Next bit position to read from in the buffer
+ ///
+ private int _bitPosition;
+
+ public BitStream(byte[] data)
+ {
+ _stream = new MemoryStream(data);
+ _bitBuffer = null;
+ _bitPosition = -1;
+ }
+
+ public BitStream(Stream data)
+ {
+ _stream = data;
+ _bitBuffer = null;
+ _bitPosition = -1;
+ }
+
+ ///
+ /// Read an array of bits from the input
+ ///
+ /// Number of bits to read
+ /// Array representing the read bits, null on error
+ public BitArray ReadBits(int bitCount)
+ {
+ // If we have an invalid bit count
+ if (bitCount <= 0)
+ return null;
+
+ // If we have an invalid bit buffer
+ if (_bitBuffer == null || _bitPosition < 0 || _bitPosition >= 8)
+ RefreshBuffer();
+
+ // Create an array to hold the bits
+ BitArray bits = new BitArray(bitCount);
+
+ // Loop through and populate the bits
+ for (int i = 0; i < bitCount; i++)
+ {
+ // Read the next bit from the buffer
+ bits[i] = _bitBuffer[_bitPosition++];
+
+ // Attempt to refresh the buffer if we need to
+ if (_bitPosition < 0 || _bitPosition > 7)
+ {
+ // If the refresh failed
+ if (!RefreshBuffer())
+ break;
+ }
+ }
+
+ // Return the bits
+ return bits;
+ }
+
+ ///
+ /// Read an array of bytes from the input
+ ///
+ /// Number of bytes to read
+ /// Array representing the read bytes, null on error
+ public byte[] ReadBytes(int byteCount)
+ {
+ // If we have an invalid byte count
+ if (byteCount <= 0)
+ return null;
+
+ // Get the corresponding bit array
+ BitArray bits = ReadBits(byteCount * 8);
+ if (bits == null)
+ return null;
+
+ // Create the byte array
+ byte[] bytes = new byte[byteCount];
+
+ // Initialize the loop variables
+ byte byt = 0; int bitNumber = 0, byteNumber = 0;
+
+ // Loop and build the byte array
+ for (int i = 0; i < bits.Length; i++)
+ {
+ // Add the new bit to the byte
+ byt <<= 1;
+ byt |= (byte)(bits[i] ? 1 : 0);
+ bitNumber++;
+
+ // If we are at the end of a byte
+ if (bitNumber == 8)
+ {
+ bytes[byteNumber++] = byt;
+ bitNumber = 0;
+ }
+ }
+
+ // Add the last byte
+ bytes[byteNumber] = byt;
+
+ return bytes;
+ }
+
+ ///
+ /// Discard the remaining bits in the buffer
+ ///
+ public void DiscardBuffer() => RefreshBuffer();
+
+ ///
+ /// Refresh the bit buffer from the data source
+ ///
+ /// True if the buffer refreshed, false otherwise
+ private bool RefreshBuffer()
+ {
+ // If we ran out of bytes
+ if (_stream.Position >= _stream.Length)
+ {
+ _bitBuffer = null;
+ _bitPosition = -1;
+ return false;
+ }
+
+ // Read the next byte and reset
+ byte next = _stream.ReadByteValue();
+ _bitBuffer = new BitArray(new byte[] { next });
+ _bitPosition = 0;
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/BurnOutSharp.Utilities/Extensions.cs b/BurnOutSharp.Utilities/Extensions.cs
index fd44a235..3a5ed2b0 100644
--- a/BurnOutSharp.Utilities/Extensions.cs
+++ b/BurnOutSharp.Utilities/Extensions.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
@@ -29,6 +30,146 @@ namespace BurnOutSharp.Utilities
#endregion
+ #region BitArray
+
+ ///
+ /// Convert a bit array into a byte
+ ///
+ public static byte AsByte(this BitArray array)
+ {
+ byte value = 0;
+
+ int maxValue = Math.Min(8, array.Length);
+ for (int i = 0; i < maxValue; i++)
+ {
+ value <<= 1;
+ value |= (byte)(array[i] ? 1 : 0);
+ }
+
+ return value;
+ }
+
+ ///
+ /// Convert a bit array into an sbyte
+ ///
+ public static sbyte AsSByte(this BitArray array)
+ {
+ sbyte value = 0;
+
+ int maxValue = Math.Min(8, array.Length);
+ for (int i = 0; i < maxValue; i++)
+ {
+ value <<= 1;
+ value |= (sbyte)(array[i] ? 1 : 0);
+ }
+
+ return value;
+ }
+
+ ///
+ /// Convert a bit array into a short
+ ///
+ public static short AsInt16(this BitArray array)
+ {
+ short value = 0;
+
+ int maxValue = Math.Min(16, array.Length);
+ for (int i = 0; i < maxValue; i++)
+ {
+ value <<= 1;
+ value |= (short)(array[i] ? 1 : 0);
+ }
+
+ return value;
+ }
+
+ ///
+ /// Convert a bit array into a ushort
+ ///
+ public static ushort AsUInt16(this BitArray array)
+ {
+ ushort value = 0;
+
+ int maxValue = Math.Min(16, array.Length);
+ for (int i = 0; i < maxValue; i++)
+ {
+ value <<= 1;
+ value |= (ushort)(array[i] ? 1 : 0);
+ }
+
+ return value;
+ }
+
+ ///
+ /// Convert a bit array into an int
+ ///
+ public static int AsInt32(this BitArray array)
+ {
+ int value = 0;
+
+ int maxValue = Math.Min(32, array.Length);
+ for (int i = 0; i < maxValue; i++)
+ {
+ value <<= 1;
+ value |= (int)(array[i] ? 1 : 0);
+ }
+
+ return value;
+ }
+
+ ///
+ /// Convert a bit array into a uint
+ ///
+ public static uint AsUInt32(this BitArray array)
+ {
+ uint value = 0;
+
+ int maxValue = Math.Min(32, array.Length);
+ for (int i = 0; i < maxValue; i++)
+ {
+ value <<= 1;
+ value |= (uint)(array[i] ? 1 : 0);
+ }
+
+ return value;
+ }
+
+ ///
+ /// Convert a bit array into a long
+ ///
+ public static long AsInt64(this BitArray array)
+ {
+ long value = 0;
+
+ int maxValue = Math.Min(64, array.Length);
+ for (int i = 0; i < maxValue; i++)
+ {
+ value <<= 1;
+ value |= (long)(array[i] ? 1 : 0);
+ }
+
+ return value;
+ }
+
+ ///
+ /// Convert a bit array into a ulong
+ ///
+ public static ulong AsUInt64(this BitArray array)
+ {
+ ulong value = 0;
+
+ int maxValue = Math.Min(64, array.Length);
+ for (int i = 0; i < maxValue; i++)
+ {
+ value <<= 1;
+ value |= (ulong)(array[i] ? 1 : 0);
+ }
+
+ return value;
+ }
+
+ #endregion
+
#region Byte Array Reading
///
diff --git a/BurnOutSharp/FileType/MicrosoftCAB.MSZIP.cs b/BurnOutSharp/FileType/MicrosoftCAB.MSZIP.cs
index 3f0d769b..c42a4846 100644
--- a/BurnOutSharp/FileType/MicrosoftCAB.MSZIP.cs
+++ b/BurnOutSharp/FileType/MicrosoftCAB.MSZIP.cs
@@ -44,18 +44,18 @@ namespace BurnOutSharp.FileType
public static class MSZIPDynamicHuffmanCompressedBlockBuilder
{
- public static DynamicHuffmanCompressedBlock Create(MSZIPDeflateStream stream)
+ public static DynamicHuffmanCompressedBlock Create(BitStream stream)
{
DynamicHuffmanCompressedBlock dynamicHuffmanCompressedBlock = new DynamicHuffmanCompressedBlock();
// # of Literal/Length codes - 257
- ulong HLIT = stream.ReadBitsLSB(5) + 257;
+ ulong HLIT = stream.ReadBits(5).AsUInt64() + 257;
// # of Distance codes - 1
- ulong HDIST = stream.ReadBitsLSB(5) + 1;
+ ulong HDIST = stream.ReadBits(5).AsUInt64() + 1;
// HCLEN, # of Code Length codes - 4
- ulong HCLEN = stream.ReadBitsLSB(5) + 4;
+ ulong HCLEN = stream.ReadBits(5).AsUInt64() + 4;
// (HCLEN + 4) x 3 bits: code lengths for the code length
// alphabet given just above
@@ -66,7 +66,7 @@ namespace BurnOutSharp.FileType
// length) is not used.
int[] codeLengthAlphabet = new int[19];
for (ulong i = 0; i < HCLEN; i++)
- codeLengthAlphabet[MSZIPDeflate.BitLengthOrder[i]] = (int)stream.ReadBitsLSB(3);
+ codeLengthAlphabet[MSZIPDeflate.BitLengthOrder[i]] = (int)stream.ReadBits(3).AsUInt64();
for (ulong i = HCLEN; i < 19; i++)
codeLengthAlphabet[MSZIPDeflate.BitLengthOrder[i]] = 0;
@@ -88,7 +88,7 @@ namespace BurnOutSharp.FileType
///
/// The alphabet for code lengths is as follows
///
- private static int[] BuildHuffmanTree(MSZIPDeflateStream stream, ulong codeCount, int[] codeLengths)
+ private static int[] BuildHuffmanTree(BitStream stream, ulong codeCount, int[] codeLengths)
{
// Setup the huffman tree
int[] tree = new int[codeCount];
@@ -97,7 +97,7 @@ namespace BurnOutSharp.FileType
int lastCode = 0, repeatLength = 0;
for (ulong i = 0; i < codeCount; i++)
{
- int code = codeLengths[(int)stream.ReadBitsLSB(7)];
+ int code = codeLengths[(int)stream.ReadBits(7).AsUInt64()];
// Represent code lengths of 0 - 15
if (code > 0 && code <= 15)
@@ -111,7 +111,7 @@ namespace BurnOutSharp.FileType
// Example: Codes 8, 16 (+2 bits 11), 16 (+2 bits 10) will expand to 12 code lengths of 8 (1 + 6 + 5)
else if (code == 16)
{
- repeatLength = (int)stream.ReadBitsLSB(2);
+ repeatLength = (int)stream.ReadBits(2).AsUInt64();
repeatLength += 2;
code = lastCode;
}
@@ -120,7 +120,7 @@ namespace BurnOutSharp.FileType
// (3 bits of length)
else if (code == 17)
{
- repeatLength = (int)stream.ReadBitsLSB(3);
+ repeatLength = (int)stream.ReadBits(3).AsUInt64();
repeatLength += 3;
code = 0;
}
@@ -129,7 +129,7 @@ namespace BurnOutSharp.FileType
// (7 bits of length)
else if (code == 18)
{
- repeatLength = (int)stream.ReadBitsLSB(7);
+ repeatLength = (int)stream.ReadBits(7).AsUInt64();
repeatLength += 11;
code = 0;
}
@@ -329,7 +329,7 @@ namespace BurnOutSharp.FileType
///
/// The decoding algorithm for the actual data
///
- public static void Decode(MSZIPDeflateStream data)
+ public static void Decode(BitStream data)
{
// Create the output byte array
List decodedBytes = new List();
@@ -339,7 +339,7 @@ namespace BurnOutSharp.FileType
do
{
- ulong header = data.ReadBitsLSB(3);
+ ulong header = data.ReadBits(3).AsUInt64();
block = MSZIPDeflateBlockBuilder.Create(header);
// We should never get a reserved block
@@ -350,15 +350,15 @@ namespace BurnOutSharp.FileType
if (block.BTYPE == DeflateCompressionType.NoCompression)
{
// Skip any remaining bits in current partially processed byte
- data.DiscardToByteBoundary();
+ data.DiscardBuffer();
// Read LEN and NLEN
- byte[] nonCompressedHeader = data.ReadBytesLSB(4);
+ byte[] nonCompressedHeader = data.ReadBytes(4);
block.BlockData = MSZIPNonCompressedBlockBuilder.Create(nonCompressedHeader);
// Copy LEN bytes of data to output
ushort length = ((NonCompressedBlock)block.BlockData).LEN;
- ((NonCompressedBlock)block.BlockData).Data = data.ReadBytesLSB(length);
+ ((NonCompressedBlock)block.BlockData).Data = data.ReadBytes(length);
decodedBytes.AddRange(((NonCompressedBlock)block.BlockData).Data);
}
@@ -383,7 +383,7 @@ namespace BurnOutSharp.FileType
while (true)
{
// Decode literal/length value from input stream
- int symbol = literalDecodeTable[data.ReadBitsLSB(9)];
+ int symbol = literalDecodeTable[data.ReadBits(9).AsUInt64()];
// Copy value (literal byte) to output stream
if (symbol < 256)
@@ -398,12 +398,12 @@ namespace BurnOutSharp.FileType
else
{
// Decode distance from input stream
- ulong length = data.ReadBitsLSB(LiteralExtraBits[symbol]);
+ ulong length = data.ReadBits(LiteralExtraBits[symbol]).AsUInt64();
length += (ulong)LiteralLengths[symbol];
int code = distanceDecodeTable[length];
- ulong distance = data.ReadBitsLSB(DistanceExtraBits[code]);
+ ulong distance = data.ReadBits(DistanceExtraBits[code]).AsUInt64();
distance += (ulong)DistanceOffsets[code];
@@ -535,398 +535,5 @@ namespace BurnOutSharp.FileType
}
}
- ///
- public class MSZIPDeflateStream
- {
- #region Instance Variables
-
- ///
- /// Original data source to read from
- ///
- private System.IO.Stream _dataStream = null;
-
- ///
- /// Current rolling buffer
- ///
- private byte[] _buffer = null;
-
- ///
- /// Current position in the buffer
- ///
- private int _bufferPointer = -1;
-
- ///
- /// Bit buffer to read bits from when necessary
- ///
- private BitArray _bitBuffer = null;
-
- ///
- /// Number of bits left in the buffer
- ///
- private int _bitsLeft = 0;
-
- #endregion
-
- ///
- /// Constructor
- ///
- public MSZIPDeflateStream(System.IO.Stream dataStream)
- {
- _dataStream = dataStream;
- }
-
- ///
- /// Read between 0 and 64 bits of data from the stream assuming LSB
- ///
- ///
- public ulong ReadBitsLSB(int numBits)
- {
- // If we are reading an invalid number of bits
- if (numBits < 0 || numBits > 64)
- throw new ArgumentOutOfRangeException();
-
- // Allocate the bit buffer
- ulong bitBuffer = 0;
-
- // If the bit buffer has the right number remaining
- if (_bitsLeft >= numBits)
- {
- for (int i = 0; i < numBits; i++)
- {
- bitBuffer |= _bitBuffer[i + _bitBuffer.Length - _bitsLeft--] ? 1u : 0;
- bitBuffer <<= 1;
- }
-
- return bitBuffer;
- }
-
- // Otherwise, we need to read what we can
- int bitsRemaining = _bitsLeft;
- for (int i = 0; i < bitsRemaining; i++)
- {
- bitBuffer |= _bitBuffer[i + _bitBuffer.Length - _bitsLeft--] ? 1u : 0;
- bitBuffer <<= 1;
- }
-
- // Fill the bit buffer, if possible
- FillBitBuffer();
-
- // If we couldn't read anything, throw an exception
- if (_buffer == null)
- throw new IndexOutOfRangeException();
-
- // Otherwise, read in the remaining bits needed
- for (int i = 0; i < bitsRemaining; i++)
- {
- bitBuffer |= _bitBuffer[i + _bitBuffer.Length - _bitsLeft--] ? 1u : 0;
- bitBuffer <<= 1;
- }
-
- return bitBuffer;
- }
-
- ///
- /// Read between 0 and 64 bits of data from the stream assuming MSB
- ///
- ///
- public ulong ReadBitsMSB(int numBits)
- {
- // If we are reading an invalid number of bits
- if (numBits < 0 || numBits > 64)
- throw new ArgumentOutOfRangeException();
-
- // Allocate the bit buffer
- ulong bitBuffer = 0;
-
- // If the bit buffer has the right number remaining
- if (_bitsLeft >= numBits)
- {
- for (int i = 0; i < numBits; i++)
- {
- bitBuffer |= _bitBuffer[i + _bitsLeft--] ? 1u : 0;
- bitBuffer <<= 1;
- }
-
- return bitBuffer;
- }
-
- // Otherwise, we need to read what we can
- int bitsRemaining = _bitsLeft;
- for (int i = 0; i < bitsRemaining; i++)
- {
- bitBuffer |= _bitBuffer[i + _bitsLeft--] ? 1u : 0;
- bitBuffer <<= 1;
- }
-
- // Fill the bit buffer, if possible
- FillBitBuffer();
-
- // If we couldn't read anything, throw an exception
- if (_buffer == null)
- throw new IndexOutOfRangeException();
-
- // Otherwise, read in the remaining bits needed
- for (int i = 0; i < bitsRemaining; i++)
- {
- bitBuffer |= _bitBuffer[i + _bitsLeft--] ? 1u : 0;
- bitBuffer <<= 1;
- }
-
- return bitBuffer;
- }
-
- ///
- /// Read more than 0 bytes of data from the stream assuming LSB
- ///
- public byte[] ReadBytesLSB(int numBytes)
- {
- // If we are reading an invalid number of bytes
- if (numBytes < 0)
- throw new ArgumentOutOfRangeException();
-
- // Allocate the byte buffer
- byte[] byteBuffer = new byte[numBytes];
- int byteBufferPtr = 0;
-
- // If the bit buffer has the right number remaining
- if (_bitsLeft >= numBytes * 8)
- {
- byte fullBitBuffer = 0;
- for (int i = 0; i < numBytes * 8; i++)
- {
- fullBitBuffer |= (byte)(_bitBuffer[i + _bitBuffer.Length - _bitsLeft--] ? 1 : 0);
- if (i % 8 == 7)
- {
- byteBuffer[byteBufferPtr++] = fullBitBuffer;
- fullBitBuffer = 0;
- }
- else
- {
- fullBitBuffer <<= 1;
- }
- }
-
- byteBuffer[byteBufferPtr++] = fullBitBuffer;
- return byteBuffer;
- }
-
- // Otherwise, we need to read what we can
- int bitsRemaining = _bitsLeft;
-
- byte bitBuffer = 0;
- for (int i = 0; i < numBytes * 8; i++)
- {
- bitBuffer |= (byte)(_bitBuffer[i + _bitBuffer.Length - _bitsLeft--] ? 1 : 0);
- if (i % 8 == 7)
- {
- byteBuffer[byteBufferPtr++] = bitBuffer;
- bitBuffer = 0;
- }
- else
- {
- bitBuffer <<= 1;
- }
- }
-
- // Fill the bit buffer, if possible
- FillBitBuffer();
-
- // If we couldn't read anything, throw an exception
- if (_buffer == null)
- throw new IndexOutOfRangeException();
-
- // Otherwise, read in the remaining bits needed
- for (int i = 0; i < bitsRemaining; i++)
- {
- bitBuffer |= (byte)(_bitBuffer[i + _bitBuffer.Length - _bitsLeft--] ? 1 : 0);
- if (i % 8 == 7)
- {
- byteBuffer[byteBufferPtr++] = bitBuffer;
- bitBuffer = 0;
- }
- else
- {
- bitBuffer <<= 1;
- }
- }
-
- byteBuffer[byteBufferPtr++] = bitBuffer;
- return byteBuffer;
- }
-
- ///
- /// Read more than 0 bytes of data from the stream assuming MSB
- ///
- public byte[] ReadBytesMSB(int numBytes)
- {
- // If we are reading an invalid number of bytes
- if (numBytes < 0)
- throw new ArgumentOutOfRangeException();
-
- // Allocate the byte buffer
- byte[] byteBuffer = new byte[numBytes];
- int byteBufferPtr = 0;
-
- // If the bit buffer has the right number remaining
- if (_bitsLeft >= numBytes * 8)
- {
- byte fullBitBuffer = 0;
- for (int i = 0; i < numBytes * 8; i++)
- {
- fullBitBuffer |= (byte)(_bitBuffer[i + _bitsLeft--] ? 1 : 0);
- if (i % 8 == 7)
- {
- byteBuffer[byteBufferPtr++] = fullBitBuffer;
- fullBitBuffer = 0;
- }
- else
- {
- fullBitBuffer <<= 1;
- }
- }
-
- byteBuffer[byteBufferPtr++] = fullBitBuffer;
- return byteBuffer;
- }
-
- // Otherwise, we need to read what we can
- int bitsRemaining = _bitsLeft;
-
- byte bitBuffer = 0;
- for (int i = 0; i < numBytes * 8; i++)
- {
- bitBuffer |= (byte)(_bitBuffer[i + _bitsLeft--] ? 1 : 0);
- if (i % 8 == 7)
- {
- byteBuffer[byteBufferPtr++] = bitBuffer;
- bitBuffer = 0;
- }
- else
- {
- bitBuffer <<= 1;
- }
- }
-
- // Fill the bit buffer, if possible
- FillBitBuffer();
-
- // If we couldn't read anything, throw an exception
- if (_buffer == null)
- throw new IndexOutOfRangeException();
-
- // Otherwise, read in the remaining bits needed
- for (int i = 0; i < bitsRemaining; i++)
- {
- bitBuffer |= (byte)(_bitBuffer[i + _bitsLeft--] ? 1 : 0);
- if (i % 8 == 7)
- {
- byteBuffer[byteBufferPtr++] = bitBuffer;
- bitBuffer = 0;
- }
- else
- {
- bitBuffer <<= 1;
- }
- }
-
- byteBuffer[byteBufferPtr++] = bitBuffer;
- return byteBuffer;
- }
-
- ///
- /// Discard bits in the array up to the next byte boundary
- ///
- public void DiscardToByteBoundary()
- {
- int bitsToDiscard = _bitsLeft & 7;
- _bitsLeft -= bitsToDiscard;
- }
-
- ///
- /// Fill the internal bit buffer from the internal buffer
- ///
- /// Fills up to 4 bytes worth of data at a time
- private void FillBitBuffer()
- {
- // If we have 4 bytes left, just create the bit buffer directly
- if (_bufferPointer < _buffer.Length - 4)
- {
- // Read all 4 bytes directly
- byte[] readAllBytes = new ReadOnlySpan(_buffer, _bufferPointer, 4).ToArray();
- _bufferPointer += 4;
-
- // Create the new bit buffer
- _bitBuffer = new BitArray(readAllBytes);
- _bitsLeft = 32;
- return;
- }
-
- // If we have less than 4 bytes left, we need to get creative
- // Create the byte array to hold the data
- byte[] bytes = new byte[4];
-
- // Read what we can first
- int bytesRemaining = _buffer.Length - _bufferPointer;
- if (bytesRemaining > 0)
- {
- byte[] readBytesRemaining = new ReadOnlySpan(_buffer, _bufferPointer, bytesRemaining).ToArray();
- Array.Copy(readBytesRemaining, 0, bytes, 0, bytesRemaining);
- _bufferPointer += bytesRemaining;
- }
-
- // Fill the buffer, if we can
- FillBuffer();
-
- // If we couldn't read anything, reset the buffer
- if (_buffer == null && bytesRemaining == 4)
- {
- _bitBuffer = null;
- _bitsLeft = 0;
- return;
- }
-
- // If we don't have anything left, just create a bit array
- if (_buffer == null)
- {
- byte[] readBytesRemaining = new ReadOnlySpan(bytes, 0, bytesRemaining).ToArray();
- _bitBuffer = new BitArray(readBytesRemaining);
- _bitsLeft = 8 * bytesRemaining;
- return;
- }
-
- // Otherwise, we want to read in the remaining necessary bytes
- int bytesToRead = 4 - bytesRemaining;
- byte[] bytesRead = new ReadOnlySpan(_buffer, _bufferPointer, bytesToRead).ToArray();
- _bufferPointer += bytesToRead;
-
- Array.Copy(bytesRead, 0, bytes, bytesRemaining, bytesToRead);
- _bitBuffer = new BitArray(bytes);
- _bitsLeft = 32;
- }
-
- ///
- /// Fill the internal buffer from the original data source
- ///
- /// Reads up to 4096 bytes at a time
- private void FillBuffer()
- {
- // Get the amount of bytes to read
- int bytesRemaining = (int)(_dataStream.Length - _dataStream.Position);
- int bytesToRead = Math.Min(bytesRemaining, 4096);
-
- // If we can't ready any bytes, reset the buffer
- if (bytesToRead == 0)
- {
- _buffer = null;
- _bufferPointer = -1;
- return;
- }
-
- // Otherwise, read and reset the position
- _buffer = _dataStream.ReadBytes(bytesToRead);
- _bufferPointer = 0;
- }
- }
-
#endregion
}