1package magic
2
3import (
4	"bytes"
5	"encoding/binary"
6)
7
8var (
9	// Flac matches a Free Lossless Audio Codec file.
10	Flac = prefix([]byte("\x66\x4C\x61\x43\x00\x00\x00\x22"))
11	// Midi matches a Musical Instrument Digital Interface file.
12	Midi = prefix([]byte("\x4D\x54\x68\x64"))
13	// Ape matches a Monkey's Audio file.
14	Ape = prefix([]byte("\x4D\x41\x43\x20\x96\x0F\x00\x00\x34\x00\x00\x00\x18\x00\x00\x00\x90\xE3"))
15	// MusePack matches a Musepack file.
16	MusePack = prefix([]byte("MPCK"))
17	// Au matches a Sun Microsystems au file.
18	Au = prefix([]byte("\x2E\x73\x6E\x64"))
19	// Amr matches an Adaptive Multi-Rate file.
20	Amr = prefix([]byte("\x23\x21\x41\x4D\x52"))
21	// Voc matches a Creative Voice file.
22	Voc = prefix([]byte("Creative Voice File"))
23	// M3u matches a Playlist file.
24	M3u = prefix([]byte("#EXTM3U"))
25)
26
27// Mp3 matches an mp3 file.
28func Mp3(raw []byte, limit uint32) bool {
29	if len(raw) < 3 {
30		return false
31	}
32
33	if bytes.HasPrefix(raw, []byte("ID3")) {
34		// MP3s with an ID3v2 tag will start with "ID3"
35		// ID3v1 tags, however appear at the end of the file.
36		return true
37	}
38
39	// Match MP3 files without tags
40	switch binary.BigEndian.Uint16(raw[:2]) & 0xFFFE {
41	case 0xFFFA:
42		// MPEG ADTS, layer III, v1
43		return true
44	case 0xFFF2:
45		// MPEG ADTS, layer III, v2
46		return true
47	case 0xFFE2:
48		// MPEG ADTS, layer III, v2.5
49		return true
50	}
51
52	return false
53}
54
55// Aac matches an Advanced Audio Coding file.
56func Aac(raw []byte, limit uint32) bool {
57	return bytes.HasPrefix(raw, []byte{0xFF, 0xF1}) ||
58		bytes.HasPrefix(raw, []byte{0xFF, 0xF9})
59}
60
61// Wav matches a Waveform Audio File Format file.
62func Wav(raw []byte, limit uint32) bool {
63	return len(raw) > 12 &&
64		bytes.Equal(raw[:4], []byte("RIFF")) &&
65		bytes.Equal(raw[8:12], []byte("\x57\x41\x56\x45"))
66}
67
68// Aiff matches Audio Interchange File Format file.
69func Aiff(raw []byte, limit uint32) bool {
70	return len(raw) > 12 &&
71		bytes.Equal(raw[:4], []byte("\x46\x4F\x52\x4D")) &&
72		bytes.Equal(raw[8:12], []byte("\x41\x49\x46\x46"))
73}
74
75// Qcp matches a Qualcomm Pure Voice file.
76func Qcp(raw []byte, limit uint32) bool {
77	return len(raw) > 12 &&
78		bytes.Equal(raw[:4], []byte("RIFF")) &&
79		bytes.Equal(raw[8:12], []byte("QLCM"))
80}
81