2
2
// Licensed under the Six Labors Split License.
3
3
4
4
using System . Diagnostics . CodeAnalysis ;
5
- using System . Runtime . InteropServices ;
6
5
7
6
namespace SixLabors . ImageSharp . Formats . Icon ;
8
7
@@ -12,22 +11,58 @@ namespace SixLabors.ImageSharp.Formats.Icon;
12
11
public class IconImageFormatDetector : IImageFormatDetector
13
12
{
14
13
/// <inheritdoc/>
15
- public int HeaderSize { get ; } = 4 ;
14
+ public int HeaderSize { get ; } = IconDir . Size + IconDirEntry . Size ;
16
15
17
16
/// <inheritdoc/>
18
17
public bool TryDetectFormat ( ReadOnlySpan < byte > header , [ NotNullWhen ( true ) ] out IImageFormat ? format )
19
18
{
20
- switch ( MemoryMarshal . Cast < byte , uint > ( header ) [ 0 ] )
19
+ format = this . IsSupportedFileFormat ( header ) switch
21
20
{
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 ;
31
66
}
32
67
}
33
68
}
0 commit comments