MeUtils 2025.3.3.18.41.24__py3-none-any.whl → 2025.3.5.19.55.22__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {MeUtils-2025.3.3.18.41.24.dist-info → MeUtils-2025.3.5.19.55.22.dist-info}/METADATA +264 -264
- {MeUtils-2025.3.3.18.41.24.dist-info → MeUtils-2025.3.5.19.55.22.dist-info}/RECORD +61 -33
- examples/_openaisdk/open_router.py +2 -1
- examples/_openaisdk/openai_files.py +16 -5
- examples/_openaisdk/openai_images.py +1 -0
- examples/_openaisdk/openai_moon.py +22 -19
- examples/sh/__init__.py +11 -0
- meutils/apis/baidu/bdaitpzs.py +9 -17
- meutils/apis/chatglm/glm_video_api.py +2 -2
- meutils/apis/images/edits.py +7 -2
- meutils/apis/jimeng/common.py +1 -1
- meutils/apis/oneapi/common.py +4 -4
- meutils/apis/proxy/ips.py +2 -0
- meutils/caches/common.py +4 -0
- meutils/data/VERSION +1 -1
- meutils/data/oneapi/NOTICE.html +12 -0
- meutils/data/oneapi/__init__.py +1 -1
- meutils/data/oneapi/index.html +275 -0
- meutils/io/_openai_files.py +31 -0
- meutils/io/openai_files.py +138 -0
- meutils/io/parsers/__init__.py +10 -0
- meutils/io/parsers/fileparser/PDF/346/212/275/345/217/226.py +58 -0
- meutils/io/parsers/fileparser/__init__.py +11 -0
- meutils/io/parsers/fileparser/common.py +91 -0
- meutils/io/parsers/fileparser/demo.py +41 -0
- meutils/io/parsers/fileparser/filetype/__init__.py +10 -0
- meutils/io/parsers/fileparser/filetype/__main__.py +37 -0
- meutils/io/parsers/fileparser/filetype/filetype.py +98 -0
- meutils/io/parsers/fileparser/filetype/helpers.py +140 -0
- meutils/io/parsers/fileparser/filetype/match.py +155 -0
- meutils/io/parsers/fileparser/filetype/types/__init__.py +118 -0
- meutils/io/parsers/fileparser/filetype/types/application.py +22 -0
- meutils/io/parsers/fileparser/filetype/types/archive.py +687 -0
- meutils/io/parsers/fileparser/filetype/types/audio.py +212 -0
- meutils/io/parsers/fileparser/filetype/types/base.py +29 -0
- meutils/io/parsers/fileparser/filetype/types/document.py +256 -0
- meutils/io/parsers/fileparser/filetype/types/font.py +115 -0
- meutils/io/parsers/fileparser/filetype/types/image.py +383 -0
- meutils/io/parsers/fileparser/filetype/types/isobmff.py +33 -0
- meutils/io/parsers/fileparser/filetype/types/video.py +223 -0
- meutils/io/parsers/fileparser/filetype/utils.py +84 -0
- meutils/io/parsers/fileparser/filetype.py +41 -0
- meutils/io/parsers/fileparser/mineru.py +48 -0
- meutils/io/parsers/fileparser/pdf.py +30 -0
- meutils/io/parsers/fileparser//350/241/250/346/240/274/346/212/275/345/217/226.py +118 -0
- meutils/llm/check_utils.py +33 -2
- meutils/llm/clients.py +1 -0
- meutils/llm/completions/chat_gemini.py +72 -0
- meutils/llm/completions/chat_plus.py +78 -0
- meutils/llm/completions/{agents/file.py → chat_spark.py} +46 -26
- meutils/llm/completions/qwenllm.py +57 -16
- meutils/llm/completions/yuanbao.py +29 -3
- meutils/llm/openai_utils/common.py +2 -2
- meutils/schemas/oneapi/common.py +22 -19
- meutils/schemas/openai_types.py +65 -29
- meutils/schemas/yuanbao_types.py +6 -7
- meutils/types.py +2 -0
- meutils/data/oneapi/NOTICE.md +0 -1
- meutils/data/oneapi/_NOTICE.md +0 -140
- meutils/llm/completions/gemini.py +0 -69
- {MeUtils-2025.3.3.18.41.24.dist-info → MeUtils-2025.3.5.19.55.22.dist-info}/LICENSE +0 -0
- {MeUtils-2025.3.3.18.41.24.dist-info → MeUtils-2025.3.5.19.55.22.dist-info}/WHEEL +0 -0
- {MeUtils-2025.3.3.18.41.24.dist-info → MeUtils-2025.3.5.19.55.22.dist-info}/entry_points.txt +0 -0
- {MeUtils-2025.3.3.18.41.24.dist-info → MeUtils-2025.3.5.19.55.22.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,687 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
from __future__ import absolute_import
|
4
|
+
|
5
|
+
import struct
|
6
|
+
|
7
|
+
from .base import Type
|
8
|
+
|
9
|
+
|
10
|
+
class Epub(Type):
|
11
|
+
"""
|
12
|
+
Implements the EPUB archive type matcher.
|
13
|
+
"""
|
14
|
+
MIME = 'application/epub+zip'
|
15
|
+
EXTENSION = 'epub'
|
16
|
+
|
17
|
+
def __init__(self):
|
18
|
+
super(Epub, self).__init__(
|
19
|
+
mime=Epub.MIME,
|
20
|
+
extension=Epub.EXTENSION
|
21
|
+
)
|
22
|
+
|
23
|
+
def match(self, buf):
|
24
|
+
return (len(buf) > 57 and
|
25
|
+
buf[0] == 0x50 and buf[1] == 0x4B and
|
26
|
+
buf[2] == 0x3 and buf[3] == 0x4 and
|
27
|
+
buf[30] == 0x6D and buf[31] == 0x69 and
|
28
|
+
buf[32] == 0x6D and buf[33] == 0x65 and
|
29
|
+
buf[34] == 0x74 and buf[35] == 0x79 and
|
30
|
+
buf[36] == 0x70 and buf[37] == 0x65 and
|
31
|
+
buf[38] == 0x61 and buf[39] == 0x70 and
|
32
|
+
buf[40] == 0x70 and buf[41] == 0x6C and
|
33
|
+
buf[42] == 0x69 and buf[43] == 0x63 and
|
34
|
+
buf[44] == 0x61 and buf[45] == 0x74 and
|
35
|
+
buf[46] == 0x69 and buf[47] == 0x6F and
|
36
|
+
buf[48] == 0x6E and buf[49] == 0x2F and
|
37
|
+
buf[50] == 0x65 and buf[51] == 0x70 and
|
38
|
+
buf[52] == 0x75 and buf[53] == 0x62 and
|
39
|
+
buf[54] == 0x2B and buf[55] == 0x7A and
|
40
|
+
buf[56] == 0x69 and buf[57] == 0x70)
|
41
|
+
|
42
|
+
|
43
|
+
class Zip(Type):
|
44
|
+
"""
|
45
|
+
Implements the Zip archive type matcher.
|
46
|
+
"""
|
47
|
+
MIME = 'application/zip'
|
48
|
+
EXTENSION = 'zip'
|
49
|
+
|
50
|
+
def __init__(self):
|
51
|
+
super(Zip, self).__init__(
|
52
|
+
mime=Zip.MIME,
|
53
|
+
extension=Zip.EXTENSION
|
54
|
+
)
|
55
|
+
|
56
|
+
def match(self, buf):
|
57
|
+
return (len(buf) > 3 and
|
58
|
+
buf[0] == 0x50 and buf[1] == 0x4B and
|
59
|
+
(buf[2] == 0x3 or buf[2] == 0x5 or
|
60
|
+
buf[2] == 0x7) and
|
61
|
+
(buf[3] == 0x4 or buf[3] == 0x6 or
|
62
|
+
buf[3] == 0x8))
|
63
|
+
|
64
|
+
|
65
|
+
class Tar(Type):
|
66
|
+
"""
|
67
|
+
Implements the Tar archive type matcher.
|
68
|
+
"""
|
69
|
+
MIME = 'application/x-tar'
|
70
|
+
EXTENSION = 'tar'
|
71
|
+
|
72
|
+
def __init__(self):
|
73
|
+
super(Tar, self).__init__(
|
74
|
+
mime=Tar.MIME,
|
75
|
+
extension=Tar.EXTENSION
|
76
|
+
)
|
77
|
+
|
78
|
+
def match(self, buf):
|
79
|
+
return (len(buf) > 261 and
|
80
|
+
buf[257] == 0x75 and
|
81
|
+
buf[258] == 0x73 and
|
82
|
+
buf[259] == 0x74 and
|
83
|
+
buf[260] == 0x61 and
|
84
|
+
buf[261] == 0x72)
|
85
|
+
|
86
|
+
|
87
|
+
class Rar(Type):
|
88
|
+
"""
|
89
|
+
Implements the RAR archive type matcher.
|
90
|
+
"""
|
91
|
+
MIME = 'application/x-rar-compressed'
|
92
|
+
EXTENSION = 'rar'
|
93
|
+
|
94
|
+
def __init__(self):
|
95
|
+
super(Rar, self).__init__(
|
96
|
+
mime=Rar.MIME,
|
97
|
+
extension=Rar.EXTENSION
|
98
|
+
)
|
99
|
+
|
100
|
+
def match(self, buf):
|
101
|
+
return (len(buf) > 6 and
|
102
|
+
buf[0] == 0x52 and
|
103
|
+
buf[1] == 0x61 and
|
104
|
+
buf[2] == 0x72 and
|
105
|
+
buf[3] == 0x21 and
|
106
|
+
buf[4] == 0x1A and
|
107
|
+
buf[5] == 0x7 and
|
108
|
+
(buf[6] == 0x0 or
|
109
|
+
buf[6] == 0x1))
|
110
|
+
|
111
|
+
|
112
|
+
class Gz(Type):
|
113
|
+
"""
|
114
|
+
Implements the GZ archive type matcher.
|
115
|
+
"""
|
116
|
+
MIME = 'application/gzip'
|
117
|
+
EXTENSION = 'gz'
|
118
|
+
|
119
|
+
def __init__(self):
|
120
|
+
super(Gz, self).__init__(
|
121
|
+
mime=Gz.MIME,
|
122
|
+
extension=Gz.EXTENSION
|
123
|
+
)
|
124
|
+
|
125
|
+
def match(self, buf):
|
126
|
+
return (len(buf) > 2 and
|
127
|
+
buf[0] == 0x1F and
|
128
|
+
buf[1] == 0x8B and
|
129
|
+
buf[2] == 0x8)
|
130
|
+
|
131
|
+
|
132
|
+
class Bz2(Type):
|
133
|
+
"""
|
134
|
+
Implements the BZ2 archive type matcher.
|
135
|
+
"""
|
136
|
+
MIME = 'application/x-bzip2'
|
137
|
+
EXTENSION = 'bz2'
|
138
|
+
|
139
|
+
def __init__(self):
|
140
|
+
super(Bz2, self).__init__(
|
141
|
+
mime=Bz2.MIME,
|
142
|
+
extension=Bz2.EXTENSION
|
143
|
+
)
|
144
|
+
|
145
|
+
def match(self, buf):
|
146
|
+
return (len(buf) > 2 and
|
147
|
+
buf[0] == 0x42 and
|
148
|
+
buf[1] == 0x5A and
|
149
|
+
buf[2] == 0x68)
|
150
|
+
|
151
|
+
|
152
|
+
class SevenZ(Type):
|
153
|
+
"""
|
154
|
+
Implements the SevenZ (7z) archive type matcher.
|
155
|
+
"""
|
156
|
+
MIME = 'application/x-7z-compressed'
|
157
|
+
EXTENSION = '7z'
|
158
|
+
|
159
|
+
def __init__(self):
|
160
|
+
super(SevenZ, self).__init__(
|
161
|
+
mime=SevenZ.MIME,
|
162
|
+
extension=SevenZ.EXTENSION
|
163
|
+
)
|
164
|
+
|
165
|
+
def match(self, buf):
|
166
|
+
return (len(buf) > 5 and
|
167
|
+
buf[0] == 0x37 and
|
168
|
+
buf[1] == 0x7A and
|
169
|
+
buf[2] == 0xBC and
|
170
|
+
buf[3] == 0xAF and
|
171
|
+
buf[4] == 0x27 and
|
172
|
+
buf[5] == 0x1C)
|
173
|
+
|
174
|
+
|
175
|
+
class Pdf(Type):
|
176
|
+
"""
|
177
|
+
Implements the PDF archive type matcher.
|
178
|
+
"""
|
179
|
+
MIME = 'application/pdf'
|
180
|
+
EXTENSION = 'pdf'
|
181
|
+
|
182
|
+
def __init__(self):
|
183
|
+
super(Pdf, self).__init__(
|
184
|
+
mime=Pdf.MIME,
|
185
|
+
extension=Pdf.EXTENSION
|
186
|
+
)
|
187
|
+
|
188
|
+
def match(self, buf):
|
189
|
+
# Detect BOM and skip first 3 bytes
|
190
|
+
if (len(buf) > 3 and
|
191
|
+
buf[0] == 0xEF and
|
192
|
+
buf[1] == 0xBB and
|
193
|
+
buf[2] == 0xBF): # noqa E129
|
194
|
+
buf = buf[3:]
|
195
|
+
|
196
|
+
return (len(buf) > 3 and
|
197
|
+
buf[0] == 0x25 and
|
198
|
+
buf[1] == 0x50 and
|
199
|
+
buf[2] == 0x44 and
|
200
|
+
buf[3] == 0x46)
|
201
|
+
|
202
|
+
|
203
|
+
class Exe(Type):
|
204
|
+
"""
|
205
|
+
Implements the EXE archive type matcher.
|
206
|
+
"""
|
207
|
+
MIME = 'application/x-msdownload'
|
208
|
+
EXTENSION = 'exe'
|
209
|
+
|
210
|
+
def __init__(self):
|
211
|
+
super(Exe, self).__init__(
|
212
|
+
mime=Exe.MIME,
|
213
|
+
extension=Exe.EXTENSION
|
214
|
+
)
|
215
|
+
|
216
|
+
def match(self, buf):
|
217
|
+
return (len(buf) > 1 and
|
218
|
+
buf[0] == 0x4D and
|
219
|
+
buf[1] == 0x5A)
|
220
|
+
|
221
|
+
|
222
|
+
class Swf(Type):
|
223
|
+
"""
|
224
|
+
Implements the SWF archive type matcher.
|
225
|
+
"""
|
226
|
+
MIME = 'application/x-shockwave-flash'
|
227
|
+
EXTENSION = 'swf'
|
228
|
+
|
229
|
+
def __init__(self):
|
230
|
+
super(Swf, self).__init__(
|
231
|
+
mime=Swf.MIME,
|
232
|
+
extension=Swf.EXTENSION
|
233
|
+
)
|
234
|
+
|
235
|
+
def match(self, buf):
|
236
|
+
return (len(buf) > 2 and
|
237
|
+
(buf[0] == 0x43 or
|
238
|
+
buf[0] == 0x46) and
|
239
|
+
buf[1] == 0x57 and
|
240
|
+
buf[2] == 0x53)
|
241
|
+
|
242
|
+
|
243
|
+
class Rtf(Type):
|
244
|
+
"""
|
245
|
+
Implements the RTF archive type matcher.
|
246
|
+
"""
|
247
|
+
MIME = 'application/rtf'
|
248
|
+
EXTENSION = 'rtf'
|
249
|
+
|
250
|
+
def __init__(self):
|
251
|
+
super(Rtf, self).__init__(
|
252
|
+
mime=Rtf.MIME,
|
253
|
+
extension=Rtf.EXTENSION
|
254
|
+
)
|
255
|
+
|
256
|
+
def match(self, buf):
|
257
|
+
return (len(buf) > 4 and
|
258
|
+
buf[0] == 0x7B and
|
259
|
+
buf[1] == 0x5C and
|
260
|
+
buf[2] == 0x72 and
|
261
|
+
buf[3] == 0x74 and
|
262
|
+
buf[4] == 0x66)
|
263
|
+
|
264
|
+
|
265
|
+
class Nes(Type):
|
266
|
+
"""
|
267
|
+
Implements the NES archive type matcher.
|
268
|
+
"""
|
269
|
+
MIME = 'application/x-nintendo-nes-rom'
|
270
|
+
EXTENSION = 'nes'
|
271
|
+
|
272
|
+
def __init__(self):
|
273
|
+
super(Nes, self).__init__(
|
274
|
+
mime=Nes.MIME,
|
275
|
+
extension=Nes.EXTENSION
|
276
|
+
)
|
277
|
+
|
278
|
+
def match(self, buf):
|
279
|
+
return (len(buf) > 3 and
|
280
|
+
buf[0] == 0x4E and
|
281
|
+
buf[1] == 0x45 and
|
282
|
+
buf[2] == 0x53 and
|
283
|
+
buf[3] == 0x1A)
|
284
|
+
|
285
|
+
|
286
|
+
class Crx(Type):
|
287
|
+
"""
|
288
|
+
Implements the CRX archive type matcher.
|
289
|
+
"""
|
290
|
+
MIME = 'application/x-google-chrome-extension'
|
291
|
+
EXTENSION = 'crx'
|
292
|
+
|
293
|
+
def __init__(self):
|
294
|
+
super(Crx, self).__init__(
|
295
|
+
mime=Crx.MIME,
|
296
|
+
extension=Crx.EXTENSION
|
297
|
+
)
|
298
|
+
|
299
|
+
def match(self, buf):
|
300
|
+
return (len(buf) > 3 and
|
301
|
+
buf[0] == 0x43 and
|
302
|
+
buf[1] == 0x72 and
|
303
|
+
buf[2] == 0x32 and
|
304
|
+
buf[3] == 0x34)
|
305
|
+
|
306
|
+
|
307
|
+
class Cab(Type):
|
308
|
+
"""
|
309
|
+
Implements the CAB archive type matcher.
|
310
|
+
"""
|
311
|
+
MIME = 'application/vnd.ms-cab-compressed'
|
312
|
+
EXTENSION = 'cab'
|
313
|
+
|
314
|
+
def __init__(self):
|
315
|
+
super(Cab, self).__init__(
|
316
|
+
mime=Cab.MIME,
|
317
|
+
extension=Cab.EXTENSION
|
318
|
+
)
|
319
|
+
|
320
|
+
def match(self, buf):
|
321
|
+
return (len(buf) > 3 and
|
322
|
+
((buf[0] == 0x4D and
|
323
|
+
buf[1] == 0x53 and
|
324
|
+
buf[2] == 0x43 and
|
325
|
+
buf[3] == 0x46) or
|
326
|
+
(buf[0] == 0x49 and
|
327
|
+
buf[1] == 0x53 and
|
328
|
+
buf[2] == 0x63 and
|
329
|
+
buf[3] == 0x28)))
|
330
|
+
|
331
|
+
|
332
|
+
class Eot(Type):
|
333
|
+
"""
|
334
|
+
Implements the EOT archive type matcher.
|
335
|
+
"""
|
336
|
+
MIME = 'application/octet-stream'
|
337
|
+
EXTENSION = 'eot'
|
338
|
+
|
339
|
+
def __init__(self):
|
340
|
+
super(Eot, self).__init__(
|
341
|
+
mime=Eot.MIME,
|
342
|
+
extension=Eot.EXTENSION
|
343
|
+
)
|
344
|
+
|
345
|
+
def match(self, buf):
|
346
|
+
return (len(buf) > 35 and
|
347
|
+
buf[34] == 0x4C and
|
348
|
+
buf[35] == 0x50 and
|
349
|
+
((buf[8] == 0x02 and
|
350
|
+
buf[9] == 0x00 and
|
351
|
+
buf[10] == 0x01) or
|
352
|
+
(buf[8] == 0x01 and
|
353
|
+
buf[9] == 0x00 and
|
354
|
+
buf[10] == 0x00) or
|
355
|
+
(buf[8] == 0x02 and
|
356
|
+
buf[9] == 0x00 and
|
357
|
+
buf[10] == 0x02)))
|
358
|
+
|
359
|
+
|
360
|
+
class Ps(Type):
|
361
|
+
"""
|
362
|
+
Implements the PS archive type matcher.
|
363
|
+
"""
|
364
|
+
MIME = 'application/postscript'
|
365
|
+
EXTENSION = 'ps'
|
366
|
+
|
367
|
+
def __init__(self):
|
368
|
+
super(Ps, self).__init__(
|
369
|
+
mime=Ps.MIME,
|
370
|
+
extension=Ps.EXTENSION
|
371
|
+
)
|
372
|
+
|
373
|
+
def match(self, buf):
|
374
|
+
return (len(buf) > 1 and
|
375
|
+
buf[0] == 0x25 and
|
376
|
+
buf[1] == 0x21)
|
377
|
+
|
378
|
+
|
379
|
+
class Xz(Type):
|
380
|
+
"""
|
381
|
+
Implements the XS archive type matcher.
|
382
|
+
"""
|
383
|
+
MIME = 'application/x-xz'
|
384
|
+
EXTENSION = 'xz'
|
385
|
+
|
386
|
+
def __init__(self):
|
387
|
+
super(Xz, self).__init__(
|
388
|
+
mime=Xz.MIME,
|
389
|
+
extension=Xz.EXTENSION
|
390
|
+
)
|
391
|
+
|
392
|
+
def match(self, buf):
|
393
|
+
return (len(buf) > 5 and
|
394
|
+
buf[0] == 0xFD and
|
395
|
+
buf[1] == 0x37 and
|
396
|
+
buf[2] == 0x7A and
|
397
|
+
buf[3] == 0x58 and
|
398
|
+
buf[4] == 0x5A and
|
399
|
+
buf[5] == 0x00)
|
400
|
+
|
401
|
+
|
402
|
+
class Sqlite(Type):
|
403
|
+
"""
|
404
|
+
Implements the Sqlite DB archive type matcher.
|
405
|
+
"""
|
406
|
+
MIME = 'application/x-sqlite3'
|
407
|
+
EXTENSION = 'sqlite'
|
408
|
+
|
409
|
+
def __init__(self):
|
410
|
+
super(Sqlite, self).__init__(
|
411
|
+
mime=Sqlite.MIME,
|
412
|
+
extension=Sqlite.EXTENSION
|
413
|
+
)
|
414
|
+
|
415
|
+
def match(self, buf):
|
416
|
+
return (len(buf) > 3 and
|
417
|
+
buf[0] == 0x53 and
|
418
|
+
buf[1] == 0x51 and
|
419
|
+
buf[2] == 0x4C and
|
420
|
+
buf[3] == 0x69)
|
421
|
+
|
422
|
+
|
423
|
+
class Deb(Type):
|
424
|
+
"""
|
425
|
+
Implements the DEB archive type matcher.
|
426
|
+
"""
|
427
|
+
MIME = 'application/x-deb'
|
428
|
+
EXTENSION = 'deb'
|
429
|
+
|
430
|
+
def __init__(self):
|
431
|
+
super(Deb, self).__init__(
|
432
|
+
mime=Deb.MIME,
|
433
|
+
extension=Deb.EXTENSION
|
434
|
+
)
|
435
|
+
|
436
|
+
def match(self, buf):
|
437
|
+
return (len(buf) > 20 and
|
438
|
+
buf[0] == 0x21 and
|
439
|
+
buf[1] == 0x3C and
|
440
|
+
buf[2] == 0x61 and
|
441
|
+
buf[3] == 0x72 and
|
442
|
+
buf[4] == 0x63 and
|
443
|
+
buf[5] == 0x68 and
|
444
|
+
buf[6] == 0x3E and
|
445
|
+
buf[7] == 0x0A and
|
446
|
+
buf[8] == 0x64 and
|
447
|
+
buf[9] == 0x65 and
|
448
|
+
buf[10] == 0x62 and
|
449
|
+
buf[11] == 0x69 and
|
450
|
+
buf[12] == 0x61 and
|
451
|
+
buf[13] == 0x6E and
|
452
|
+
buf[14] == 0x2D and
|
453
|
+
buf[15] == 0x62 and
|
454
|
+
buf[16] == 0x69 and
|
455
|
+
buf[17] == 0x6E and
|
456
|
+
buf[18] == 0x61 and
|
457
|
+
buf[19] == 0x72 and
|
458
|
+
buf[20] == 0x79)
|
459
|
+
|
460
|
+
|
461
|
+
class Ar(Type):
|
462
|
+
"""
|
463
|
+
Implements the AR archive type matcher.
|
464
|
+
"""
|
465
|
+
MIME = 'application/x-unix-archive'
|
466
|
+
EXTENSION = 'ar'
|
467
|
+
|
468
|
+
def __init__(self):
|
469
|
+
super(Ar, self).__init__(
|
470
|
+
mime=Ar.MIME,
|
471
|
+
extension=Ar.EXTENSION
|
472
|
+
)
|
473
|
+
|
474
|
+
def match(self, buf):
|
475
|
+
return (len(buf) > 6 and
|
476
|
+
buf[0] == 0x21 and
|
477
|
+
buf[1] == 0x3C and
|
478
|
+
buf[2] == 0x61 and
|
479
|
+
buf[3] == 0x72 and
|
480
|
+
buf[4] == 0x63 and
|
481
|
+
buf[5] == 0x68 and
|
482
|
+
buf[6] == 0x3E)
|
483
|
+
|
484
|
+
|
485
|
+
class Z(Type):
|
486
|
+
"""
|
487
|
+
Implements the Z archive type matcher.
|
488
|
+
"""
|
489
|
+
MIME = 'application/x-compress'
|
490
|
+
EXTENSION = 'Z'
|
491
|
+
|
492
|
+
def __init__(self):
|
493
|
+
super(Z, self).__init__(
|
494
|
+
mime=Z.MIME,
|
495
|
+
extension=Z.EXTENSION
|
496
|
+
)
|
497
|
+
|
498
|
+
def match(self, buf):
|
499
|
+
return (len(buf) > 1 and
|
500
|
+
((buf[0] == 0x1F and
|
501
|
+
buf[1] == 0xA0) or
|
502
|
+
(buf[0] == 0x1F and
|
503
|
+
buf[1] == 0x9D)))
|
504
|
+
|
505
|
+
|
506
|
+
class Lzop(Type):
|
507
|
+
"""
|
508
|
+
Implements the Lzop archive type matcher.
|
509
|
+
"""
|
510
|
+
MIME = 'application/x-lzop'
|
511
|
+
EXTENSION = 'lzo'
|
512
|
+
|
513
|
+
def __init__(self):
|
514
|
+
super(Lzop, self).__init__(
|
515
|
+
mime=Lzop.MIME,
|
516
|
+
extension=Lzop.EXTENSION
|
517
|
+
)
|
518
|
+
|
519
|
+
def match(self, buf):
|
520
|
+
return (len(buf) > 7 and
|
521
|
+
buf[0] == 0x89 and
|
522
|
+
buf[1] == 0x4C and
|
523
|
+
buf[2] == 0x5A and
|
524
|
+
buf[3] == 0x4F and
|
525
|
+
buf[4] == 0x00 and
|
526
|
+
buf[5] == 0x0D and
|
527
|
+
buf[6] == 0x0A and
|
528
|
+
buf[7] == 0x1A)
|
529
|
+
|
530
|
+
|
531
|
+
class Lz(Type):
|
532
|
+
"""
|
533
|
+
Implements the Lz archive type matcher.
|
534
|
+
"""
|
535
|
+
MIME = 'application/x-lzip'
|
536
|
+
EXTENSION = 'lz'
|
537
|
+
|
538
|
+
def __init__(self):
|
539
|
+
super(Lz, self).__init__(
|
540
|
+
mime=Lz.MIME,
|
541
|
+
extension=Lz.EXTENSION
|
542
|
+
)
|
543
|
+
|
544
|
+
def match(self, buf):
|
545
|
+
return (len(buf) > 3 and
|
546
|
+
buf[0] == 0x4C and
|
547
|
+
buf[1] == 0x5A and
|
548
|
+
buf[2] == 0x49 and
|
549
|
+
buf[3] == 0x50)
|
550
|
+
|
551
|
+
|
552
|
+
class Elf(Type):
|
553
|
+
"""
|
554
|
+
Implements the Elf archive type matcher
|
555
|
+
"""
|
556
|
+
MIME = 'application/x-executable'
|
557
|
+
EXTENSION = 'elf'
|
558
|
+
|
559
|
+
def __init__(self):
|
560
|
+
super(Elf, self).__init__(
|
561
|
+
mime=Elf.MIME,
|
562
|
+
extension=Elf.EXTENSION
|
563
|
+
)
|
564
|
+
|
565
|
+
def match(self, buf):
|
566
|
+
return (len(buf) > 52 and
|
567
|
+
buf[0] == 0x7F and
|
568
|
+
buf[1] == 0x45 and
|
569
|
+
buf[2] == 0x4C and
|
570
|
+
buf[3] == 0x46)
|
571
|
+
|
572
|
+
|
573
|
+
class Lz4(Type):
|
574
|
+
"""
|
575
|
+
Implements the Lz4 archive type matcher.
|
576
|
+
"""
|
577
|
+
MIME = 'application/x-lz4'
|
578
|
+
EXTENSION = 'lz4'
|
579
|
+
|
580
|
+
def __init__(self):
|
581
|
+
super(Lz4, self).__init__(
|
582
|
+
mime=Lz4.MIME,
|
583
|
+
extension=Lz4.EXTENSION
|
584
|
+
)
|
585
|
+
|
586
|
+
def match(self, buf):
|
587
|
+
return (len(buf) > 3 and
|
588
|
+
buf[0] == 0x04 and
|
589
|
+
buf[1] == 0x22 and
|
590
|
+
buf[2] == 0x4D and
|
591
|
+
buf[3] == 0x18)
|
592
|
+
|
593
|
+
|
594
|
+
class Br(Type):
|
595
|
+
"""Implements the Br image type matcher."""
|
596
|
+
|
597
|
+
MIME = 'application/x-brotli'
|
598
|
+
EXTENSION = 'br'
|
599
|
+
|
600
|
+
def __init__(self):
|
601
|
+
super(Br, self).__init__(
|
602
|
+
mime=Br.MIME,
|
603
|
+
extension=Br.EXTENSION
|
604
|
+
)
|
605
|
+
|
606
|
+
def match(self, buf):
|
607
|
+
return buf[:4] == bytearray([0xce, 0xb2, 0xcf, 0x81])
|
608
|
+
|
609
|
+
|
610
|
+
class Dcm(Type):
|
611
|
+
"""Implements the Dcm image type matcher."""
|
612
|
+
|
613
|
+
MIME = 'application/dicom'
|
614
|
+
EXTENSION = 'dcm'
|
615
|
+
|
616
|
+
def __init__(self):
|
617
|
+
super(Dcm, self).__init__(
|
618
|
+
mime=Dcm.MIME,
|
619
|
+
extension=Dcm.EXTENSION
|
620
|
+
)
|
621
|
+
|
622
|
+
def match(self, buf):
|
623
|
+
return buf[128:131] == bytearray([0x44, 0x49, 0x43, 0x4d])
|
624
|
+
|
625
|
+
|
626
|
+
class Rpm(Type):
|
627
|
+
"""Implements the Rpm image type matcher."""
|
628
|
+
|
629
|
+
MIME = 'application/x-rpm'
|
630
|
+
EXTENSION = 'rpm'
|
631
|
+
|
632
|
+
def __init__(self):
|
633
|
+
super(Rpm, self).__init__(
|
634
|
+
mime=Rpm.MIME,
|
635
|
+
extension=Rpm.EXTENSION
|
636
|
+
)
|
637
|
+
|
638
|
+
def match(self, buf):
|
639
|
+
return buf[:4] == bytearray([0xed, 0xab, 0xee, 0xdb])
|
640
|
+
|
641
|
+
|
642
|
+
class Zstd(Type):
|
643
|
+
"""
|
644
|
+
Implements the Zstd archive type matcher.
|
645
|
+
https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md
|
646
|
+
"""
|
647
|
+
MIME = 'application/zstd'
|
648
|
+
EXTENSION = 'zst'
|
649
|
+
MAGIC_SKIPPABLE_START = 0x184D2A50
|
650
|
+
MAGIC_SKIPPABLE_MASK = 0xFFFFFFF0
|
651
|
+
|
652
|
+
def __init__(self):
|
653
|
+
super(Zstd, self).__init__(
|
654
|
+
mime=Zstd.MIME,
|
655
|
+
extension=Zstd.EXTENSION
|
656
|
+
)
|
657
|
+
|
658
|
+
@staticmethod
|
659
|
+
def _to_little_endian_int(buf):
|
660
|
+
# return int.from_bytes(buf, byteorder='little')
|
661
|
+
return struct.unpack('<L', buf)[0]
|
662
|
+
|
663
|
+
def match(self, buf):
|
664
|
+
# Zstandard compressed data is made of one or more frames.
|
665
|
+
# There are two frame formats defined by Zstandard:
|
666
|
+
# Zstandard frames and Skippable frames.
|
667
|
+
# See more details from
|
668
|
+
# https://tools.ietf.org/id/draft-kucherawy-dispatch-zstd-00.html#rfc.section.2
|
669
|
+
is_zstd = (
|
670
|
+
len(buf) > 3 and
|
671
|
+
buf[0] in (0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28) and
|
672
|
+
buf[1] == 0xb5 and
|
673
|
+
buf[2] == 0x2f and
|
674
|
+
buf[3] == 0xfd)
|
675
|
+
if is_zstd:
|
676
|
+
return True
|
677
|
+
# skippable frames
|
678
|
+
if len(buf) < 8:
|
679
|
+
return False
|
680
|
+
magic = self._to_little_endian_int(buf[:4]) & Zstd.MAGIC_SKIPPABLE_MASK
|
681
|
+
if magic == Zstd.MAGIC_SKIPPABLE_START:
|
682
|
+
user_data_len = self._to_little_endian_int(buf[4:8])
|
683
|
+
if len(buf) < 8 + user_data_len:
|
684
|
+
return False
|
685
|
+
next_frame = buf[8 + user_data_len:]
|
686
|
+
return self.match(next_frame)
|
687
|
+
return False
|