You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
93 lines
3.2 KiB
93 lines
3.2 KiB
package magic
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"strings"
|
|
)
|
|
|
|
var (
|
|
// Odt matches an OpenDocument Text file.
|
|
Odt = offset([]byte("mimetypeapplication/vnd.oasis.opendocument.text"), 30)
|
|
// Ott matches an OpenDocument Text Template file.
|
|
Ott = offset([]byte("mimetypeapplication/vnd.oasis.opendocument.text-template"), 30)
|
|
// Ods matches an OpenDocument Spreadsheet file.
|
|
Ods = offset([]byte("mimetypeapplication/vnd.oasis.opendocument.spreadsheet"), 30)
|
|
// Ots matches an OpenDocument Spreadsheet Template file.
|
|
Ots = offset([]byte("mimetypeapplication/vnd.oasis.opendocument.spreadsheet-template"), 30)
|
|
// Odp matches an OpenDocument Presentation file.
|
|
Odp = offset([]byte("mimetypeapplication/vnd.oasis.opendocument.presentation"), 30)
|
|
// Otp matches an OpenDocument Presentation Template file.
|
|
Otp = offset([]byte("mimetypeapplication/vnd.oasis.opendocument.presentation-template"), 30)
|
|
// Odg matches an OpenDocument Drawing file.
|
|
Odg = offset([]byte("mimetypeapplication/vnd.oasis.opendocument.graphics"), 30)
|
|
// Otg matches an OpenDocument Drawing Template file.
|
|
Otg = offset([]byte("mimetypeapplication/vnd.oasis.opendocument.graphics-template"), 30)
|
|
// Odf matches an OpenDocument Formula file.
|
|
Odf = offset([]byte("mimetypeapplication/vnd.oasis.opendocument.formula"), 30)
|
|
// Odc matches an OpenDocument Chart file.
|
|
Odc = offset([]byte("mimetypeapplication/vnd.oasis.opendocument.chart"), 30)
|
|
// Epub matches an EPUB file.
|
|
Epub = offset([]byte("mimetypeapplication/epub+zip"), 30)
|
|
// Sxc matches an OpenOffice Spreadsheet file.
|
|
Sxc = offset([]byte("mimetypeapplication/vnd.sun.xml.calc"), 30)
|
|
)
|
|
|
|
// Zip matches a zip archive.
|
|
func Zip(raw []byte, limit uint32) bool {
|
|
return len(raw) > 3 &&
|
|
raw[0] == 0x50 && raw[1] == 0x4B &&
|
|
(raw[2] == 0x3 || raw[2] == 0x5 || raw[2] == 0x7) &&
|
|
(raw[3] == 0x4 || raw[3] == 0x6 || raw[3] == 0x8)
|
|
}
|
|
|
|
// Jar matches a Java archive file.
|
|
func Jar(raw []byte, limit uint32) bool {
|
|
return zipContains(raw, "META-INF/MANIFEST.MF")
|
|
}
|
|
|
|
// zipTokenizer holds the source zip file and scanned index.
|
|
type zipTokenizer struct {
|
|
in []byte
|
|
i int // current index
|
|
}
|
|
|
|
// next returns the next file name from the zip headers.
|
|
// https://web.archive.org/web/20191129114319/https://users.cs.jmu.edu/buchhofp/forensics/formats/pkzip.html
|
|
func (t *zipTokenizer) next() (fileName string) {
|
|
if t.i > len(t.in) {
|
|
return
|
|
}
|
|
in := t.in[t.i:]
|
|
// pkSig is the signature of the zip local file header.
|
|
pkSig := []byte("PK\003\004")
|
|
pkIndex := bytes.Index(in, pkSig)
|
|
// 30 is the offset of the file name in the header.
|
|
fNameOffset := pkIndex + 30
|
|
// end if signature not found or file name offset outside of file.
|
|
if pkIndex == -1 || fNameOffset > len(in) {
|
|
return
|
|
}
|
|
|
|
fNameLen := int(binary.LittleEndian.Uint16(in[pkIndex+26 : pkIndex+28]))
|
|
if fNameLen <= 0 || fNameOffset+fNameLen > len(in) {
|
|
return
|
|
}
|
|
t.i += fNameOffset + fNameLen
|
|
return string(in[fNameOffset : fNameOffset+fNameLen])
|
|
}
|
|
|
|
// zipContains returns true if the zip file headers from in contain any of the paths.
|
|
func zipContains(in []byte, paths ...string) bool {
|
|
t := zipTokenizer{in: in}
|
|
for i, tok := 0, t.next(); tok != ""; i, tok = i+1, t.next() {
|
|
for p := range paths {
|
|
if strings.HasPrefix(tok, paths[p]) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|