not sure I like this fix

This commit is contained in:
Adam Hathcock
2026-02-01 08:47:17 +00:00
parent cb27b117b4
commit 62b8fc92d1
6 changed files with 119 additions and 23 deletions

View File

@@ -48,11 +48,17 @@ public partial class EntryStream : Stream
//Need a safe standard approach to this - it's okay for compression to overreads. Handling needs to be standardised
if (_stream is IStreamStack ss)
{
if (ss.BaseStream() is SharpCompress.Compressors.Deflate.DeflateStream deflateStream)
if (
ss.GetStream<SharpCompress.Compressors.Deflate.DeflateStream>()
is SharpCompress.Compressors.Deflate.DeflateStream deflateStream
)
{
deflateStream.Flush(); //Deflate over reads. Knock it back
}
else if (ss.BaseStream() is SharpCompress.Compressors.LZMA.LzmaStream lzmaStream)
else if (
ss.GetStream<SharpCompress.Compressors.LZMA.LzmaStream>()
is SharpCompress.Compressors.LZMA.LzmaStream lzmaStream
)
{
lzmaStream.Flush(); //Lzma over reads. Knock it back
}

View File

@@ -29,10 +29,11 @@ using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.IO;
namespace SharpCompress.Compressors.Deflate;
public partial class DeflateStream : Stream
public partial class DeflateStream : Stream, IStreamStack
{
private readonly ZlibBaseStream _baseStream;
private bool _disposed;
@@ -269,6 +270,8 @@ public partial class DeflateStream : Stream
}
}
Stream IStreamStack.BaseStream() => _baseStream;
/// <summary>
/// Flush the stream.
/// </summary>

View File

@@ -34,6 +34,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common.Tar.Headers;
using SharpCompress.IO;
namespace SharpCompress.Compressors.Deflate;
@@ -44,8 +45,10 @@ internal enum ZlibStreamFlavor
GZIP = 1952,
}
internal class ZlibBaseStream : Stream
internal class ZlibBaseStream : Stream, IStreamStack
{
Stream IStreamStack.BaseStream() => _stream;
protected internal ZlibCodec _z; // deferred init... new ZlibCodec();
protected internal StreamMode _streamMode = StreamMode.Undefined;
@@ -590,8 +593,24 @@ internal class ZlibBaseStream : Stream
{
_stream.Flush();
}
//rewind the buffer
//unused: ((IStreamStack)this).Rewind(z.AvailableBytesIn);
else if (_streamMode == StreamMode.Reader && z.AvailableBytesIn > 0)
{
// Rewind the underlying stream by the number of unconsumed bytes in the buffer
// This handles the case where the decompressor over-read past the end of the entry
if (_stream is IStreamStack stack)
{
var root = stack.GetRootStream();
if (root.CanSeek)
{
// Try to seek backward on the root stream; ignore if not supported
try
{
root.Seek(-z.AvailableBytesIn, SeekOrigin.Current);
}
catch (NotSupportedException) { }
}
}
}
z.AvailableBytesIn = 0;
}
@@ -604,8 +623,24 @@ internal class ZlibBaseStream : Stream
{
await _stream.FlushAsync(cancellationToken).ConfigureAwait(false);
}
//rewind the buffer
//unused: ((IStreamStack)this).Rewind(z.AvailableBytesIn);
else if (_streamMode == StreamMode.Reader && z.AvailableBytesIn > 0)
{
// Rewind the underlying stream by the number of unconsumed bytes in the buffer
// This handles the case where the decompressor over-read past the end of the entry
if (_stream is IStreamStack stack)
{
var root = stack.GetRootStream();
if (root.CanSeek)
{
// Try to seek backward on the root stream; ignore if not supported
try
{
root.Seek(-z.AvailableBytesIn, SeekOrigin.Current);
}
catch (NotSupportedException) { }
}
}
}
z.AvailableBytesIn = 0;
}

View File

@@ -4,10 +4,11 @@ using System.IO;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Compressors.LZMA.LZ;
using SharpCompress.IO;
namespace SharpCompress.Compressors.LZMA;
public partial class LzmaStream : Stream
public partial class LzmaStream : Stream, IStreamStack
{
private readonly Stream? _inputStream;
private readonly long _inputSize;
@@ -190,6 +191,8 @@ public partial class LzmaStream : Stream
public override void Flush() { }
Stream IStreamStack.BaseStream() => _inputStream!;
protected override void Dispose(bool disposing)
{
if (_isDisposed)

View File

@@ -15,4 +15,39 @@ namespace SharpCompress.IO
/// </summary>
Stream BaseStream();
}
public static class StreamStackExtensions
{
public static T? GetStream<T>(this IStreamStack stack)
where T : Stream
{
var baseStream = stack.BaseStream();
if (baseStream is T tStream)
{
return tStream;
}
else if (baseStream is IStreamStack innerStack)
{
return innerStack.GetStream<T>();
}
else
{
return null;
}
}
/// <summary>
/// Gets the root underlying stream at the bottom of the stack.
/// This is useful for seeking when the intermediate streams don't support it.
/// </summary>
public static Stream GetRootStream(this IStreamStack stack)
{
var current = stack.BaseStream();
while (current is IStreamStack streamStack)
{
current = streamStack.BaseStream();
}
return current;
}
}
}

View File

@@ -105,20 +105,22 @@ internal partial class RewindableStream : Stream
}
return streamPosition;
}
set
{
long bufferStart = streamPosition - bufferStream.Length;
long bufferEnd = streamPosition;
set => SeekToPosition(value);
}
if (value >= bufferStart && value < bufferEnd)
{
isRewound = true;
bufferStream.Position = value - bufferStart;
}
else
{
throw new NotSupportedException("Cannot seek outside buffered region.");
}
private void SeekToPosition(long targetPosition)
{
long bufferStart = streamPosition - bufferStream.Length;
long bufferEnd = streamPosition;
if (targetPosition >= bufferStart && targetPosition <= bufferEnd)
{
isRewound = true;
bufferStream.Position = targetPosition - bufferStart;
}
else
{
throw new NotSupportedException("Cannot seek outside buffered region.");
}
}
@@ -159,7 +161,19 @@ internal partial class RewindableStream : Stream
return read;
}
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
public override long Seek(long offset, SeekOrigin origin)
{
long targetPosition = origin switch
{
SeekOrigin.Begin => offset,
SeekOrigin.Current => Position + offset,
SeekOrigin.End => throw new NotSupportedException("Seeking from end is not supported."),
_ => throw new ArgumentOutOfRangeException(nameof(origin)),
};
SeekToPosition(targetPosition);
return targetPosition;
}
public override void SetLength(long value) => throw new NotSupportedException();