clean up shrink stream to ensure correctness

This commit is contained in:
Adam Hathcock
2026-04-02 11:48:01 +01:00
parent 58bec11b2c
commit 16903bdecb
3 changed files with 14 additions and 47 deletions

View File

@@ -2,7 +2,6 @@ using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common;
namespace SharpCompress.Compressors.Shrink;
@@ -16,12 +15,7 @@ internal partial class ShrinkStream : Stream
CancellationToken cancellationToken = default
)
{
var shrinkStream = new ShrinkStream(
stream,
compressionMode,
compressedSize,
uncompressedSize
);
var shrinkStream = new ShrinkStream(stream, uncompressedSize);
await shrinkStream.DecompressAsync(cancellationToken).ConfigureAwait(false);
return shrinkStream;
}
@@ -33,26 +27,16 @@ internal partial class ShrinkStream : Stream
return;
}
// Read actual compressed data from stream rather than pre-allocating based on the
// Read actual compressed data from the stream rather than pre-allocating based on the
// declared compressed size, which may be crafted to cause an OutOfMemoryException.
// The stream is already bounded by ReadOnlySubStream in ZipFilePart.
using var srcMs = new MemoryStream();
await inStream.CopyToAsync(srcMs, 81920, cancellationToken).ConfigureAwait(false);
await _inStream.CopyToAsync(srcMs, 81920, cancellationToken).ConfigureAwait(false);
var src = srcMs.ToArray();
var srcLen = src.Length;
// Decompress synchronously (CPU-bound operation)
var srcUsed = 0;
var dstUsed = 0;
HwUnshrink.Unshrink(
src,
srcLen,
out srcUsed,
_byteOut,
(int)_uncompressedSize,
out dstUsed
);
HwUnshrink.Unshrink(src, srcLen, out _, _byteOut, (int)_uncompressedSize, out var dstUsed);
_outBytesCount = dstUsed;
_decompressed = true;
}

View File

@@ -5,33 +5,23 @@ namespace SharpCompress.Compressors.Shrink;
internal partial class ShrinkStream : Stream
{
private Stream inStream;
private readonly Stream _inStream;
private long _uncompressedSize;
private byte[] _byteOut;
private readonly long _uncompressedSize;
private readonly byte[] _byteOut;
private long _outBytesCount;
private bool _decompressed;
private long _position;
public ShrinkStream(
Stream stream,
CompressionMode compressionMode,
long compressedSize,
long uncompressedSize
)
public ShrinkStream(Stream stream, long uncompressedSize)
{
inStream = stream;
_inStream = stream;
_uncompressedSize = uncompressedSize;
_byteOut = new byte[_uncompressedSize];
_outBytesCount = 0L;
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
}
public override bool CanRead => true;
public override bool CanSeek => true;
@@ -52,23 +42,21 @@ internal partial class ShrinkStream : Stream
{
if (!_decompressed)
{
// Read actual compressed data from stream rather than pre-allocating based on the
// Read actual compressed data from the stream rather than pre-allocating based on the
// declared compressed size, which may be crafted to cause an OutOfMemoryException.
// The stream is already bounded by ReadOnlySubStream in ZipFilePart.
using var srcMs = new MemoryStream();
inStream.CopyTo(srcMs);
_inStream.CopyTo(srcMs);
var src = srcMs.ToArray();
var srcLen = src.Length;
var srcUsed = 0;
var dstUsed = 0;
HwUnshrink.Unshrink(
src,
srcLen,
out srcUsed,
out _,
_byteOut,
(int)_uncompressedSize,
out dstUsed
out var dstUsed
);
_outBytesCount = dstUsed;
_decompressed = true;

View File

@@ -27,12 +27,7 @@ public sealed class ShrinkCompressionProvider : ContextRequiredDecompressionProv
{
ValidateRequiredSizes(context, "Shrink");
return new ShrinkStream(
source,
CompressionMode.Decompress,
context.InputSize,
context.OutputSize
);
return new ShrinkStream(source, context.OutputSize);
}
public override async ValueTask<Stream> CreateDecompressStreamAsync(