diff --git a/SabreTools.Compression/Blast/Decompressor.cs b/SabreTools.Compression/Blast/Decompressor.cs
index 721710d..1fb8d44 100644
--- a/SabreTools.Compression/Blast/Decompressor.cs
+++ b/SabreTools.Compression/Blast/Decompressor.cs
@@ -146,7 +146,7 @@ namespace SabreTools.Compression.Blast
int err;
try
{
- err = Decomp(state);
+ err = Decompress(state);
}
catch (IndexOutOfRangeException)
{
@@ -198,7 +198,7 @@ namespace SabreTools.Compression.Blast
/// ignoring whether the length is greater than the distance or not implements
/// this correctly.
///
- private int Decomp(State state)
+ private int Decompress(State state)
{
int symbol; // decoded symbol, extra bits for distance
int len; // length for copy
@@ -207,29 +207,29 @@ namespace SabreTools.Compression.Blast
int from, to; // copy pointers
// Read header
- int lit = state.Bits(8); // true if literals are coded
+ int lit = state.ReadBits(8); // true if literals are coded
if (lit > 1)
return -1;
- int dict = state.Bits(8); // log2(dictionary size) - 6
+ int dict = state.ReadBits(8); // log2(dictionary size) - 6
if (dict < 4 || dict > 6)
return -2;
// Decode literals and length/distance pairs
while (true)
{
- if (state.Bits(1) != 0)
+ if (state.ReadBits(1) != 0)
{
// Get length
symbol = lencode.Decode(state);
- len = baseLength[symbol] + state.Bits(extra[symbol]);
+ len = baseLength[symbol] + state.ReadBits(extra[symbol]);
if (len == 519)
break; // end code
// Get distance
symbol = len == 2 ? 2 : dict;
dist = (uint)(distcode.Decode(state) << symbol);
- dist += (uint)state.Bits(symbol);
+ dist += (uint)state.ReadBits(symbol);
dist++;
if (state.First && dist > state.Next)
return -3; //distance too far back
@@ -237,7 +237,7 @@ namespace SabreTools.Compression.Blast
// Copy length bytes from distance bytes back
do
{
- to = (int)(state.OutputPtr + state.Next);
+ to = (int)state.Next;
from = (int)(to - dist);
copy = MAXWIN;
if (state.Next < dist)
@@ -252,11 +252,7 @@ namespace SabreTools.Compression.Blast
len -= copy;
state.Next += (uint)copy;
- do
- {
- state.Output[to++] = state.Output[from++];
- }
- while (--copy != 0);
+ state.CopyOutputBytes(to, from, copy);
if (state.Next == MAXWIN)
{
@@ -272,8 +268,8 @@ namespace SabreTools.Compression.Blast
else
{
// Get literal and write it
- symbol = lit != 0 ? litcode.Decode(state) : state.Bits(8);
- state.Output[state.Next++] = (byte)symbol;
+ symbol = lit != 0 ? litcode.Decode(state) : state.ReadBits(8);
+ state.WriteToOutput((byte)symbol);
if (state.Next == MAXWIN)
{
if (!state.ProcessOutput())
diff --git a/SabreTools.Compression/Blast/Huffman.cs b/SabreTools.Compression/Blast/Huffman.cs
index 70dd3a6..7629efa 100644
--- a/SabreTools.Compression/Blast/Huffman.cs
+++ b/SabreTools.Compression/Blast/Huffman.cs
@@ -1,4 +1,3 @@
-using System;
using static SabreTools.Compression.Blast.Constants;
namespace SabreTools.Compression.Blast
@@ -187,15 +186,7 @@ namespace SabreTools.Compression.Blast
if (left == 0)
break;
- if (state.Left == 0)
- {
- state.Left = state.ProcessInput();
- if (state.Left == 0)
- throw new IndexOutOfRangeException();
- }
-
- bitbuf = state.Input[state.InputPtr++];
- state.Left--;
+ bitbuf = state.ReadNextByte();
if (left > 8)
left = 8;
}
diff --git a/SabreTools.Compression/Blast/State.cs b/SabreTools.Compression/Blast/State.cs
index 73641e3..b533e97 100644
--- a/SabreTools.Compression/Blast/State.cs
+++ b/SabreTools.Compression/Blast/State.cs
@@ -14,22 +14,22 @@ namespace SabreTools.Compression.Blast
///
/// Opaque information passed to InputFunction()
///
- public Stream Source { get; set; }
-
+ private readonly Stream _source;
+
///
/// Next input location
///
- public byte[] Input { get; set; }
+ private readonly byte[] _input = new byte[MAXWIN];
///
/// Pointer to the next input location
///
- public int InputPtr { get; set; }
+ private int _inputPtr;
///
/// Available input at in
///
- public uint Left { get; set; }
+ private uint _available;
///
/// Bit buffer
@@ -48,7 +48,7 @@ namespace SabreTools.Compression.Blast
///
/// Opaque information passed to OutputFunction()
///
- public Stream Dest { get; set; }
+ private readonly Stream _dest;
///
/// Index of next write location in out[]
@@ -63,12 +63,7 @@ namespace SabreTools.Compression.Blast
///
/// Output buffer and sliding window
///
- public readonly byte[] Output = new byte[MAXWIN];
-
- ///
- /// Pointer to the next output location
- ///
- public int OutputPtr { get; set; }
+ private readonly byte[] _output = new byte[MAXWIN];
#endregion
@@ -77,18 +72,29 @@ namespace SabreTools.Compression.Blast
///
public State(Stream source, Stream dest)
{
- Source = source;
- Input = [];
- InputPtr = 0;
- Left = 0;
+ _source = source;
+ _inputPtr = 0;
+ _available = 0;
BitBuf = 0;
BitCnt = 0;
- Dest = dest;
+ _dest = dest;
Next = 0;
First = true;
}
+ ///
+ /// Copy bytes in the output buffer between locations
+ ///
+ public void CopyOutputBytes(int to, int from, int len)
+ {
+ do
+ {
+ _output[to++] = _output[from++];
+ }
+ while (--len > 0);
+ }
+
///
/// Return need bits from the input stream. This always leaves less than
/// eight bits in the buffer. bits() works properly for need == 0.
@@ -100,22 +106,16 @@ namespace SabreTools.Compression.Blast
/// buffer, using shift right, and new bytes are appended to the top of the
/// bit buffer, using shift left.
///
- public int Bits(int need)
+ public int ReadBits(int need)
{
// Load at least need bits into val
int val = BitBuf;
while (BitCnt < need)
{
- if (Left == 0)
- {
- Left = ProcessInput();
- if (Left == 0)
- throw new IndexOutOfRangeException();
- }
-
// Load eight bits
- val |= Input[InputPtr++] << BitCnt;
- Left--;
+ EnsureAvailable();
+ val |= _input[_inputPtr++] << BitCnt;
+ _available--;
BitCnt += 8;
}
@@ -127,16 +127,6 @@ namespace SabreTools.Compression.Blast
return val & ((1 << need) - 1);
}
- ///
- /// Process input for the current state
- ///
- /// Amount of data in Input
- public uint ProcessInput()
- {
- int read = Source.Read(Input, 0, 4096);
- return (uint)read;
- }
-
///
/// Process output for the current state
///
@@ -145,10 +135,10 @@ namespace SabreTools.Compression.Blast
{
try
{
- byte[] next = new byte[Next];
- Array.Copy(Output, next, next.Length);
- Dest.Write(next);
- Dest.Flush();
+ _dest.Write(_output, 0, (int)Next);
+ _dest.Flush();
+
+ Next = 0;
return true;
}
catch
@@ -156,5 +146,39 @@ namespace SabreTools.Compression.Blast
return false;
}
}
+
+ ///
+ /// Read the next byte from the input buffer
+ ///
+ public byte ReadNextByte()
+ {
+ EnsureAvailable();
+ return _input[_inputPtr++];
+ }
+
+ ///
+ /// Write a byte value to the output buffer
+ ///
+ public void WriteToOutput(byte value)
+ => _output[Next++] = value;
+
+ ///
+ /// Ensure there are bytes available, if possible
+ ///
+ ///
+ private void EnsureAvailable()
+ {
+ // If there are bytes
+ if (_inputPtr < _available)
+ return;
+
+ // Read the next block
+ _available = (uint)_source.Read(_input, 0, MAXWIN);
+ if (_available == 0)
+ throw new IndexOutOfRangeException();
+
+ // Reset the pointer
+ _inputPtr = 0;
+ }
}
}
\ No newline at end of file