Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,30 +131,35 @@ protected override Image<TPixel> Decode<TPixel>(BufferedReadStream stream, Cance
try
{
int bytesPerColorMapEntry = this.ReadImageHeaders(stream, out bool inverted, out byte[] palette);
ushort bitsPerPixel = this.infoHeader.BitsPerPixel;

image = new Image<TPixel>(this.configuration, this.infoHeader.Width, this.infoHeader.Height, this.metadata);

Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer();

switch (this.infoHeader.Compression)
{
case BmpCompression.RGB when this.infoHeader.BitsPerPixel is 32 && this.bmpMetadata.InfoHeaderType is BmpInfoHeaderType.WinVersion3:
case BmpCompression.RGB when bitsPerPixel is 32 && this.bmpMetadata.InfoHeaderType is BmpInfoHeaderType.WinVersion3:
this.ReadRgb32Slow(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);

break;
case BmpCompression.RGB when this.infoHeader.BitsPerPixel is 32:

case BmpCompression.RGB when bitsPerPixel is 32:
this.ReadRgb32Fast(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);

break;
case BmpCompression.RGB when this.infoHeader.BitsPerPixel is 24:

case BmpCompression.RGB when bitsPerPixel is 24:
this.ReadRgb24(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);

break;
case BmpCompression.RGB when this.infoHeader.BitsPerPixel is 16:

case BmpCompression.RGB when bitsPerPixel is 16:
this.ReadRgb16(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);

break;
case BmpCompression.RGB when this.infoHeader.BitsPerPixel is <= 8 && this.processedAlphaMask:

case BmpCompression.RGB when bitsPerPixel is > 0 and <= 8 && this.processedAlphaMask:
this.ReadRgbPaletteWithAlphaMask(
stream,
pixels,
Expand All @@ -166,7 +171,8 @@ protected override Image<TPixel> Decode<TPixel>(BufferedReadStream stream, Cance
inverted);

break;
case BmpCompression.RGB when this.infoHeader.BitsPerPixel is <= 8:

case BmpCompression.RGB when bitsPerPixel is > 0 and <= 8:
this.ReadRgbPalette(
stream,
pixels,
Expand All @@ -179,6 +185,10 @@ protected override Image<TPixel> Decode<TPixel>(BufferedReadStream stream, Cance

break;

case BmpCompression.RGB when bitsPerPixel is <= 0 or > 32:
BmpThrowHelper.ThrowInvalidImageContentException($"Invalid bits per pixel: {bitsPerPixel}");
break;

case BmpCompression.RLE24:
this.ReadRle24(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);

Expand Down
23 changes: 23 additions & 0 deletions tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -571,4 +571,27 @@ public void BmpDecoder_ThrowsException_Issue2696<TPixel>(TestImageProvider<TPixe
});
Assert.IsType<InvalidMemoryOperationException>(ex.InnerException);
}

[Fact]
public void BmpDecoder_ThrowsException_Issue3067()
{
// Construct minimal BMP with bitsPerPixel = 0
byte[] bmp = new byte[54];
bmp[0] = (byte)'B';
bmp[1] = (byte)'M';
BitConverter.GetBytes(54).CopyTo(bmp, 2);
BitConverter.GetBytes(54).CopyTo(bmp, 10);
BitConverter.GetBytes(40).CopyTo(bmp, 14);
BitConverter.GetBytes(1).CopyTo(bmp, 18);
BitConverter.GetBytes(1).CopyTo(bmp, 22);
BitConverter.GetBytes((short)1).CopyTo(bmp, 26);
BitConverter.GetBytes((short)0).CopyTo(bmp, 28); // bitsPerPixel = 0

using MemoryStream stream = new(bmp);

Assert.Throws<InvalidImageContentException>(() =>
{
using Image image = BmpDecoder.Instance.Decode(DecoderOptions.Default, stream);
});
}
}
11 changes: 9 additions & 2 deletions tests/ImageSharp.Tests/Formats/Icon/Ico/IcoDecoderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,12 +204,19 @@ public void Bpp8Test(TestImageProvider<Rgba32> provider)
}

[Theory]
[WithFile(InvalidAll, PixelTypes.Rgba32)]
[WithFile(InvalidBpp, PixelTypes.Rgba32)]
public void InvalidThrows_InvalidImageContentException(TestImageProvider<Rgba32> provider)
=> Assert.Throws<InvalidImageContentException>(() =>
{
using Image<Rgba32> image = provider.GetImage(IcoDecoder.Instance);
});

[Theory]
[WithFile(InvalidAll, PixelTypes.Rgba32)]
[WithFile(InvalidCompression, PixelTypes.Rgba32)]
[WithFile(InvalidRLE4, PixelTypes.Rgba32)]
[WithFile(InvalidRLE8, PixelTypes.Rgba32)]
public void InvalidTest(TestImageProvider<Rgba32> provider)
public void InvalidThows_NotSupportedException(TestImageProvider<Rgba32> provider)
=> Assert.Throws<NotSupportedException>(() =>
{
using Image<Rgba32> image = provider.GetImage(IcoDecoder.Instance);
Expand Down
Loading