diff --git a/src/ImageSharp/Formats/Png/PngChunk.cs b/src/ImageSharp/Formats/Png/PngChunk.cs
index 2483a3ad9d..b944b43a34 100644
--- a/src/ImageSharp/Formats/Png/PngChunk.cs
+++ b/src/ImageSharp/Formats/Png/PngChunk.cs
@@ -10,13 +10,18 @@ namespace SixLabors.ImageSharp.Formats.Png
///
internal sealed class PngChunk
{
+ public PngChunk(int length)
+ {
+ this.Length = length;
+ }
+
///
- /// Gets or sets the length.
+ /// Gets the length.
/// An unsigned integer giving the number of bytes in the chunk's
/// data field. The length counts only the data field, not itself,
/// the chunk type code, or the CRC. Zero is a valid length
///
- public int Length { get; set; }
+ public int Length { get; }
///
/// Gets or sets the chunk type as string with 4 chars.
diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
index ffa3875057..e5431cf34f 100644
--- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
@@ -217,19 +217,18 @@ namespace SixLabors.ImageSharp.Formats.Png
{
using (var deframeStream = new ZlibInflateStream(this.currentStream))
{
- PngChunk currentChunk;
- while (!this.isEndChunkReached && (currentChunk = this.ReadChunk()) != null)
+ while (!this.isEndChunkReached && this.TryReadChunk(out PngChunk chunk))
{
try
{
- switch (currentChunk.Type)
+ switch (chunk.Type)
{
case PngChunkTypes.Header:
- this.ReadHeaderChunk(currentChunk.Data.Array);
+ this.ReadHeaderChunk(chunk.Data.Array);
this.ValidateHeader();
break;
case PngChunkTypes.Physical:
- this.ReadPhysicalChunk(metadata, currentChunk.Data.Array);
+ this.ReadPhysicalChunk(metadata, chunk.Data.Array);
break;
case PngChunkTypes.Data:
if (image == null)
@@ -237,23 +236,23 @@ namespace SixLabors.ImageSharp.Formats.Png
this.InitializeImage(metadata, out image);
}
- deframeStream.AllocateNewBytes(currentChunk.Length);
+ deframeStream.AllocateNewBytes(chunk.Length);
this.ReadScanlines(deframeStream.CompressedStream, image.Frames.RootFrame);
this.currentStream.Read(this.crcBuffer, 0, 4);
break;
case PngChunkTypes.Palette:
- byte[] pal = new byte[currentChunk.Length];
- Buffer.BlockCopy(currentChunk.Data.Array, 0, pal, 0, currentChunk.Length);
+ byte[] pal = new byte[chunk.Length];
+ Buffer.BlockCopy(chunk.Data.Array, 0, pal, 0, chunk.Length);
this.palette = pal;
break;
case PngChunkTypes.PaletteAlpha:
- byte[] alpha = new byte[currentChunk.Length];
- Buffer.BlockCopy(currentChunk.Data.Array, 0, alpha, 0, currentChunk.Length);
+ byte[] alpha = new byte[chunk.Length];
+ Buffer.BlockCopy(chunk.Data.Array, 0, alpha, 0, chunk.Length);
this.paletteAlpha = alpha;
this.AssignTransparentMarkers(alpha);
break;
case PngChunkTypes.Text:
- this.ReadTextChunk(metadata, currentChunk.Data.Array, currentChunk.Length);
+ this.ReadTextChunk(metadata, chunk.Data.Array, chunk.Length);
break;
case PngChunkTypes.End:
this.isEndChunkReached = true;
@@ -263,10 +262,10 @@ namespace SixLabors.ImageSharp.Formats.Png
finally
{
// Data is rented in ReadChunkData()
- if (currentChunk.Data != null)
+ if (chunk.Data != null)
{
- currentChunk.Data.Dispose();
- currentChunk.Data = null;
+ chunk.Data.Dispose();
+ chunk.Data = null;
}
}
}
@@ -297,25 +296,24 @@ namespace SixLabors.ImageSharp.Formats.Png
this.currentStream.Skip(8);
try
{
- PngChunk currentChunk;
- while (!this.isEndChunkReached && (currentChunk = this.ReadChunk()) != null)
+ while (!this.isEndChunkReached && this.TryReadChunk(out PngChunk chunk))
{
try
{
- switch (currentChunk.Type)
+ switch (chunk.Type)
{
case PngChunkTypes.Header:
- this.ReadHeaderChunk(currentChunk.Data.Array);
+ this.ReadHeaderChunk(chunk.Data.Array);
this.ValidateHeader();
break;
case PngChunkTypes.Physical:
- this.ReadPhysicalChunk(metadata, currentChunk.Data.Array);
+ this.ReadPhysicalChunk(metadata, chunk.Data.Array);
break;
case PngChunkTypes.Data:
- this.SkipChunkDataAndCrc(currentChunk);
+ this.SkipChunkDataAndCrc(chunk);
break;
case PngChunkTypes.Text:
- this.ReadTextChunk(metadata, currentChunk.Data.Array, currentChunk.Length);
+ this.ReadTextChunk(metadata, chunk.Data.Array, chunk.Length);
break;
case PngChunkTypes.End:
this.isEndChunkReached = true;
@@ -325,9 +323,9 @@ namespace SixLabors.ImageSharp.Formats.Png
finally
{
// Data is rented in ReadChunkData()
- if (currentChunk.Data != null)
+ if (chunk.Data != null)
{
- ArrayPool.Shared.Return(currentChunk.Data.Array);
+ ArrayPool.Shared.Return(chunk.Data.Array);
}
}
}
@@ -1208,36 +1206,40 @@ namespace SixLabors.ImageSharp.Formats.Png
///
/// The .
///
- private PngChunk ReadChunk()
+ private bool TryReadChunk(out PngChunk chunk)
{
- var chunk = new PngChunk();
- this.ReadChunkLength(chunk);
+ int length = this.ReadChunkLength();
- if (chunk.Length == -1)
+ if (length == -1)
{
+ chunk = default;
+
// IEND
- return null;
+ return false;
}
+ chunk = new PngChunk(length);
+
if (chunk.Length < 0 || chunk.Length > this.currentStream.Length - this.currentStream.Position)
{
// Not a valid chunk so we skip back all but one of the four bytes we have just read.
// That lets us read one byte at a time until we reach a known chunk.
this.currentStream.Position -= 3;
- return chunk;
+
+ return true;
}
this.ReadChunkType(chunk);
if (chunk.Type == PngChunkTypes.Data)
{
- return chunk;
+ return true;
}
this.ReadChunkData(chunk);
this.ReadChunkCrc(chunk);
- return chunk;
+ return true;
}
///
@@ -1314,21 +1316,19 @@ namespace SixLabors.ImageSharp.Formats.Png
///
/// Calculates the length of the given chunk.
///
- /// The chunk.
///
/// Thrown if the input stream is not valid.
///
- private void ReadChunkLength(PngChunk chunk)
+ private int ReadChunkLength()
{
int numBytes = this.currentStream.Read(this.chunkLengthBuffer, 0, 4);
if (numBytes < 4)
{
- chunk.Length = -1;
- return;
+ return -1;
}
- chunk.Length = BinaryPrimitives.ReadInt32BigEndian(this.chunkLengthBuffer);
+ return BinaryPrimitives.ReadInt32BigEndian(this.chunkLengthBuffer);
}
///