diff --git a/src/ICSharpCode.SharpZipLib/Zip/ZipInputStream.cs b/src/ICSharpCode.SharpZipLib/Zip/ZipInputStream.cs index 66a3fc872..5a0e8e4ac 100644 --- a/src/ICSharpCode.SharpZipLib/Zip/ZipInputStream.cs +++ b/src/ICSharpCode.SharpZipLib/Zip/ZipInputStream.cs @@ -493,6 +493,14 @@ private int ReadingNotSupported(byte[] destination, int offset, int count) throw new ZipException("The compression method for this entry is not supported"); } + /// + /// Handle attempts to read from this entry by throwing an exception + /// + private int StoredDescriptorEntry(byte[] destination, int offset, int count) => + throw new StreamUnsupportedException( + "The combination of Stored compression method and Descriptor flag is not possible to read using ZipInputStream"); + + /// /// Perform the initial read on an entry which may include /// reading encryption headers and setting up inflation. @@ -544,13 +552,22 @@ private int InitialRead(byte[] destination, int offset, int count) inputBuffer.CryptoTransform = null; } - if ((csize > 0) || ((flags & (int)GeneralBitFlags.Descriptor) != 0)) + var usesDescriptor = (flags & (int) GeneralBitFlags.Descriptor) != 0; + + if ((csize > 0) || usesDescriptor) { if ((method == CompressionMethod.Deflated) && (inputBuffer.Available > 0)) { inputBuffer.SetInflaterInput(inf); } + // It's not possible to know how many bytes to read when using "Stored" compression (unless using encryption) + if (!entry.IsCrypted && method == CompressionMethod.Stored && usesDescriptor) + { + internalReader = StoredDescriptorEntry; + return StoredDescriptorEntry(destination, offset, count); + } + internalReader = new ReadDataHandler(BodyRead); return BodyRead(destination, offset, count); } diff --git a/test/ICSharpCode.SharpZipLib.Tests/Zip/StreamHandling.cs b/test/ICSharpCode.SharpZipLib.Tests/Zip/StreamHandling.cs index cb2c72d16..a946e3954 100644 --- a/test/ICSharpCode.SharpZipLib.Tests/Zip/StreamHandling.cs +++ b/test/ICSharpCode.SharpZipLib.Tests/Zip/StreamHandling.cs @@ -502,5 +502,41 @@ public void ShouldBeAbleToReadEntriesWithInvalidFileNames() } } } + + [Test] + [Category("Zip")] + public void ShouldThrowDescriptiveExceptionOnUncompressedDescriptorEntry() + { + using (var ms = new MemoryStreamWithoutSeek()) + { + using (var zos = new ZipOutputStream(ms)) + { + zos.IsStreamOwner = false; + var entry = new ZipEntry("testentry"); + entry.CompressionMethod = CompressionMethod.Stored; + entry.Flags |= (int)GeneralBitFlags.Descriptor; + zos.PutNextEntry(entry); + zos.Write(new byte[1], 0, 1); + zos.CloseEntry(); + } + + // Patch the Compression Method, since ZipOutputStream automatically changes it to Deflate when descriptors are used + ms.Seek(8, SeekOrigin.Begin); + ms.WriteByte((byte)CompressionMethod.Stored); + ms.Seek(0, SeekOrigin.Begin); + + using (var zis = new ZipInputStream(ms)) + { + zis.IsStreamOwner = false; + var buf = new byte[32]; + zis.GetNextEntry(); + + Assert.Throws(typeof(StreamUnsupportedException), () => + { + zis.Read(buf, 0, buf.Length); + }); + } + } + } } }