From e6fb704780510df44f48c9e12987fcb0872b5761 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 12:59:30 +0000 Subject: [PATCH 1/6] Initial plan From f77a2aababba3bf1b391a02270aea58e298a3f2f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 13:04:58 +0000 Subject: [PATCH 2/6] Fix EntryStream.Dispose() to not throw NotSupportedException on non-seekable streams Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- src/SharpCompress/Common/EntryStream.cs | 36 +++++++++++++-- .../SharpCompress.Test/Zip/ZipReaderTests.cs | 46 +++++++++++++++++++ 2 files changed, 78 insertions(+), 4 deletions(-) diff --git a/src/SharpCompress/Common/EntryStream.cs b/src/SharpCompress/Common/EntryStream.cs index e4de4ca9..d265be00 100644 --- a/src/SharpCompress/Common/EntryStream.cs +++ b/src/SharpCompress/Common/EntryStream.cs @@ -79,11 +79,25 @@ public class EntryStream : Stream, IStreamStack { 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 class EntryStream : Stream, IStreamStack { 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/Zip/ZipReaderTests.cs b/tests/SharpCompress.Test/Zip/ZipReaderTests.cs index c3b53e11..0ad07ffb 100644 --- a/tests/SharpCompress.Test/Zip/ZipReaderTests.cs +++ b/tests/SharpCompress.Test/Zip/ZipReaderTests.cs @@ -444,4 +444,50 @@ public class ZipReaderTests : ReaderTests Assert.Equal(archiveKeys.OrderBy(k => k), readerKeys.OrderBy(k => k)); } } + + [Fact] + public void EntryStream_Dispose_DoesNotThrow_OnNonSeekableStream_Deflate() + { + // Test for issue: 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() + { + // Test for issue: 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 + } + } + } } From 8b74243e7915bc78f9375f7a673118ae0307ad31 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 13:07:32 +0000 Subject: [PATCH 3/6] Update test comments to include version context Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- tests/SharpCompress.Test/Zip/ZipReaderTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/SharpCompress.Test/Zip/ZipReaderTests.cs b/tests/SharpCompress.Test/Zip/ZipReaderTests.cs index 0ad07ffb..a3c4fbae 100644 --- a/tests/SharpCompress.Test/Zip/ZipReaderTests.cs +++ b/tests/SharpCompress.Test/Zip/ZipReaderTests.cs @@ -448,7 +448,7 @@ public class ZipReaderTests : ReaderTests [Fact] public void EntryStream_Dispose_DoesNotThrow_OnNonSeekableStream_Deflate() { - // Test for issue: EntryStream.Dispose() should not throw NotSupportedException + // 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)); @@ -471,7 +471,7 @@ public class ZipReaderTests : ReaderTests [Fact] public void EntryStream_Dispose_DoesNotThrow_OnNonSeekableStream_LZMA() { - // Test for issue: EntryStream.Dispose() should not throw NotSupportedException + // 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)); From 7cbdc5b46c6c78ae08e11c6fcd40d0dfea824dee Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 13:21:36 +0000 Subject: [PATCH 4/6] Format code with CSharpier Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- tests/SharpCompress.Test/Zip/ZipReaderTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/SharpCompress.Test/Zip/ZipReaderTests.cs b/tests/SharpCompress.Test/Zip/ZipReaderTests.cs index a3c4fbae..30f1f16f 100644 --- a/tests/SharpCompress.Test/Zip/ZipReaderTests.cs +++ b/tests/SharpCompress.Test/Zip/ZipReaderTests.cs @@ -453,7 +453,7 @@ public class ZipReaderTests : ReaderTests 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()) { @@ -476,7 +476,7 @@ public class ZipReaderTests : ReaderTests 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()) { From 9628f2dda180b90a07065c1b3bec640a9c38eede Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 14:35:16 +0000 Subject: [PATCH 5/6] Add async tests for EntryStream.Dispose on non-seekable streams Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- .../Zip/ZipReaderAsyncTests.cs | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/SharpCompress.Test/Zip/ZipReaderAsyncTests.cs b/tests/SharpCompress.Test/Zip/ZipReaderAsyncTests.cs index 3aec7ea9..1d81f6f2 100644 --- a/tests/SharpCompress.Test/Zip/ZipReaderAsyncTests.cs +++ b/tests/SharpCompress.Test/Zip/ZipReaderAsyncTests.cs @@ -283,4 +283,50 @@ public class ZipReaderAsyncTests : ReaderTests } 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) + { + await using var entryStream = await reader.OpenEntryStreamAsync(); + // 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) + { + await using var entryStream = await reader.OpenEntryStreamAsync(); + // Read some data + var buffer = new byte[1024]; + await entryStream.ReadAsync(buffer, 0, buffer.Length); + // DisposeAsync should not throw NotSupportedException + } + } + } } From 1522e647971fb3459187cc970aa0379633648f3b Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 22 Jan 2026 15:15:57 +0000 Subject: [PATCH 6/6] fix async tests --- tests/SharpCompress.Test/SharpCompress.Test.csproj | 5 ++++- tests/SharpCompress.Test/Zip/ZipReaderAsyncTests.cs | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/SharpCompress.Test/SharpCompress.Test.csproj b/tests/SharpCompress.Test/SharpCompress.Test.csproj index c16a1581..3de1dac7 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 1d81f6f2..c4c5bb3a 100644 --- a/tests/SharpCompress.Test/Zip/ZipReaderAsyncTests.cs +++ b/tests/SharpCompress.Test/Zip/ZipReaderAsyncTests.cs @@ -298,7 +298,11 @@ public class ZipReaderAsyncTests : ReaderTests { 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); @@ -321,7 +325,11 @@ public class ZipReaderAsyncTests : ReaderTests { 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);