Browse Source

Fix #1047

pull/1055/head
James Jackson-South 6 years ago
parent
commit
94eb476764
  1. 5
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  2. 4
      src/ImageSharp/Formats/Png/PngThrowHelper.cs
  3. 21
      tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs
  4. 15
      tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
  5. 1
      tests/ImageSharp.Tests/TestImages.cs
  6. BIN
      tests/Images/Input/Png/issues/Issue_1047.png

5
src/ImageSharp/Formats/Png/PngDecoderCore.cs

@ -1159,6 +1159,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <summary>
/// Reads the cycle redundancy chunk from the data.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
private uint ReadChunkCrc()
{
uint crc = 0;
@ -1174,6 +1175,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// Skips the chunk data and the cycle redundancy chunk read from the data.
/// </summary>
/// <param name="chunk">The image format chunk.</param>
[MethodImpl(InliningOptions.ShortMethod)]
private void SkipChunkDataAndCrc(in PngChunk chunk)
{
this.currentStream.Skip(chunk.Length);
@ -1184,6 +1186,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// Reads the chunk data from the stream.
/// </summary>
/// <param name="length">The length of the chunk data to read.</param>
[MethodImpl(InliningOptions.ShortMethod)]
private IManagedByteBuffer ReadChunkData(int length)
{
// We rent the buffer here to return it afterwards in Decode()
@ -1200,6 +1203,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <exception cref="ImageFormatException">
/// Thrown if the input stream is not valid.
/// </exception>
[MethodImpl(InliningOptions.ShortMethod)]
private PngChunkType ReadChunkType()
{
if (this.currentStream.Read(this.buffer, 0, 4) == 4)
@ -1221,6 +1225,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <returns>
/// Whether the length was read.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
private bool TryReadChunkLength(out int result)
{
if (this.currentStream.Read(this.buffer, 0, 4) == 4)

4
src/ImageSharp/Formats/Png/PngThrowHelper.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Formats.Png
@ -17,13 +18,16 @@ namespace SixLabors.ImageSharp.Formats.Png
[MethodImpl(InliningOptions.ColdPath)]
public static void ThrowNoData() => throw new ImageFormatException("PNG Image does not contain a data chunk");
[MethodImpl(InliningOptions.ColdPath)]
public static void ThrowInvalidChunkType() => throw new ImageFormatException("Invalid PNG data.");
[MethodImpl(InliningOptions.ColdPath)]
public static void ThrowInvalidChunkCrc(string chunkTypeName) => throw new ImageFormatException($"CRC Error. PNG {chunkTypeName} chunk is corrupt!");
[MethodImpl(InliningOptions.ColdPath)]
public static void ThrowNotSupportedColor() => new NotSupportedException("Unsupported PNG color type");
[MethodImpl(InliningOptions.ColdPath)]
public static void ThrowUnknownFilter() => throw new ImageFormatException("Unknown filter type.");
}
}

21
tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs

@ -54,7 +54,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
[InlineData((uint)PngChunkType.Header)] // IHDR
[InlineData((uint)PngChunkType.Palette)] // PLTE
// [InlineData(PngChunkTypes.Data)] //TODO: Figure out how to test this
[InlineData((uint)PngChunkType.End)] // IEND
public void Decode_IncorrectCRCForCriticalChunk_ExceptionIsThrown(uint chunkType)
{
string chunkName = GetChunkTypeName(chunkType);
@ -74,26 +73,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
}
}
[Theory]
[InlineData((uint)PngChunkType.Gamma)] // gAMA
[InlineData((uint)PngChunkType.Transparency)] // tRNS
[InlineData((uint)PngChunkType.Physical)] // pHYs: It's ok to test physical as we don't throw for duplicate chunks.
//[InlineData(PngChunkTypes.Text)] //TODO: Figure out how to test this
public void Decode_IncorrectCRCForNonCriticalChunk_ExceptionIsThrown(uint chunkType)
{
string chunkName = GetChunkTypeName(chunkType);
using (var memStream = new MemoryStream())
{
WriteHeaderChunk(memStream);
WriteChunk(memStream, chunkName);
WriteDataChunk(memStream);
var decoder = new PngDecoder();
decoder.Decode<Rgb24>(null, memStream);
}
}
private static string GetChunkTypeName(uint value)
{
var data = new byte[4];

15
tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs

@ -4,11 +4,11 @@
// ReSharper disable InconsistentNaming
using System.IO;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs;
using Xunit;
namespace SixLabors.ImageSharp.Tests.Formats.Png
@ -42,6 +42,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
TestImages.Png.Bad.ZlibOverflow,
TestImages.Png.Bad.ZlibOverflow2,
TestImages.Png.Bad.ZlibZtxtBadHeader,
TestImages.Png.Bad.Issue1047_BadEndChunk
};
public static readonly string[] TestImages48Bpp =
@ -90,7 +91,15 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
using (Image<TPixel> image = provider.GetImage(new PngDecoder()))
{
image.DebugSave(provider);
image.CompareToOriginal(provider, ImageComparer.Exact);
if (provider.Utility.SourceFileOrDescription == TestImages.Png.Bad.Issue1047_BadEndChunk)
{
image.CompareToOriginal(provider, ImageComparer.Exact, (IImageDecoder)SystemDrawingReferenceDecoder.Instance);
}
else
{
image.CompareToOriginal(provider, ImageComparer.Exact);
}
}
}

1
tests/ImageSharp.Tests/TestImages.cs

@ -99,6 +99,7 @@ namespace SixLabors.ImageSharp.Tests
public const string ZlibOverflow = "Png/zlib-overflow.png";
public const string ZlibOverflow2 = "Png/zlib-overflow2.png";
public const string ZlibZtxtBadHeader = "Png/zlib-ztxt-bad-header.png";
public const string Issue1047_BadEndChunk = "Png/issues/Issue_1047.png";
}
public static readonly string[] All =

BIN
tests/Images/Input/Png/issues/Issue_1047.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Loading…
Cancel
Save