From 1213b8b00a799f2ab27a6069522f16d5ea84de67 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 27 May 2020 14:21:58 +0200 Subject: [PATCH] DetectFormat for tga now additionally checks: - If all color map spec bytes are zero when color map type is zero - Width and height are not zero --- .../Formats/Tga/TgaImageFormatDetector.cs | 31 +++++++++++-- .../Formats/Tga/TgaFileHeaderTests.cs | 44 ++++++++++++++----- 2 files changed, 59 insertions(+), 16 deletions(-) diff --git a/src/ImageSharp/Formats/Tga/TgaImageFormatDetector.cs b/src/ImageSharp/Formats/Tga/TgaImageFormatDetector.cs index 300172f6c..9074b3756 100644 --- a/src/ImageSharp/Formats/Tga/TgaImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Tga/TgaImageFormatDetector.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tga public sealed class TgaImageFormatDetector : IImageFormatDetector { /// - public int HeaderSize => TgaConstants.FileHeaderLength; + public int HeaderSize => 16; /// public IImageFormat DetectFormat(ReadOnlySpan header) @@ -23,15 +23,38 @@ namespace SixLabors.ImageSharp.Formats.Tga { if (header.Length >= this.HeaderSize) { - // There are no magic bytes in a tga file, so at least the image type - // and the colormap type in the header will be checked for a valid value. + // There are no magic bytes in the first few bytes of a tga file, + // so we try to figure out if its a valid tga by checking for valid tga header bytes. + + // The color map type should be either 0 or 1, other values are not valid. if (header[1] != 0 && header[1] != 1) { return false; } + // The third byte is the image type. var imageType = (TgaImageType)header[2]; - return imageType.IsValid(); + if (!imageType.IsValid()) + { + return false; + } + + // If the color map typ is zero, all bytes of the color map specification should also be zeros. + if (header[1] == 0) + { + if (header[3] != 0 || header[4] != 0 || header[5] != 0 || header[6] != 0 || header[7] != 0) + { + return false; + } + } + + // The height or the width of the image should not be zero. + if ((header[12] == 0 && header[13] == 0) || (header[14] == 0 && header[15] == 0)) + { + return false; + } + + return true; } return false; diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs index 2b0b088a1..a305e58b7 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs @@ -1,34 +1,54 @@ // Copyright (c) Six Labors and contributors. // Licensed under the GNU Affero General Public License, Version 3. +using System.Collections.Generic; using System.IO; using SixLabors.ImageSharp.Formats; - +using SixLabors.ImageSharp.Formats.Tga; using Xunit; namespace SixLabors.ImageSharp.Tests.Formats.Tga { public class TgaFileHeaderTests { - private static readonly byte[] Data = + [Theory] + [InlineData(new byte[] { 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0, 195, 0, 32, 8 })] // invalid tga image type. + [InlineData(new byte[] { 0, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0, 195, 0, 32, 8 })] // invalid colormap type. + [InlineData(new byte[] { 0, 0, 1, 5, 5, 5, 5, 5, 0, 0, 0, 0, 250, 0, 195, 0, 32, 8 })] // valid colormap type (0), but colomap spec bytes should all be zero. + [InlineData(new byte[] { 0, 0, 1, 0, 0, 0, 0, 8, 0, 0, 0, 0, 250, 0, 195, 0, 32, 8 })] // valid colormap type (0), but colomap spec bytes should all be zero. + [InlineData(new byte[] { 0, 0, 1, 0, 0, 0, 7, 0, 0, 0, 0, 0, 250, 0, 195, 0, 32, 8 })] // valid colormap type (0), but colomap spec bytes should all be zero. + [InlineData(new byte[] { 0, 0, 1, 0, 0, 6, 0, 0, 0, 0, 0, 0, 250, 0, 195, 0, 32, 8 })] // valid colormap type (0), but colomap spec bytes should all be zero. + [InlineData(new byte[] { 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 250, 0, 195, 0, 32, 8 })] // valid colormap type (0), but colomap spec bytes should all be zero. + [InlineData(new byte[] { 0, 0, 0, 12, 106, 80, 32, 32, 13, 10, 135, 10, 0, 0, 0, 20, 102, 116 })] // jp2 image header + [InlineData(new byte[] { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 195, 0, 32, 8 })] // invalid width + [InlineData(new byte[] { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0, 0, 0, 32, 8 })] // invalid height + public void ImageLoad_WithNoValidTgaHeaderBytes_Throws_UnknownImageFormatException(byte[] data) { - 0, - 0, - 15 // invalid tga image type - }; - - private MemoryStream Stream { get; } = new MemoryStream(Data); + using var stream = new MemoryStream(data); - [Fact] - public void ImageLoad_WithInvalidImageType_Throws_UnknownImageFormatException() - { Assert.Throws(() => { - using (Image.Load(Configuration.Default, this.Stream, out IImageFormat _)) + using (Image.Load(Configuration.Default, stream, out IImageFormat _)) { } }); } + + [Theory] + [InlineData(new byte[] { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0, 195, 0, 32, 8 }, 250, 195, TgaBitsPerPixel.Pixel32)] + [InlineData(new byte[] { 26, 1, 9, 0, 0, 0, 1, 16, 0, 0, 0, 0, 128, 0, 128, 0, 8, 0 }, 128, 128, TgaBitsPerPixel.Pixel8)] + [InlineData(new byte[] { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 220, 0, 16, 0 }, 220, 220, TgaBitsPerPixel.Pixel16)] + [InlineData(new byte[] { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124, 0, 124, 0, 24, 32 }, 124, 124, TgaBitsPerPixel.Pixel24)] + public void Identify_WithValidData_Works(byte[] data, int width, int height, TgaBitsPerPixel bitsPerPixel) + { + using var stream = new MemoryStream(data); + + IImageInfo info = Image.Identify(stream); + TgaMetadata tgaData = info.Metadata.GetTgaMetadata(); + Assert.Equal(bitsPerPixel, tgaData.BitsPerPixel); + Assert.Equal(width, info.Width); + Assert.Equal(height, info.Height); + } } }