-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmagic.go
More file actions
152 lines (137 loc) · 3.97 KB
/
Copy pathmagic.go
File metadata and controls
152 lines (137 loc) · 3.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Package magic identifies the physical format and text encoding of file
// content.
package magic
// Kind is the broad content class.
type Kind string
const (
// KindUnknown means the bytes could not be classified as text or binary.
KindUnknown Kind = "unknown"
// KindText means the bytes satisfy the package's text rules.
KindText Kind = "text"
// KindBinary means the bytes have a binary signature or binary content.
KindBinary Kind = "binary"
)
// Reason explains why a classification is provisional or unknown.
type Reason string
const (
// ReasonNone means the classification is final for the supplied input.
ReasonNone Reason = ""
// ReasonNeedMore means more bytes could change a prefix classification.
ReasonNeedMore Reason = "need-more"
// ReasonInvalidText means the bytes are neither accepted text nor
// recognised binary content.
ReasonInvalidText Reason = "invalid-text"
)
// Result describes the physical format and text properties of content.
//
// MIME never includes a charset parameter. Encoding uses lowercase registered
// names. Empty fields mean that the corresponding property was not identified.
type Result struct {
Kind Kind
MIME string
Format string
Encoding string
Reason Reason
NeedBytes int
}
// Format values reported in Result.Format.
const (
FormatText = "text"
FormatHTML = "html"
FormatXML = "xml"
FormatSVG = "svg"
FormatJSON = "json"
FormatZIP = "zip"
FormatTAR = "tar"
FormatPHAR = "phar"
FormatGZIP = "gzip"
FormatBZIP2 = "bzip2"
FormatXZ = "xz"
FormatZstd = "zstd"
FormatPDF = "pdf"
FormatCFBF = "cfbf"
FormatPNG = "png"
FormatJPEG = "jpeg"
FormatGIF = "gif"
FormatELF = "elf"
FormatMachO = "mach-o"
FormatPE = "pe"
FormatWASM = "wasm"
FormatAR = "ar"
)
const (
mimeText = "text/plain"
mimeHTML = "text/html"
mimeXML = "text/xml"
mimeSVG = "image/svg+xml"
mimeJSON = "application/json"
mimeZIP = "application/zip"
mimeTAR = "application/x-tar"
mimePHAR = "application/x-phar"
mimeGZIP = "application/gzip"
mimeBZIP2 = "application/x-bzip2"
mimeXZ = "application/x-xz"
mimePDF = "application/pdf"
mimeCFBF = "application/x-ole-storage"
mimePNG = "image/png"
mimeJPEG = "image/jpeg"
mimeGIF = "image/gif"
mimeZstd = "application/zstd"
mimeELF = "application/x-elf"
mimeMachO = "application/x-mach-binary"
mimePE = "application/vnd.microsoft.portable-executable"
mimeWASM = "application/wasm"
mimeAR = "application/x-archive"
encodingUTF8 = "utf-8"
encodingUTF16LE = "utf-16le"
encodingUTF16BE = "utf-16be"
)
// Detect classifies data as the complete content of a file.
func Detect(data []byte) Result {
return detect(data, false)
}
// DetectPrefix classifies an intentionally bounded file prefix.
//
// ReasonNeedMore reports that later bytes could change the answer. NeedBytes
// is reserved for a known minimum total length and is zero in this release.
func DetectPrefix(prefix []byte) Result {
if len(prefix) == 0 {
return Result{Kind: KindUnknown, Reason: ReasonNeedMore}
}
return detect(prefix, true)
}
func detect(data []byte, prefix bool) Result {
format, mime, binaryNeedsMore := binaryFormatState(data)
if format != "" {
return Result{
Kind: KindBinary,
MIME: mime,
Format: format,
}
}
format, mime = textFormat(data)
if format == "" && isJSON(data, prefix) {
format = FormatJSON
mime = mimeJSON
}
result := classifyText(data)
if format != "" {
result.Format = format
result.MIME = mime
} else if result.Kind == KindText {
result.Format = FormatText
result.MIME = mimeText
}
if prefix && (binaryNeedsMore || prefixResultCanChange(result, len(data))) {
result.Reason = ReasonNeedMore
}
return result
}
func prefixResultCanChange(result Result, inputLength int) bool {
if result.Kind == KindBinary {
// Fixed-offset binary signatures are final once the sniff window is
// present. Incomplete PHAR validation is handled before this function.
return inputLength < sniffLength
}
return true
}