Stream MSCab extraction output.

This commit is contained in:
Paul Chote
2016-06-16 20:56:57 +01:00
parent a9a5b9bc71
commit 63782aad2e
2 changed files with 26 additions and 26 deletions

View File

@@ -87,42 +87,44 @@ namespace OpenRA.Mods.Common.FileFormats
files[i] = new CabFile(stream); files[i] = new CabFile(stream);
} }
public byte[] ExtractFile(string filename, Action<int> onProgress = null) public void ExtractFile(string filename, Stream output, Action<int> onProgress = null)
{ {
var file = files.FirstOrDefault(f => f.FileName == filename); var file = files.FirstOrDefault(f => f.FileName == filename);
if (file == null) if (file == null)
return null; throw new FileNotFoundException(filename);
var folder = folders[file.FolderIndex]; var folder = folders[file.FolderIndex];
stream.Seek(folder.BlockOffset, SeekOrigin.Begin); stream.Seek(folder.BlockOffset, SeekOrigin.Begin);
using (var outputStream = new MemoryStream()) var inflater = new Inflater(true);
var buffer = new byte[4096];
var decompressedBytes = 0;
for (var i = 0; i < folder.BlockCount; i++)
{ {
var inflater = new Inflater(true); if (onProgress != null)
var buffer = new byte[4096]; onProgress((int)(100 * output.Position / file.DecompressedLength));
for (var i = 0; i < folder.BlockCount; i++)
// Ignore checksums
stream.Position += 4;
var blockLength = stream.ReadUInt16();
stream.Position += 4;
using (var batch = new MemoryStream(stream.ReadBytes(blockLength - 2)))
using (var inflaterStream = new InflaterInputStream(batch, inflater))
{ {
if (onProgress != null) int n;
onProgress((int)(100 * outputStream.Position / file.DecompressedLength)); while ((n = inflaterStream.Read(buffer, 0, buffer.Length)) > 0)
// Ignore checksums
stream.Position += 4;
var blockLength = stream.ReadUInt16();
stream.Position += 4;
using (var batch = new MemoryStream(stream.ReadBytes(blockLength - 2)))
using (var inflaterStream = new InflaterInputStream(batch, inflater))
{ {
int n; var offset = Math.Max(0, file.DecompressedOffset - decompressedBytes);
while ((n = inflaterStream.Read(buffer, 0, buffer.Length)) > 0) var count = Math.Min(n - offset, file.DecompressedLength - decompressedBytes);
outputStream.Write(buffer, 0, n); if (offset < n)
} output.Write(buffer, (int)offset, (int)count);
inflater.Reset(); decompressedBytes += n;
}
} }
outputStream.Seek(file.DecompressedOffset, SeekOrigin.Begin); inflater.Reset();
return outputStream.ReadBytes((int)file.DecompressedLength);
} }
} }

View File

@@ -304,12 +304,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic
Directory.CreateDirectory(Path.GetDirectoryName(targetPath)); Directory.CreateDirectory(Path.GetDirectoryName(targetPath));
using (var target = File.OpenWrite(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)); Log.Write("install", "Extracting {0} -> {1}".F(sourcePath, targetPath));
var displayFilename = Path.GetFileName(Path.GetFileName(targetPath)); var displayFilename = Path.GetFileName(Path.GetFileName(targetPath));
Action<int> onProgress = percent => updateMessage("Extracting {0} ({1}%)".F(displayFilename, percent)); Action<int> onProgress = percent => updateMessage("Extracting {0} ({1}%)".F(displayFilename, percent));
target.Write(reader.ExtractFile(node.Value.Value, onProgress)); reader.ExtractFile(node.Value.Value, target, onProgress);
} }
} }
} }