mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-07-08 18:16:30 +00:00
Fix XZBlock exception when accessing Position on non-seekable streams
XZBlock accesses stream.Position in its constructor and SkipPadding(), which throws NotSupportedException for non-seekable streams (e.g., HTTP). Fix: XZStream now auto-wraps non-seekable streams with SharpCompressStream.Create() to provide position tracking via ring buffer. Add tests for raw non-seekable streams (sync and async). Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com>
This commit is contained in:
@@ -5,6 +5,7 @@ using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Compressors.Xz;
|
||||
|
||||
@@ -12,7 +13,7 @@ namespace SharpCompress.Compressors.Xz;
|
||||
public sealed partial class XZStream : XZReadOnlyStream
|
||||
{
|
||||
public XZStream(Stream baseStream)
|
||||
: base(baseStream) { }
|
||||
: base(baseStream.CanSeek ? baseStream : SharpCompressStream.Create(baseStream)) { }
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
|
||||
@@ -55,4 +55,24 @@ public class XzStreamAsyncTests : XzTestsBase
|
||||
var uncompressed = await sr.ReadToEndAsync().ConfigureAwait(false);
|
||||
Assert.Equal(OriginalEmpty, uncompressed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async ValueTask CanReadRawNonSeekableStreamAsync()
|
||||
{
|
||||
var nonSeekable = new ForwardOnlyStream(new MemoryStream(Compressed));
|
||||
var xz = new XZStream(nonSeekable);
|
||||
using var sr = new StreamReader(new AsyncOnlyStream(xz));
|
||||
var uncompressed = await sr.ReadToEndAsync().ConfigureAwait(false);
|
||||
Assert.Equal(Original, uncompressed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async ValueTask CanReadRawNonSeekableEmptyStreamAsync()
|
||||
{
|
||||
var nonSeekable = new ForwardOnlyStream(new MemoryStream(CompressedEmpty));
|
||||
var xz = new XZStream(nonSeekable);
|
||||
using var sr = new StreamReader(new AsyncOnlyStream(xz));
|
||||
var uncompressed = await sr.ReadToEndAsync().ConfigureAwait(false);
|
||||
Assert.Equal(OriginalEmpty, uncompressed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,4 +54,24 @@ public class XzStreamTests : XzTestsBase
|
||||
var uncompressed = sr.ReadToEnd();
|
||||
Assert.Equal(OriginalEmpty, uncompressed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanReadRawNonSeekableStream()
|
||||
{
|
||||
var nonSeekable = new ForwardOnlyStream(new MemoryStream(Compressed));
|
||||
var xz = new XZStream(nonSeekable);
|
||||
using var sr = new StreamReader(xz);
|
||||
var uncompressed = sr.ReadToEnd();
|
||||
Assert.Equal(Original, uncompressed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanReadRawNonSeekableEmptyStream()
|
||||
{
|
||||
var nonSeekable = new ForwardOnlyStream(new MemoryStream(CompressedEmpty));
|
||||
var xz = new XZStream(nonSeekable);
|
||||
using var sr = new StreamReader(xz);
|
||||
var uncompressed = sr.ReadToEnd();
|
||||
Assert.Equal(OriginalEmpty, uncompressed);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user