// Copyright (C) 2021 Marius Schellenberger package scan import ( "bytes" "net/http" "os" "strings" ) const ( pdfT = "application/pdf" jpegT = "image/jpeg" pngT = "image/png" bmpT = "image/bmp" gifT = "image/gif" webpT = "image/webp" pnmT = "image/x-portable-anymap" jp2T = "image/jp2" tiffT = "image/tiff" textT = "text/" rawT = "application/octet-stream" maxSniffSize = 512 ) type extendedSig struct { sig []byte ct string } var extendedSigs = []extendedSig{ {[]byte("P1\x0A"), pnmT}, {[]byte("P2\x0A"), pnmT}, {[]byte("P3\x0A"), pnmT}, {[]byte("P4\x0A"), pnmT}, {[]byte("P5\x0A"), pnmT}, {[]byte("P6\x0A"), pnmT}, {[]byte("P7\x0A"), pnmT}, {[]byte("\x00\x00\x00\x0C\x6A\x50\x20\x20\x0D\x0A\x87\x0A\x00\x00\x00\x14\x66\x74\x79\x70\x6A\x70\x32"), jp2T}, {[]byte("\x4d\x4d\x00\x2a"), tiffT}, {[]byte("\x49\x49\x2a\x00"), tiffT}, } func extendedContentType(buf []byte) string { for _, sig := range extendedSigs { if bytes.HasPrefix(buf, sig.sig) { return sig.ct } } return rawT } func isImage(ct string, buf []byte) bool { switch ct { case jpegT, pngT, bmpT, gifT, webpT: return true default: switch extendedContentType(buf) { case pnmT, jp2T, tiffT: return true } } return false } type filetype struct { text bool pdf bool image bool } func (s *Scanner) newFileType(path string) (ft *filetype) { ft = new(filetype) f, err := os.Open(path) if err != nil { return } defer f.Close() buf := make([]byte, maxSniffSize) n, err := f.Read(buf) if err != nil { return } buf = buf[:n] ct := http.DetectContentType(buf) ft.text = strings.HasPrefix(ct, textT) ft.pdf = ct == pdfT ft.image = isImage(ct, buf) return }