diff --git a/src/ImageSharp/Formats/Icon/IconImageFormatDetector.cs b/src/ImageSharp/Formats/Icon/IconImageFormatDetector.cs
index aff8dfe0ac..4fceef3b8e 100644
--- a/src/ImageSharp/Formats/Icon/IconImageFormatDetector.cs
+++ b/src/ImageSharp/Formats/Icon/IconImageFormatDetector.cs
@@ -2,7 +2,6 @@
// Licensed under the Six Labors Split License.
using System.Diagnostics.CodeAnalysis;
-using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.Icon;
@@ -12,22 +11,58 @@ namespace SixLabors.ImageSharp.Formats.Icon;
public class IconImageFormatDetector : IImageFormatDetector
{
///
- public int HeaderSize { get; } = 4;
+ public int HeaderSize { get; } = IconDir.Size + IconDirEntry.Size;
///
public bool TryDetectFormat(ReadOnlySpan header, [NotNullWhen(true)] out IImageFormat? format)
{
- switch (MemoryMarshal.Cast(header)[0])
+ format = this.IsSupportedFileFormat(header) switch
{
- case Ico.IcoConstants.FileHeader:
- format = Ico.IcoFormat.Instance;
- return true;
- case Cur.CurConstants.FileHeader:
- format = Cur.CurFormat.Instance;
- return true;
- default:
- format = default;
- return false;
+ true => Ico.IcoFormat.Instance,
+ false => Cur.CurFormat.Instance,
+ null => default
+ };
+
+ return format is not null;
+ }
+
+ private bool? IsSupportedFileFormat(ReadOnlySpan header)
+ {
+ // 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.
+ if (header.Length < this.HeaderSize)
+ {
+ return null;
+ }
+
+ IconDir dir = IconDir.Parse(header);
+ if (dir is not { Reserved: 0 } // Should be 0.
+ or not { Type: IconFileType.ICO or IconFileType.CUR } // Unknown Type.
+ or { Count: 0 }) // Should not be 0.
+ {
+ return null;
+ }
+
+ IconDirEntry entry = IconDirEntry.Parse(header[IconDir.Size..]);
+ if (entry is not { Reserved: 0 } // Should be 0.
+ or { BytesInRes: 0 } // Should not be 0.
+ || entry.ImageOffset < IconDir.Size + (dir.Count * IconDirEntry.Size))
+ {
+ return null;
+ }
+
+ if (dir.Type is IconFileType.ICO)
+ {
+ if (entry is not { BitCount: 1 or 4 or 8 or 16 or 24 or 32 } or not { Planes: 0 or 1 })
+ {
+ return null;
+ }
+
+ return true;
+ }
+ else
+ {
+ return false;
}
}
}