1package magic
2
3import "bytes"
4
5var (
6	// Png matches a Portable Network Graphics file.
7	Png = prefix([]byte{0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A})
8	// Jpg matches a Joint Photographic Experts Group file.
9	Jpg = prefix([]byte{0xFF, 0xD8, 0xFF})
10	// Jp2 matches a JPEG 2000 Image file (ISO 15444-1).
11	Jp2 = jpeg2k([]byte{0x6a, 0x70, 0x32, 0x20})
12	// Jpx matches a JPEG 2000 Image file (ISO 15444-2).
13	Jpx = jpeg2k([]byte{0x6a, 0x70, 0x78, 0x20})
14	// Jpm matches a JPEG 2000 Image file (ISO 15444-6).
15	Jpm = jpeg2k([]byte{0x6a, 0x70, 0x6D, 0x20})
16	// Gif matches a Graphics Interchange Format file.
17	Gif = prefix([]byte("GIF87a"), []byte("GIF89a"))
18	// Bmp matches a bitmap image file.
19	Bmp = prefix([]byte{0x42, 0x4D})
20	// Ps matches a PostScript file.
21	Ps = prefix([]byte("%!PS-Adobe-"))
22	// Psd matches a Photoshop Document file.
23	Psd = prefix([]byte("8BPS"))
24	// Ico matches an ICO file.
25	Ico = prefix([]byte{0x00, 0x00, 0x01, 0x00}, []byte{0x00, 0x00, 0x02, 0x00})
26	// Icns matches an ICNS (Apple Icon Image format) file.
27	Icns = prefix([]byte("icns"))
28	// Tiff matches a Tagged Image File Format file.
29	Tiff = prefix([]byte{0x49, 0x49, 0x2A, 0x00}, []byte{0x4D, 0x4D, 0x00, 0x2A})
30	// Bpg matches a Better Portable Graphics file.
31	Bpg = prefix([]byte{0x42, 0x50, 0x47, 0xFB})
32	// Xcf matches GIMP image data.
33	Xcf = prefix([]byte("gimp xcf"))
34	// Pat matches GIMP pattern data.
35	Pat = offset([]byte("GPAT"), 20)
36	// Gbr matches GIMP brush data.
37	Gbr = offset([]byte("GIMP"), 20)
38	// Hdr matches Radiance HDR image.
39	// https://web.archive.org/web/20060913152809/http://local.wasp.uwa.edu.au/~pbourke/dataformats/pic/
40	Hdr = prefix([]byte("#?RADIANCE\n"))
41	// Xpm matches X PixMap image data.
42	Xpm = prefix([]byte{0x2F, 0x2A, 0x20, 0x58, 0x50, 0x4D, 0x20, 0x2A, 0x2F})
43)
44
45func jpeg2k(sig []byte) Detector {
46	return func(raw []byte, _ uint32) bool {
47		if len(raw) < 24 {
48			return false
49		}
50
51		if !bytes.Equal(raw[4:8], []byte{0x6A, 0x50, 0x20, 0x20}) &&
52			!bytes.Equal(raw[4:8], []byte{0x6A, 0x50, 0x32, 0x20}) {
53			return false
54		}
55		return bytes.Equal(raw[20:24], sig)
56	}
57}
58
59// Webp matches a WebP file.
60func Webp(raw []byte, _ uint32) bool {
61	return len(raw) > 12 &&
62		bytes.Equal(raw[0:4], []byte("RIFF")) &&
63		bytes.Equal(raw[8:12], []byte{0x57, 0x45, 0x42, 0x50})
64}
65
66// Dwg matches a CAD drawing file.
67func Dwg(raw []byte, _ uint32) bool {
68	if len(raw) < 6 || raw[0] != 0x41 || raw[1] != 0x43 {
69		return false
70	}
71	dwgVersions := [][]byte{
72		{0x31, 0x2E, 0x34, 0x30},
73		{0x31, 0x2E, 0x35, 0x30},
74		{0x32, 0x2E, 0x31, 0x30},
75		{0x31, 0x30, 0x30, 0x32},
76		{0x31, 0x30, 0x30, 0x33},
77		{0x31, 0x30, 0x30, 0x34},
78		{0x31, 0x30, 0x30, 0x36},
79		{0x31, 0x30, 0x30, 0x39},
80		{0x31, 0x30, 0x31, 0x32},
81		{0x31, 0x30, 0x31, 0x34},
82		{0x31, 0x30, 0x31, 0x35},
83		{0x31, 0x30, 0x31, 0x38},
84		{0x31, 0x30, 0x32, 0x31},
85		{0x31, 0x30, 0x32, 0x34},
86		{0x31, 0x30, 0x33, 0x32},
87	}
88
89	for _, d := range dwgVersions {
90		if bytes.Equal(raw[2:6], d) {
91			return true
92		}
93	}
94
95	return false
96}
97
98// Jxl matches JPEG XL image file.
99func Jxl(raw []byte, _ uint32) bool {
100	return bytes.HasPrefix(raw, []byte{0xFF, 0x0A}) ||
101		bytes.HasPrefix(raw, []byte("\x00\x00\x00\x0cJXL\x20\x0d\x0a\x87\x0a"))
102}
103