diff --git a/src/SharpCompress/Common/EntryStream.cs b/src/SharpCompress/Common/EntryStream.cs
index e4de4ca9a..d265be00b 100644
--- a/src/SharpCompress/Common/EntryStream.cs
+++ b/src/SharpCompress/Common/EntryStream.cs
@@ -79,11 +79,25 @@ protected override void Dispose(bool disposing)
{
if (ss.BaseStream() is SharpCompress.Compressors.Deflate.DeflateStream deflateStream)
{
- deflateStream.Flush(); //Deflate over reads. Knock it back
+ try
+ {
+ deflateStream.Flush(); //Deflate over reads. Knock it back
+ }
+ catch (NotSupportedException)
+ {
+ // Ignore: underlying stream does not support required operations for Flush
+ }
}
else if (ss.BaseStream() is SharpCompress.Compressors.LZMA.LzmaStream lzmaStream)
{
- lzmaStream.Flush(); //Lzma over reads. Knock it back
+ try
+ {
+ lzmaStream.Flush(); //Lzma over reads. Knock it back
+ }
+ catch (NotSupportedException)
+ {
+ // Ignore: underlying stream does not support required operations for Flush
+ }
}
}
#if DEBUG_STREAMS
@@ -111,11 +125,25 @@ public override async ValueTask DisposeAsync()
{
if (ss.BaseStream() is SharpCompress.Compressors.Deflate.DeflateStream deflateStream)
{
- await deflateStream.FlushAsync().ConfigureAwait(false);
+ try
+ {
+ await deflateStream.FlushAsync().ConfigureAwait(false);
+ }
+ catch (NotSupportedException)
+ {
+ // Ignore: underlying stream does not support required operations for Flush
+ }
}
else if (ss.BaseStream() is SharpCompress.Compressors.LZMA.LzmaStream lzmaStream)
{
- await lzmaStream.FlushAsync().ConfigureAwait(false);
+ try
+ {
+ await lzmaStream.FlushAsync().ConfigureAwait(false);
+ }
+ catch (NotSupportedException)
+ {
+ // Ignore: underlying stream does not support required operations for Flush
+ }
}
}
#if DEBUG_STREAMS
diff --git a/tests/SharpCompress.Test/SharpCompress.Test.csproj b/tests/SharpCompress.Test/SharpCompress.Test.csproj
index c16a1581a..3de1dac78 100644
--- a/tests/SharpCompress.Test/SharpCompress.Test.csproj
+++ b/tests/SharpCompress.Test/SharpCompress.Test.csproj
@@ -9,6 +9,9 @@
$(DefineConstants);DEBUG_STREAMS
+
+ $(DefineConstants);LEGACY_DOTNET
+
$(DefineConstants);WINDOWS
@@ -24,7 +27,7 @@
-
+
diff --git a/tests/SharpCompress.Test/Zip/ZipReaderAsyncTests.cs b/tests/SharpCompress.Test/Zip/ZipReaderAsyncTests.cs
index 3aec7ea9d..c4c5bb3a4 100644
--- a/tests/SharpCompress.Test/Zip/ZipReaderAsyncTests.cs
+++ b/tests/SharpCompress.Test/Zip/ZipReaderAsyncTests.cs
@@ -283,4 +283,58 @@ await reader.WriteEntryToDirectoryAsync(
}
Assert.Equal(8, count);
}
+
+ [Fact]
+ public async ValueTask EntryStream_Dispose_DoesNotThrow_OnNonSeekableStream_Deflate_Async()
+ {
+ // Since version 0.41.0: EntryStream.DisposeAsync() should not throw NotSupportedException
+ // when FlushAsync() fails on non-seekable streams (Deflate compression)
+ var path = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip");
+ using Stream stream = new ForwardOnlyStream(File.OpenRead(path));
+ await using var reader = ReaderFactory.OpenAsyncReader(new AsyncOnlyStream(stream));
+
+ // This should not throw, even if internal FlushAsync() fails
+ while (await reader.MoveToNextEntryAsync())
+ {
+ if (!reader.Entry.IsDirectory)
+ {
+#if LEGACY_DOTNET
+ using var entryStream = await reader.OpenEntryStreamAsync();
+#else
+ await using var entryStream = await reader.OpenEntryStreamAsync();
+#endif
+ // Read some data
+ var buffer = new byte[1024];
+ await entryStream.ReadAsync(buffer, 0, buffer.Length);
+ // DisposeAsync should not throw NotSupportedException
+ }
+ }
+ }
+
+ [Fact]
+ public async ValueTask EntryStream_Dispose_DoesNotThrow_OnNonSeekableStream_LZMA_Async()
+ {
+ // Since version 0.41.0: EntryStream.DisposeAsync() should not throw NotSupportedException
+ // when FlushAsync() fails on non-seekable streams (LZMA compression)
+ var path = Path.Combine(TEST_ARCHIVES_PATH, "Zip.lzma.dd.zip");
+ using Stream stream = new ForwardOnlyStream(File.OpenRead(path));
+ await using var reader = ReaderFactory.OpenAsyncReader(new AsyncOnlyStream(stream));
+
+ // This should not throw, even if internal FlushAsync() fails
+ while (await reader.MoveToNextEntryAsync())
+ {
+ if (!reader.Entry.IsDirectory)
+ {
+#if LEGACY_DOTNET
+ using var entryStream = await reader.OpenEntryStreamAsync();
+#else
+ await using var entryStream = await reader.OpenEntryStreamAsync();
+#endif
+ // Read some data
+ var buffer = new byte[1024];
+ await entryStream.ReadAsync(buffer, 0, buffer.Length);
+ // DisposeAsync should not throw NotSupportedException
+ }
+ }
+ }
}
diff --git a/tests/SharpCompress.Test/Zip/ZipReaderTests.cs b/tests/SharpCompress.Test/Zip/ZipReaderTests.cs
index c3b53e113..30f1f16f6 100644
--- a/tests/SharpCompress.Test/Zip/ZipReaderTests.cs
+++ b/tests/SharpCompress.Test/Zip/ZipReaderTests.cs
@@ -444,4 +444,50 @@ public void ZipReader_Returns_Same_Entries_As_ZipArchive()
Assert.Equal(archiveKeys.OrderBy(k => k), readerKeys.OrderBy(k => k));
}
}
+
+ [Fact]
+ public void EntryStream_Dispose_DoesNotThrow_OnNonSeekableStream_Deflate()
+ {
+ // Since version 0.41.0: EntryStream.Dispose() should not throw NotSupportedException
+ // when Flush() fails on non-seekable streams (Deflate compression)
+ var path = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip");
+ using Stream stream = new ForwardOnlyStream(File.OpenRead(path));
+ using var reader = ReaderFactory.OpenReader(stream);
+
+ // This should not throw, even if internal Flush() fails
+ while (reader.MoveToNextEntry())
+ {
+ if (!reader.Entry.IsDirectory)
+ {
+ using var entryStream = reader.OpenEntryStream();
+ // Read some data
+ var buffer = new byte[1024];
+ entryStream.Read(buffer, 0, buffer.Length);
+ // Dispose should not throw NotSupportedException
+ }
+ }
+ }
+
+ [Fact]
+ public void EntryStream_Dispose_DoesNotThrow_OnNonSeekableStream_LZMA()
+ {
+ // Since version 0.41.0: EntryStream.Dispose() should not throw NotSupportedException
+ // when Flush() fails on non-seekable streams (LZMA compression)
+ var path = Path.Combine(TEST_ARCHIVES_PATH, "Zip.lzma.dd.zip");
+ using Stream stream = new ForwardOnlyStream(File.OpenRead(path));
+ using var reader = ReaderFactory.OpenReader(stream);
+
+ // This should not throw, even if internal Flush() fails
+ while (reader.MoveToNextEntry())
+ {
+ if (!reader.Entry.IsDirectory)
+ {
+ using var entryStream = reader.OpenEntryStream();
+ // Read some data
+ var buffer = new byte[1024];
+ entryStream.Read(buffer, 0, buffer.Length);
+ // Dispose should not throw NotSupportedException
+ }
+ }
+ }
}