diff --git a/internal/charset/charset.go b/internal/charset/charset.go index 380357f..d1ccdd1 100644 --- a/internal/charset/charset.go +++ b/internal/charset/charset.go @@ -29,7 +29,7 @@ var ( } // https://github.com/file/file/blob/fa93fb9f7d21935f1c7644c47d2975d31f12b812/src/encoding.c#L241 - textChars [256]byte = [256]byte{ + textChars = [256]byte{ /* BEL BS HT LF VT FF CR */ F, F, F, F, F, F, F, T, T, T, T, T, T, T, F, F, /* 0x0X */ /* ESC */ diff --git a/internal/json/json.go b/internal/json/json.go index 683b159..ee39349 100644 --- a/internal/json/json.go +++ b/internal/json/json.go @@ -74,7 +74,7 @@ type ( ) // Scan returns the number of bytes scanned and if there was any error -// in trying to reach the end of data +// in trying to reach the end of data. func Scan(data []byte) (int, error) { s := &scanner{} _ = checkValid(data, s) diff --git a/internal/magic/archive.go b/internal/magic/archive.go index 8f5ff87..b4a1702 100644 --- a/internal/magic/archive.go +++ b/internal/magic/archive.go @@ -37,6 +37,12 @@ var ( Xz = prefix([]byte{0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00}) // Lzip matches an Lzip compressed file. Lzip = prefix([]byte{0x4c, 0x5a, 0x49, 0x50}) + // RPM matches an RPM or Delta RPM package file. + RPM = prefix([]byte{0xed, 0xab, 0xee, 0xdb}, []byte("drpm")) + // Cpio matches a cpio archive file. + Cpio = prefix([]byte("070707"), []byte("070701"), []byte("070702")) + // RAR matches a RAR archive file. + RAR = prefix([]byte("Rar!\x1A\x07\x00"), []byte("Rar!\x1A\x07\x01\x00")) ) // Zstd matches a Zstandard archive file. @@ -46,27 +52,8 @@ func Zstd(raw []byte, limit uint32) bool { bytes.HasPrefix(raw[1:], []byte{0xB5, 0x2F, 0xFD}) } -// Rpm matches an RPM or Delta RPM package file. -func Rpm(raw []byte, limit uint32) bool { - return bytes.HasPrefix(raw, []byte{0xed, 0xab, 0xee, 0xdb}) || - bytes.HasPrefix(raw, []byte("drpm")) -} - -// Cpio matches a cpio archive file. -func Cpio(raw []byte, limit uint32) bool { - return bytes.HasPrefix(raw, []byte("070707")) || - bytes.HasPrefix(raw, []byte("070701")) || - bytes.HasPrefix(raw, []byte("070702")) -} - -// Rar matches a RAR archive file. -func Rar(raw []byte, limit uint32) bool { - return bytes.HasPrefix(raw, []byte("Rar!\x1A\x07\x00")) || - bytes.HasPrefix(raw, []byte("Rar!\x1A\x07\x01\x00")) -} - -// Crx matches a Chrome extension file: a zip archive prepended by a package header. -func Crx(raw []byte, limit uint32) bool { +// CRX matches a Chrome extension file: a zip archive prepended by a package header. +func CRX(raw []byte, limit uint32) bool { const minHeaderLen = 16 if len(raw) < minHeaderLen || !bytes.HasPrefix(raw, []byte("Cr24")) { return false diff --git a/internal/magic/audio.go b/internal/magic/audio.go index ca3c833..d17e324 100644 --- a/internal/magic/audio.go +++ b/internal/magic/audio.go @@ -22,6 +22,8 @@ var ( Voc = prefix([]byte("Creative Voice File")) // M3u matches a Playlist file. M3u = prefix([]byte("#EXTM3U")) + // AAC matches an Advanced Audio Coding file. + AAC = prefix([]byte{0xFF, 0xF1}, []byte{0xFF, 0xF9}) ) // Mp3 matches an mp3 file. @@ -52,24 +54,18 @@ func Mp3(raw []byte, limit uint32) bool { return false } -// Aac matches an Advanced Audio Coding file. -func Aac(raw []byte, limit uint32) bool { - return bytes.HasPrefix(raw, []byte{0xFF, 0xF1}) || - bytes.HasPrefix(raw, []byte{0xFF, 0xF9}) -} - // Wav matches a Waveform Audio File Format file. func Wav(raw []byte, limit uint32) bool { return len(raw) > 12 && bytes.Equal(raw[:4], []byte("RIFF")) && - bytes.Equal(raw[8:12], []byte("\x57\x41\x56\x45")) + bytes.Equal(raw[8:12], []byte{0x57, 0x41, 0x56, 0x45}) } // Aiff matches Audio Interchange File Format file. func Aiff(raw []byte, limit uint32) bool { return len(raw) > 12 && - bytes.Equal(raw[:4], []byte("\x46\x4F\x52\x4D")) && - bytes.Equal(raw[8:12], []byte("\x41\x49\x46\x46")) + bytes.Equal(raw[:4], []byte{0x46, 0x4F, 0x52, 0x4D}) && + bytes.Equal(raw[8:12], []byte{0x41, 0x49, 0x46, 0x46}) } // Qcp matches a Qualcomm Pure Voice file. diff --git a/internal/magic/binary.go b/internal/magic/binary.go index 3419dcf..feca467 100644 --- a/internal/magic/binary.go +++ b/internal/magic/binary.go @@ -19,6 +19,10 @@ var ( Nes = prefix([]byte{0x4E, 0x45, 0x53, 0x1A}) // TzIf matches a Time Zone Information Format (TZif) file. TzIf = prefix([]byte("TZif")) + // SWF matches an Adobe Flash swf file. + SWF = prefix([]byte("CWS"), []byte("FWS"), []byte("ZWS")) + // Torrent has bencoded text in the beginning. + Torrent = prefix([]byte("d8:announce")) ) // Java bytecode and Mach-O binaries share the same magic number. @@ -57,13 +61,6 @@ func MachO(raw []byte, limit uint32) bool { le == macho.Magic64 } -// Swf matches an Adobe Flash swf file. -func Swf(raw []byte, limit uint32) bool { - return bytes.HasPrefix(raw, []byte("CWS")) || - bytes.HasPrefix(raw, []byte("FWS")) || - bytes.HasPrefix(raw, []byte("ZWS")) -} - // Dbf matches a dBase file. // https://www.dbase.com/Knowledgebase/INT/db7_file_fmt.htm func Dbf(raw []byte, limit uint32) bool { @@ -142,3 +139,19 @@ func Marc(raw []byte, limit uint32) bool { // Field terminator is present in first 2048 bytes. return bytes.Contains(raw[:min(2048, len(raw))], []byte{0x1E}) } + +// Glb matches a glTF model format file. +// GLB is the binary file format representation of 3D models save in +// the GL transmission Format (glTF). +// see more: https://docs.fileformat.com/3d/glb/ +// https://www.iana.org/assignments/media-types/model/gltf-binary +// GLB file format is based on little endian and its header structure +// show below: +// +// <-- 12-byte header --> +// | magic | version | length | +// | (uint32) | (uint32) | (uint32) | +// | \x67\x6C\x54\x46 | \x01\x00\x00\x00 | ... | +// | g l T F | 1 | ... | +var Glb = prefix([]byte("\x67\x6C\x54\x46\x02\x00\x00\x00"), + []byte("\x67\x6C\x54\x46\x01\x00\x00\x00")) diff --git a/internal/magic/model.go b/internal/magic/model.go deleted file mode 100644 index 687effa..0000000 --- a/internal/magic/model.go +++ /dev/null @@ -1,17 +0,0 @@ -package magic - -// Glb matches a glTF model format file. -// GLB is the binary file format representation of 3D models save in -// the GL transmission Format (glTF). -// see more: https://docs.fileformat.com/3d/glb/ -// https://www.iana.org/assignments/media-types/model/gltf-binary -// GLB file format is based on little endian and its header structure -// show below: -// -// <-- 12-byte header --> -// | magic | version | length | -// | (uint32) | (uint32) | (uint32) | -// | \x67\x6C\x54\x46 | \x01\x00\x00\x00 | ... | -// | g l T F | 1 | ... | -var Glb = prefix([]byte("\x67\x6C\x54\x46\x02\x00\x00\x00"), - []byte("\x67\x6C\x54\x46\x01\x00\x00\x00")) diff --git a/internal/magic/signature.go b/internal/magic/signature.go index 0cb5359..abab040 100644 --- a/internal/magic/signature.go +++ b/internal/magic/signature.go @@ -1,4 +1,4 @@ -// package magic holds the matching functions used to find MIME types. +// Package magic holds the matching functions used to find MIME types. package magic import ( @@ -7,6 +7,10 @@ import ( ) type ( + // Detector receiveѕ the raw data of a file and returns whether the data + // meets any conditions. The limit parameter is an upper limit to the number + // of bytes received and is used to tell if the byte slice represents the + // whole file or is just the header of a file: len(raw) < limit or len(raw)>limit. Detector func(raw []byte, limit uint32) bool xmlSig struct { // the local name of the root tag @@ -151,7 +155,7 @@ func ftyp(sigs ...[]byte) Detector { } } -func newXmlSig(localName, xmlns string) xmlSig { +func newXMLSig(localName, xmlns string) xmlSig { ret := xmlSig{xmlns: []byte(xmlns)} if localName != "" { ret.localName = []byte(fmt.Sprintf("<%s", localName)) diff --git a/internal/magic/text.go b/internal/magic/text.go index dff756c..db5ff5a 100644 --- a/internal/magic/text.go +++ b/internal/magic/text.go @@ -9,8 +9,8 @@ import ( ) var ( - // Html matches a Hypertext Markup Language file. - Html = markup( + // HTML matches a Hypertext Markup Language file. + HTML = markup( []byte(" 1 && hasObjOrArr } -// Har matches a HAR Spec file. +// HAR matches a HAR Spec file. // Spec: http://www.softwareishard.com/blog/har-12-spec/ func HAR(raw []byte, limit uint32) bool { s := []byte(`"log"`) @@ -279,12 +279,12 @@ func HAR(raw []byte, limit uint32) bool { // Skip any whitespace after the colon. raw = trimLWS(raw[1:]) - harJsonTypes := [][]byte{ + harJSONTypes := [][]byte{ []byte(`"version"`), []byte(`"creator"`), []byte(`"entries"`), } - for _, t := range harJsonTypes { + for _, t := range harJSONTypes { si := bytes.Index(raw, t) if si > -1 { return true diff --git a/internal/magic/torrent.go b/internal/magic/torrent.go deleted file mode 100644 index ca6a5c9..0000000 --- a/internal/magic/torrent.go +++ /dev/null @@ -1,4 +0,0 @@ -package magic - -// Torrent has bencoded text in the beginning. -var Torrent = prefix([]byte("d8:announce")) diff --git a/mime.go b/mime.go index 51dc4cd..e5a1c4e 100644 --- a/mime.go +++ b/mime.go @@ -70,7 +70,6 @@ func newMIME( mime, extension string, detector magic.Detector, children ...*MIME) *MIME { - m := &MIME{ mime: mime, extension: extension, diff --git a/mimetype.go b/mimetype.go index 61f1fbe..08e68e3 100644 --- a/mimetype.go +++ b/mimetype.go @@ -52,7 +52,7 @@ func DetectReader(r io.Reader) (*MIME, error) { return errMIME, err } } else { - n := 0 + var n int in = make([]byte, l) // io.UnexpectedEOF means len(r) < len(in). It is not an error in this case, // it just means the input file is smaller than the allocated bytes slice. diff --git a/tree.go b/tree.go index 374728b..dfd3227 100644 --- a/tree.go +++ b/tree.go @@ -77,14 +77,14 @@ var ( oggAudio = newMIME("audio/ogg", ".oga", magic.OggAudio) oggVideo = newMIME("video/ogg", ".ogv", magic.OggVideo) text = newMIME("text/plain", ".txt", magic.Text, html, svg, xml, php, js, lua, perl, python, json, ndJSON, rtf, tcl, csv, tsv, vCard, iCalendar, warc) - xml = newMIME("text/xml", ".xml", magic.Xml, rss, atom, x3d, kml, xliff, collada, gml, gpx, tcx, amf, threemf, xfdf, owl2) + xml = newMIME("text/xml", ".xml", magic.XML, rss, atom, x3d, kml, xliff, collada, gml, gpx, tcx, amf, threemf, xfdf, owl2) json = newMIME("application/json", ".json", magic.JSON, geoJSON, har) har = newMIME("application/json", ".har", magic.HAR) csv = newMIME("text/csv", ".csv", magic.Csv) tsv = newMIME("text/tab-separated-values", ".tsv", magic.Tsv) geoJSON = newMIME("application/geo+json", ".geojson", magic.GeoJSON) ndJSON = newMIME("application/x-ndjson", ".ndjson", magic.NdJSON) - html = newMIME("text/html", ".html", magic.Html) + html = newMIME("text/html", ".html", magic.HTML) php = newMIME("text/x-php", ".php", magic.Php) rtf = newMIME("text/rtf", ".rtf", magic.Rtf) js = newMIME("application/javascript", ".js", magic.Js). @@ -147,7 +147,7 @@ var ( au = newMIME("audio/basic", ".au", magic.Au) amr = newMIME("audio/amr", ".amr", magic.Amr). alias("audio/amr-nb") - aac = newMIME("audio/aac", ".aac", magic.Aac) + aac = newMIME("audio/aac", ".aac", magic.AAC) voc = newMIME("audio/x-unknown", ".voc", magic.Voc) aMp4 = newMIME("audio/mp4", ".mp4", magic.AMp4). alias("audio/x-m4a", "audio/x-mp4a") @@ -173,8 +173,8 @@ var ( alias("video/asf", "video/x-ms-wmv") rmvb = newMIME("application/vnd.rn-realmedia-vbr", ".rmvb", magic.Rmvb) class = newMIME("application/x-java-applet", ".class", magic.Class) - swf = newMIME("application/x-shockwave-flash", ".swf", magic.Swf) - crx = newMIME("application/x-chrome-extension", ".crx", magic.Crx) + swf = newMIME("application/x-shockwave-flash", ".swf", magic.SWF) + crx = newMIME("application/x-chrome-extension", ".crx", magic.CRX) ttf = newMIME("font/ttf", ".ttf", magic.Ttf). alias("font/sfnt", "application/x-font-ttf", "application/font-sfnt") woff = newMIME("font/woff", ".woff", magic.Woff) @@ -194,7 +194,7 @@ var ( ar = newMIME("application/x-archive", ".a", magic.Ar, deb). alias("application/x-unix-archive") deb = newMIME("application/vnd.debian.binary-package", ".deb", magic.Deb) - rpm = newMIME("application/x-rpm", ".rpm", magic.Rpm) + rpm = newMIME("application/x-rpm", ".rpm", magic.RPM) dcm = newMIME("application/dicom", ".dcm", magic.Dcm) odt = newMIME("application/vnd.oasis.opendocument.text", ".odt", magic.Odt, ott). alias("application/x-vnd.oasis.opendocument.text") @@ -217,7 +217,7 @@ var ( odc = newMIME("application/vnd.oasis.opendocument.chart", ".odc", magic.Odc). alias("application/x-vnd.oasis.opendocument.chart") sxc = newMIME("application/vnd.sun.xml.calc", ".sxc", magic.Sxc) - rar = newMIME("application/x-rar-compressed", ".rar", magic.Rar). + rar = newMIME("application/x-rar-compressed", ".rar", magic.RAR). alias("application/x-rar") djvu = newMIME("image/vnd.djvu", ".djvu", magic.DjVu) mobi = newMIME("application/x-mobipocket-ebook", ".mobi", magic.Mobi)