diff --git a/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs b/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs index e4645c44ac..3eb34b8617 100644 --- a/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs +++ b/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib internal sealed class ZlibInflateStream : Stream { /// - /// Used to read the Adler-32 and Crc-32 checksums + /// Used to read the Adler-32 and Crc-32 checksums. /// We don't actually use this for anything so it doesn't /// have to be threadsafe. /// @@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib private static readonly Func GetDataNoOp = () => 0; /// - /// The inner raw memory stream + /// The inner raw memory stream. /// private readonly Stream innerStream; @@ -43,12 +43,12 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib private bool isDisposed; /// - /// The current data remaining to be read + /// The current data remaining to be read. /// private int currentDataRemaining; /// - /// Delegate to get more data once we've exhausted the current data remaining + /// Delegate to get more data once we've exhausted the current data remaining. /// private readonly Func getData; @@ -88,14 +88,14 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } /// - /// Gets the compressed stream over the deframed inner stream + /// Gets the compressed stream over the deframed inner stream. /// public DeflateStream CompressedStream { get; private set; } /// - /// Adds new bytes from a frame found in the original stream + /// Adds new bytes from a frame found in the original stream. /// - /// blabla + /// The current remaining data according to the chunk length. /// Whether the chunk to be inflated is a critical chunk. /// The . public bool AllocateNewBytes(int bytes, bool isCriticalChunk) @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib { if (this.currentDataRemaining == 0) { - // last buffer was read in its entirety, let's make sure we don't actually have more + // Last buffer was read in its entirety, let's make sure we don't actually have more in additional IDAT chunks. this.currentDataRemaining = this.getData(); if (this.currentDataRemaining == 0) @@ -135,32 +135,35 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib int bytesToRead = Math.Min(count, this.currentDataRemaining); this.currentDataRemaining -= bytesToRead; - int bytesRead = this.innerStream.Read(buffer, offset, bytesToRead); - long length = this.innerStream.Length; + int totalBytesRead = this.innerStream.Read(buffer, offset, bytesToRead); + long innerStreamLength = this.innerStream.Length; - // Keep reading data until we've reached the end of the stream or filled the buffer - while (this.currentDataRemaining == 0 && bytesRead < count) + // Keep reading data until we've reached the end of the stream or filled the buffer. + int bytesRead = 0; + offset += totalBytesRead; + while (this.currentDataRemaining == 0 && totalBytesRead < count) { this.currentDataRemaining = this.getData(); if (this.currentDataRemaining == 0) { - return bytesRead; + return totalBytesRead; } offset += bytesRead; - if (offset >= length || offset >= count) + if (offset >= innerStreamLength || offset >= count) { - return bytesRead; + return totalBytesRead; } - bytesToRead = Math.Min(count - bytesRead, this.currentDataRemaining); + bytesToRead = Math.Min(count - totalBytesRead, this.currentDataRemaining); this.currentDataRemaining -= bytesToRead; - bytesRead += this.innerStream.Read(buffer, offset, bytesToRead); + bytesRead = this.innerStream.Read(buffer, offset, bytesToRead); + totalBytesRead += bytesRead; } - return bytesRead; + return totalBytesRead; } /// @@ -191,7 +194,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib if (disposing) { - // dispose managed resources + // Dispose managed resources. if (this.CompressedStream != null) { this.CompressedStream.Dispose(); diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 91b1ef2c17..2a76310fcd 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -75,6 +75,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png TestImages.Png.GrayAlpha8BitInterlaced }; + public static readonly string[] TestImagesIssue1014 = + { + TestImages.Png.Issue1014_1, TestImages.Png.Issue1014_2, + TestImages.Png.Issue1014_3, TestImages.Png.Issue1014_4, + TestImages.Png.Issue1014_5, TestImages.Png.Issue1014_6 + }; + [Theory] [WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32)] public void Decode(TestImageProvider provider) @@ -199,5 +206,22 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType?.BitsPerPixel); } } + + [Theory] + [WithFileCollection(nameof(TestImagesIssue1014), PixelTypes.Rgba32)] + public void Issue1014(TestImageProvider provider) + where TPixel : struct, IPixel + { + System.Exception ex = Record.Exception( + () => + { + using (Image image = provider.GetImage(new PngDecoder())) + { + image.DebugSave(provider); + // TODO: compare to expected output + } + }); + Assert.Null(ex); + } } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 163d09bdde..146f2efcdb 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -82,6 +82,14 @@ namespace SixLabors.ImageSharp.Tests public const string Ducky = "Png/ducky.png"; public const string Rainbow = "Png/rainbow.png"; + // Issue 1014: https://github.com/SixLabors/ImageSharp/issues/1014 + public const string Issue1014_1 = "Png/issues/Issue_1014_1.png"; + public const string Issue1014_2 = "Png/issues/Issue_1014_2.png"; + public const string Issue1014_3 = "Png/issues/Issue_1014_3.png"; + public const string Issue1014_4 = "Png/issues/Issue_1014_4.png"; + public const string Issue1014_5 = "Png/issues/Issue_1014_5.png"; + public const string Issue1014_6 = "Png/issues/Issue_1014_6.png"; + public static class Bad { // Odd chunk lengths diff --git a/tests/Images/Input/Png/issues/Issue_1014_1.png b/tests/Images/Input/Png/issues/Issue_1014_1.png new file mode 100644 index 0000000000..2cbd401e61 Binary files /dev/null and b/tests/Images/Input/Png/issues/Issue_1014_1.png differ diff --git a/tests/Images/Input/Png/issues/Issue_1014_2.png b/tests/Images/Input/Png/issues/Issue_1014_2.png new file mode 100644 index 0000000000..ca1c8ea5b9 Binary files /dev/null and b/tests/Images/Input/Png/issues/Issue_1014_2.png differ diff --git a/tests/Images/Input/Png/issues/Issue_1014_3.png b/tests/Images/Input/Png/issues/Issue_1014_3.png new file mode 100644 index 0000000000..3a7a8ed2c0 Binary files /dev/null and b/tests/Images/Input/Png/issues/Issue_1014_3.png differ diff --git a/tests/Images/Input/Png/issues/Issue_1014_4.png b/tests/Images/Input/Png/issues/Issue_1014_4.png new file mode 100644 index 0000000000..54d099427d Binary files /dev/null and b/tests/Images/Input/Png/issues/Issue_1014_4.png differ diff --git a/tests/Images/Input/Png/issues/Issue_1014_5.png b/tests/Images/Input/Png/issues/Issue_1014_5.png new file mode 100644 index 0000000000..9e719ca302 Binary files /dev/null and b/tests/Images/Input/Png/issues/Issue_1014_5.png differ diff --git a/tests/Images/Input/Png/issues/Issue_1014_6.png b/tests/Images/Input/Png/issues/Issue_1014_6.png new file mode 100644 index 0000000000..7b90f49da6 Binary files /dev/null and b/tests/Images/Input/Png/issues/Issue_1014_6.png differ