22// Licensed under the Six Labors Split License.
33
44using System . Diagnostics . CodeAnalysis ;
5- using System . Runtime . InteropServices ;
65
76namespace SixLabors . ImageSharp . Formats . Icon ;
87
@@ -12,22 +11,58 @@ namespace SixLabors.ImageSharp.Formats.Icon;
1211public class IconImageFormatDetector : IImageFormatDetector
1312{
1413 /// <inheritdoc/>
15- public int HeaderSize { get ; } = 4 ;
14+ public int HeaderSize { get ; } = IconDir . Size + IconDirEntry . Size ;
1615
1716 /// <inheritdoc/>
1817 public bool TryDetectFormat ( ReadOnlySpan < byte > header , [ NotNullWhen ( true ) ] out IImageFormat ? format )
1918 {
20- switch ( MemoryMarshal . Cast < byte , uint > ( header ) [ 0 ] )
19+ format = this . IsSupportedFileFormat ( header ) switch
2120 {
22- case Ico . IcoConstants . FileHeader :
23- format = Ico . IcoFormat . Instance ;
24- return true ;
25- case Cur . CurConstants . FileHeader :
26- format = Cur . CurFormat . Instance ;
27- return true ;
28- default :
29- format = default ;
30- return false ;
21+ true => Ico . IcoFormat . Instance ,
22+ false => Cur . CurFormat . Instance ,
23+ null => default
24+ } ;
25+
26+ return format is not null ;
27+ }
28+
29+ private bool ? IsSupportedFileFormat ( ReadOnlySpan < byte > header )
30+ {
31+ // There are no magic bytes in the first few bytes of a tga file,
32+ // so we try to figure out if its a valid tga by checking for valid tga header bytes.
33+ if ( header . Length < this . HeaderSize )
34+ {
35+ return null ;
36+ }
37+
38+ IconDir dir = IconDir . Parse ( header ) ;
39+ if ( dir is not { Reserved : 0 } // Should be 0.
40+ or not { Type : IconFileType . ICO or IconFileType . CUR } // Unknown Type.
41+ or { Count : 0 } ) // Should not be 0.
42+ {
43+ return null ;
44+ }
45+
46+ IconDirEntry entry = IconDirEntry . Parse ( header [ IconDir . Size ..] ) ;
47+ if ( entry is not { Reserved : 0 } // Should be 0.
48+ or { BytesInRes : 0 } // Should not be 0.
49+ || entry . ImageOffset < IconDir . Size + ( dir . Count * IconDirEntry . Size ) )
50+ {
51+ return null ;
52+ }
53+
54+ if ( dir . Type is IconFileType . ICO )
55+ {
56+ if ( entry is not { BitCount : 1 or 4 or 8 or 16 or 24 or 32 } or not { Planes : 0 or 1 } )
57+ {
58+ return null ;
59+ }
60+
61+ return true ;
62+ }
63+ else
64+ {
65+ return false ;
3166 }
3267 }
3368}
0 commit comments