Change Blast.Decompress to use Stream I/O.
This commit is contained in:
@@ -57,10 +57,13 @@ namespace OpenRA.FileFormats
|
||||
static Huffman lencode = new Huffman(lenlen, lenlen.Length, 16);
|
||||
static Huffman distcode = new Huffman(distlen, distlen.Length, 64);
|
||||
|
||||
// Decode PKWare Compression Library stream.
|
||||
public static byte[] Decompress(byte[] src)
|
||||
/// <summary>PKWare Compression Library stream.</summary>
|
||||
/// <param name="input">Compressed input stream.</param>
|
||||
/// <param name="output">Stream to write the decompressed output.</param>
|
||||
/// <param name="onProgress">Progress callback, invoked with (read bytes, written bytes).</param>
|
||||
public static void Decompress(Stream input, Stream output, Action<long, long> onProgress = null)
|
||||
{
|
||||
var br = new BitReader(src);
|
||||
var br = new BitReader(input);
|
||||
|
||||
// Are literals coded?
|
||||
var coded = br.ReadBits(8);
|
||||
@@ -78,7 +81,9 @@ namespace OpenRA.FileFormats
|
||||
ushort next = 0; // index of next write location in out[]
|
||||
var first = true; // true to check distances (for first 4K)
|
||||
var outBuffer = new byte[MAXWIN]; // output buffer and sliding window
|
||||
var ms = new MemoryStream();
|
||||
|
||||
var inputStart = input.Position;
|
||||
var outputStart = output.Position;
|
||||
|
||||
// decode literals and length/distance pairs
|
||||
do
|
||||
@@ -94,7 +99,10 @@ namespace OpenRA.FileFormats
|
||||
if (len == 519)
|
||||
{
|
||||
for (var i = 0; i < next; i++)
|
||||
ms.WriteByte(outBuffer[i]);
|
||||
output.WriteByte(outBuffer[i]);
|
||||
|
||||
if (onProgress != null)
|
||||
onProgress(input.Position - inputStart, output.Position - outputStart);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -137,9 +145,12 @@ namespace OpenRA.FileFormats
|
||||
if (next == MAXWIN)
|
||||
{
|
||||
for (var i = 0; i < next; i++)
|
||||
ms.WriteByte(outBuffer[i]);
|
||||
output.WriteByte(outBuffer[i]);
|
||||
next = 0;
|
||||
first = false;
|
||||
|
||||
if (onProgress != null)
|
||||
onProgress(input.Position - inputStart, output.Position - outputStart);
|
||||
}
|
||||
} while (len != 0);
|
||||
}
|
||||
@@ -151,14 +162,15 @@ namespace OpenRA.FileFormats
|
||||
if (next == MAXWIN)
|
||||
{
|
||||
for (var i = 0; i < next; i++)
|
||||
ms.WriteByte(outBuffer[i]);
|
||||
output.WriteByte(outBuffer[i]);
|
||||
next = 0;
|
||||
first = false;
|
||||
|
||||
if (onProgress != null)
|
||||
onProgress(input.Position - inputStart, output.Position - outputStart);
|
||||
}
|
||||
}
|
||||
} while (true);
|
||||
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
// Decode a code using Huffman table h.
|
||||
@@ -185,14 +197,13 @@ namespace OpenRA.FileFormats
|
||||
|
||||
class BitReader
|
||||
{
|
||||
readonly byte[] src;
|
||||
int offset = 0;
|
||||
int bitBuffer = 0;
|
||||
readonly Stream stream;
|
||||
byte bitBuffer = 0;
|
||||
int bitCount = 0;
|
||||
|
||||
public BitReader(byte[] src)
|
||||
public BitReader(Stream stream)
|
||||
{
|
||||
this.src = src;
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
public int ReadBits(int count)
|
||||
@@ -203,7 +214,7 @@ namespace OpenRA.FileFormats
|
||||
{
|
||||
if (bitCount == 0)
|
||||
{
|
||||
bitBuffer = src[offset++];
|
||||
bitBuffer = stream.ReadUInt8();
|
||||
bitCount = 8;
|
||||
}
|
||||
|
||||
|
||||
@@ -114,9 +114,12 @@ namespace OpenRA.FileSystem
|
||||
return null;
|
||||
|
||||
s.Seek(dataStart + e.Offset, SeekOrigin.Begin);
|
||||
var data = s.ReadBytes((int)e.Length);
|
||||
|
||||
return new MemoryStream(Blast.Decompress(data));
|
||||
var ret = new MemoryStream();
|
||||
Blast.Decompress(s, ret);
|
||||
ret.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public bool Contains(string filename)
|
||||
|
||||
@@ -183,13 +183,13 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
|
||||
case "extract-raw":
|
||||
{
|
||||
ExtractFromPackage(ExtractionType.Raw, path, i.Value, extracted, ref message);
|
||||
ExtractFromPackage(ExtractionType.Raw, path, i.Value, extracted, m => message = m);
|
||||
break;
|
||||
}
|
||||
|
||||
case "extract-blast":
|
||||
{
|
||||
ExtractFromPackage(ExtractionType.Blast, path, i.Value, extracted, ref message);
|
||||
ExtractFromPackage(ExtractionType.Blast, path, i.Value, extracted, m => message = m);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
|
||||
enum ExtractionType { Raw, Blast }
|
||||
|
||||
static void ExtractFromPackage(ExtractionType type, string path, MiniYaml actionYaml, List<string> extractedFiles, ref string progressMessage)
|
||||
static void ExtractFromPackage(ExtractionType type, string path, MiniYaml actionYaml, List<string> extractedFiles, Action<string> updateMessage)
|
||||
{
|
||||
var sourcePath = Path.Combine(path, actionYaml.Value);
|
||||
using (var source = File.OpenRead(sourcePath))
|
||||
@@ -265,15 +265,20 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(targetPath));
|
||||
using (var target = File.OpenWrite(targetPath))
|
||||
{
|
||||
// This is a bit dumb memory-wise, but we load the whole thing when running the game anyway
|
||||
Log.Write("install", "Extracting {0} -> {1}".F(sourcePath, targetPath));
|
||||
progressMessage = "Extracting " + Path.GetFileName(Path.GetFileName(targetPath));
|
||||
|
||||
var data = source.ReadBytes(length);
|
||||
var displayFilename = Path.GetFileName(Path.GetFileName(targetPath));
|
||||
if (type == ExtractionType.Blast)
|
||||
data = Blast.Decompress(data);
|
||||
|
||||
target.Write(data);
|
||||
{
|
||||
Action<long, long> onProgress = (read, _) =>
|
||||
updateMessage("Extracting " + displayFilename + " ({0}%)".F(100 * read / length));
|
||||
Blast.Decompress(source, target, onProgress);
|
||||
}
|
||||
else
|
||||
{
|
||||
updateMessage("Extracting " + displayFilename);
|
||||
// This is a bit dumb memory-wise, but we load the whole thing when running the game anyway
|
||||
target.Write(source.ReadBytes(length));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user