Skip to content

Commit 97a83b4

Browse files
committed
Make Blast like others
1 parent b2fe81d commit 97a83b4

File tree

2 files changed

+58
-38
lines changed

2 files changed

+58
-38
lines changed

SabreTools.Compression/Blast/BlastDecoder.cs renamed to SabreTools.Compression/Blast/Decompressor.cs

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,29 +30,40 @@
3030
*/
3131

3232
using System;
33-
using System.Collections.Generic;
33+
using System.IO;
3434
using static SabreTools.Compression.Blast.Constants;
3535

3636
namespace SabreTools.Compression.Blast
3737
{
38-
public unsafe static class BlastDecoder
38+
/// <summary>
39+
/// blast() decompresses the PKWare Data Compression Library (DCL) compressed
40+
/// format. It provides the same functionality as the explode() function in
41+
/// that library. (Note: PKWare overused the "implode" verb, and the format
42+
/// used by their library implode() function is completely different and
43+
/// incompatible with the implode compression method supported by PKZIP.)
44+
///
45+
/// The binary mode for stdio functions should be used to assure that the
46+
/// compressed data is not corrupted when read or written. For example:
47+
/// fopen(..., "rb") and fopen(..., "wb").
48+
/// </summary>
49+
public unsafe class Decompressor
3950
{
4051
#region Huffman Encoding
4152

4253
/// <summary>
4354
/// Literal code
4455
/// </summary>
45-
private static readonly Huffman litcode = new(MAXBITS + 1, 256);
56+
private readonly Huffman litcode = new(MAXBITS + 1, 256);
4657

4758
/// <summary>
4859
/// Length code
4960
/// </summary>
50-
private static readonly Huffman lencode = new(MAXBITS + 1, 16);
61+
private readonly Huffman lencode = new(MAXBITS + 1, 16);
5162

5263
/// <summary>
5364
/// Distance code
5465
/// </summary>
55-
private static readonly Huffman distcode = new(MAXBITS + 1, 64);
66+
private readonly Huffman distcode = new(MAXBITS + 1, 64);
5667

5768
/// <summary>
5869
/// Base for length codes
@@ -72,10 +83,12 @@ public unsafe static class BlastDecoder
7283

7384
#endregion
7485

86+
#region Constructors
87+
7588
/// <summary>
76-
/// Static constructor
89+
/// Create a Blast decompressor
7790
/// </summary>
78-
static BlastDecoder()
91+
private Decompressor()
7992
{
8093
// Repeated code lengths of literal codes
8194
byte[] litlen =
@@ -105,20 +118,29 @@ static BlastDecoder()
105118
}
106119

107120
/// <summary>
108-
/// blast() decompresses the PKWare Data Compression Library (DCL) compressed
109-
/// format. It provides the same functionality as the explode() function in
110-
/// that library. (Note: PKWare overused the "implode" verb, and the format
111-
/// used by their library implode() function is completely different and
112-
/// incompatible with the implode compression method supported by PKZIP.)
113-
///
114-
/// The binary mode for stdio functions should be used to assure that the
115-
/// compressed data is not corrupted when read or written. For example:
116-
/// fopen(..., "rb") and fopen(..., "wb").
121+
/// Create a Blast decompressor
122+
/// </summary>
123+
public static Decompressor Create() => new();
124+
125+
#endregion
126+
127+
/// <summary>
128+
/// Decompress source data to an output stream
129+
/// </summary>
130+
public bool CopyTo(byte[] source, Stream dest)
131+
=> CopyTo(new MemoryStream(source), dest);
132+
133+
/// <summary>
134+
/// Decompress source data to an output stream
117135
/// </summary>
118-
public static int Blast(byte[] inhow, List<byte> outhow)
136+
public bool CopyTo(Stream source, Stream dest)
119137
{
138+
// Ignore unwritable streams
139+
if (!dest.CanWrite)
140+
return false;
141+
120142
// Input/output state
121-
var state = new State(inhow, outhow);
143+
var state = new State(source, dest);
122144

123145
// Attempt to decompress using the above state
124146
int err;
@@ -136,7 +158,7 @@ public static int Blast(byte[] inhow, List<byte> outhow)
136158
if (err != 1 && state.Next != 0 && !state.ProcessOutput() && err == 0)
137159
err = 1;
138160

139-
return err;
161+
return err == 0;
140162
}
141163

142164
/// <summary>
@@ -176,7 +198,7 @@ public static int Blast(byte[] inhow, List<byte> outhow)
176198
/// ignoring whether the length is greater than the distance or not implements
177199
/// this correctly.
178200
/// </remarks>
179-
private static int Decomp(State state)
201+
private int Decomp(State state)
180202
{
181203
int symbol; // decoded symbol, extra bits for distance
182204
int len; // length for copy
@@ -194,7 +216,7 @@ private static int Decomp(State state)
194216
return -2;
195217

196218
// Decode literals and length/distance pairs
197-
do
219+
while (true)
198220
{
199221
if (state.Bits(1) != 0)
200222
{
@@ -256,13 +278,12 @@ private static int Decomp(State state)
256278
{
257279
if (!state.ProcessOutput())
258280
return 1;
259-
281+
260282
state.Next = 0;
261283
state.First = false;
262284
}
263285
}
264286
}
265-
while (true);
266287

267288
return 0;
268289
}

SabreTools.Compression/Blast/State.cs

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
using System;
2-
using System.Collections.Generic;
2+
using System.IO;
33
using static SabreTools.Compression.Blast.Constants;
44

55
namespace SabreTools.Compression.Blast
@@ -14,12 +14,12 @@ public class State
1414
/// <summary>
1515
/// Opaque information passed to InputFunction()
1616
/// </summary>
17-
public byte[] InHow { get; set; }
17+
public Stream Source { get; set; }
1818

1919
/// <summary>
2020
/// Next input location
2121
/// </summary>
22-
public List<byte> Input { get; set; }
22+
public byte[] Input { get; set; }
2323

2424
/// <summary>
2525
/// Pointer to the next input location
@@ -48,7 +48,7 @@ public class State
4848
/// <summary>
4949
/// Opaque information passed to OutputFunction()
5050
/// </summary>
51-
public List<byte> OutHow { get; set; }
51+
public Stream Dest { get; set; }
5252

5353
/// <summary>
5454
/// Index of next write location in out[]
@@ -63,7 +63,7 @@ public class State
6363
/// <summary>
6464
/// Output buffer and sliding window
6565
/// </summary>
66-
public byte[] Output { get; set; } = new byte[MAXWIN];
66+
public readonly byte[] Output = new byte[MAXWIN];
6767

6868
/// <summary>
6969
/// Pointer to the next output location
@@ -75,18 +75,16 @@ public class State
7575
/// <summary>
7676
/// Constructor
7777
/// </summary>
78-
/// <param name="inhow">Input byte array</param>
79-
/// <param name="outhow">Output byte list</param>
80-
public State(byte[] inhow, List<byte> outhow)
78+
public State(Stream source, Stream dest)
8179
{
82-
InHow = inhow;
83-
Input = new List<byte>();
80+
Source = source;
81+
Input = [];
8482
InputPtr = 0;
8583
Left = 0;
8684
BitBuf = 0;
8785
BitCnt = 0;
8886

89-
OutHow = outhow;
87+
Dest = dest;
9088
Next = 0;
9189
First = true;
9290
}
@@ -116,7 +114,7 @@ public int Bits(int need)
116114
}
117115

118116
// Load eight bits
119-
val |= (int)(Input[InputPtr++]) << BitCnt;
117+
val |= Input[InputPtr++] << BitCnt;
120118
Left--;
121119
BitCnt += 8;
122120
}
@@ -135,8 +133,8 @@ public int Bits(int need)
135133
/// <returns>Amount of data in Input</returns>
136134
public uint ProcessInput()
137135
{
138-
Input = [.. InHow];
139-
return (uint)Input.Count;
136+
int read = Source.Read(Input, 0, 4096);
137+
return (uint)read;
140138
}
141139

142140
/// <summary>
@@ -149,7 +147,8 @@ public bool ProcessOutput()
149147
{
150148
byte[] next = new byte[Next];
151149
Array.Copy(Output, next, next.Length);
152-
OutHow.AddRange(next);
150+
Dest.Write(next);
151+
Dest.Flush();
153152
return true;
154153
}
155154
catch

0 commit comments

Comments
 (0)