...
1
2 package magic
3
4 import (
5 "bytes"
6 "fmt"
7 )
8
9 type (
10
11
12
13
14 Detector func(raw []byte, limit uint32) bool
15 xmlSig struct {
16
17 localName []byte
18
19 xmlns []byte
20 }
21 )
22
23
24
25 func prefix(sigs ...[]byte) Detector {
26 return func(raw []byte, limit uint32) bool {
27 for _, s := range sigs {
28 if bytes.HasPrefix(raw, s) {
29 return true
30 }
31 }
32 return false
33 }
34 }
35
36
37
38 func offset(sig []byte, offset int) Detector {
39 return func(raw []byte, limit uint32) bool {
40 return len(raw) > offset && bytes.HasPrefix(raw[offset:], sig)
41 }
42 }
43
44
45 func ciPrefix(sigs ...[]byte) Detector {
46 return func(raw []byte, limit uint32) bool {
47 for _, s := range sigs {
48 if ciCheck(s, raw) {
49 return true
50 }
51 }
52 return false
53 }
54 }
55 func ciCheck(sig, raw []byte) bool {
56 if len(raw) < len(sig)+1 {
57 return false
58 }
59
60 for i, b := range sig {
61 db := raw[i]
62 if 'A' <= b && b <= 'Z' {
63 db &= 0xDF
64 }
65 if b != db {
66 return false
67 }
68 }
69
70 return true
71 }
72
73
74
75 func xml(sigs ...xmlSig) Detector {
76 return func(raw []byte, limit uint32) bool {
77 raw = trimLWS(raw)
78 if len(raw) == 0 {
79 return false
80 }
81 for _, s := range sigs {
82 if xmlCheck(s, raw) {
83 return true
84 }
85 }
86 return false
87 }
88 }
89 func xmlCheck(sig xmlSig, raw []byte) bool {
90 raw = raw[:min(len(raw), 512)]
91
92 if len(sig.localName) == 0 {
93 return bytes.Index(raw, sig.xmlns) > 0
94 }
95 if len(sig.xmlns) == 0 {
96 return bytes.Index(raw, sig.localName) > 0
97 }
98
99 localNameIndex := bytes.Index(raw, sig.localName)
100 return localNameIndex != -1 && localNameIndex < bytes.Index(raw, sig.xmlns)
101 }
102
103
104
105 func markup(sigs ...[]byte) Detector {
106 return func(raw []byte, limit uint32) bool {
107 if bytes.HasPrefix(raw, []byte{0xEF, 0xBB, 0xBF}) {
108
109
110
111 raw = trimLWS(raw[3:])
112 } else {
113 raw = trimLWS(raw)
114 }
115 if len(raw) == 0 {
116 return false
117 }
118 for _, s := range sigs {
119 if markupCheck(s, raw) {
120 return true
121 }
122 }
123 return false
124 }
125 }
126 func markupCheck(sig, raw []byte) bool {
127 if len(raw) < len(sig)+1 {
128 return false
129 }
130
131
132 for i, b := range sig {
133 db := raw[i]
134 if 'A' <= b && b <= 'Z' {
135 db &= 0xDF
136 }
137 if b != db {
138 return false
139 }
140 }
141
142 if db := raw[len(sig)]; db != ' ' && db != '>' {
143 return false
144 }
145
146 return true
147 }
148
149
150
151 func ftyp(sigs ...[]byte) Detector {
152 return func(raw []byte, limit uint32) bool {
153 if len(raw) < 12 {
154 return false
155 }
156 for _, s := range sigs {
157 if bytes.Equal(raw[4:12], append([]byte("ftyp"), s...)) {
158 return true
159 }
160 }
161 return false
162 }
163 }
164
165 func newXMLSig(localName, xmlns string) xmlSig {
166 ret := xmlSig{xmlns: []byte(xmlns)}
167 if localName != "" {
168 ret.localName = []byte(fmt.Sprintf("<%s", localName))
169 }
170
171 return ret
172 }
173
174
175
176
177
178
179
180
181
182
183
184 func shebang(sigs ...[]byte) Detector {
185 return func(raw []byte, limit uint32) bool {
186 for _, s := range sigs {
187 if shebangCheck(s, firstLine(raw)) {
188 return true
189 }
190 }
191 return false
192 }
193 }
194
195 func shebangCheck(sig, raw []byte) bool {
196 if len(raw) < len(sig)+2 {
197 return false
198 }
199 if raw[0] != '#' || raw[1] != '!' {
200 return false
201 }
202
203 return bytes.Equal(trimLWS(trimRWS(raw[2:])), sig)
204 }
205
206
207 func trimLWS(in []byte) []byte {
208 firstNonWS := 0
209 for ; firstNonWS < len(in) && isWS(in[firstNonWS]); firstNonWS++ {
210 }
211
212 return in[firstNonWS:]
213 }
214
215
216 func trimRWS(in []byte) []byte {
217 lastNonWS := len(in) - 1
218 for ; lastNonWS > 0 && isWS(in[lastNonWS]); lastNonWS-- {
219 }
220
221 return in[:lastNonWS+1]
222 }
223
224 func firstLine(in []byte) []byte {
225 lineEnd := 0
226 for ; lineEnd < len(in) && in[lineEnd] != '\n'; lineEnd++ {
227 }
228
229 return in[:lineEnd]
230 }
231
232 func isWS(b byte) bool {
233 return b == '\t' || b == '\n' || b == '\x0c' || b == '\r' || b == ' '
234 }
235
236 func min(a, b int) int {
237 if a < b {
238 return a
239 }
240 return b
241 }
242
View as plain text