// Copyright (C) 2019 Marius Schellenberger package scan import ( "bytes" "net/http" "os" ) 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" 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 "application/octet-stream" } func isPDF(path string) bool { f, err := os.Open(path) if err != nil { return false } defer f.Close() buf := make([]byte, maxSniffSize) _, err = f.Read(buf) if err != nil { return false } return http.DetectContentType(buf) == pdfT } func isImage(path string) bool { f, err := os.Open(path) if err != nil { return false } defer f.Close() buf := make([]byte, maxSniffSize) _, err = f.Read(buf) if err != nil { return false } switch http.DetectContentType(buf) { case jpegT, pngT, bmpT, gifT, webpT: return true default: switch extendedContentType(buf) { case pnmT, jp2T, tiffT: return true } } return false }