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.
Files changed (64) hide show
  1. {MeUtils-2025.3.3.18.41.24.dist-info → MeUtils-2025.3.5.19.55.22.dist-info}/METADATA +264 -264
  2. {MeUtils-2025.3.3.18.41.24.dist-info → MeUtils-2025.3.5.19.55.22.dist-info}/RECORD +61 -33
  3. examples/_openaisdk/open_router.py +2 -1
  4. examples/_openaisdk/openai_files.py +16 -5
  5. examples/_openaisdk/openai_images.py +1 -0
  6. examples/_openaisdk/openai_moon.py +22 -19
  7. examples/sh/__init__.py +11 -0
  8. meutils/apis/baidu/bdaitpzs.py +9 -17
  9. meutils/apis/chatglm/glm_video_api.py +2 -2
  10. meutils/apis/images/edits.py +7 -2
  11. meutils/apis/jimeng/common.py +1 -1
  12. meutils/apis/oneapi/common.py +4 -4
  13. meutils/apis/proxy/ips.py +2 -0
  14. meutils/caches/common.py +4 -0
  15. meutils/data/VERSION +1 -1
  16. meutils/data/oneapi/NOTICE.html +12 -0
  17. meutils/data/oneapi/__init__.py +1 -1
  18. meutils/data/oneapi/index.html +275 -0
  19. meutils/io/_openai_files.py +31 -0
  20. meutils/io/openai_files.py +138 -0
  21. meutils/io/parsers/__init__.py +10 -0
  22. meutils/io/parsers/fileparser/PDF/346/212/275/345/217/226.py +58 -0
  23. meutils/io/parsers/fileparser/__init__.py +11 -0
  24. meutils/io/parsers/fileparser/common.py +91 -0
  25. meutils/io/parsers/fileparser/demo.py +41 -0
  26. meutils/io/parsers/fileparser/filetype/__init__.py +10 -0
  27. meutils/io/parsers/fileparser/filetype/__main__.py +37 -0
  28. meutils/io/parsers/fileparser/filetype/filetype.py +98 -0
  29. meutils/io/parsers/fileparser/filetype/helpers.py +140 -0
  30. meutils/io/parsers/fileparser/filetype/match.py +155 -0
  31. meutils/io/parsers/fileparser/filetype/types/__init__.py +118 -0
  32. meutils/io/parsers/fileparser/filetype/types/application.py +22 -0
  33. meutils/io/parsers/fileparser/filetype/types/archive.py +687 -0
  34. meutils/io/parsers/fileparser/filetype/types/audio.py +212 -0
  35. meutils/io/parsers/fileparser/filetype/types/base.py +29 -0
  36. meutils/io/parsers/fileparser/filetype/types/document.py +256 -0
  37. meutils/io/parsers/fileparser/filetype/types/font.py +115 -0
  38. meutils/io/parsers/fileparser/filetype/types/image.py +383 -0
  39. meutils/io/parsers/fileparser/filetype/types/isobmff.py +33 -0
  40. meutils/io/parsers/fileparser/filetype/types/video.py +223 -0
  41. meutils/io/parsers/fileparser/filetype/utils.py +84 -0
  42. meutils/io/parsers/fileparser/filetype.py +41 -0
  43. meutils/io/parsers/fileparser/mineru.py +48 -0
  44. meutils/io/parsers/fileparser/pdf.py +30 -0
  45. meutils/io/parsers/fileparser//350/241/250/346/240/274/346/212/275/345/217/226.py +118 -0
  46. meutils/llm/check_utils.py +33 -2
  47. meutils/llm/clients.py +1 -0
  48. meutils/llm/completions/chat_gemini.py +72 -0
  49. meutils/llm/completions/chat_plus.py +78 -0
  50. meutils/llm/completions/{agents/file.py → chat_spark.py} +46 -26
  51. meutils/llm/completions/qwenllm.py +57 -16
  52. meutils/llm/completions/yuanbao.py +29 -3
  53. meutils/llm/openai_utils/common.py +2 -2
  54. meutils/schemas/oneapi/common.py +22 -19
  55. meutils/schemas/openai_types.py +65 -29
  56. meutils/schemas/yuanbao_types.py +6 -7
  57. meutils/types.py +2 -0
  58. meutils/data/oneapi/NOTICE.md +0 -1
  59. meutils/data/oneapi/_NOTICE.md +0 -140
  60. meutils/llm/completions/gemini.py +0 -69
  61. {MeUtils-2025.3.3.18.41.24.dist-info → MeUtils-2025.3.5.19.55.22.dist-info}/LICENSE +0 -0
  62. {MeUtils-2025.3.3.18.41.24.dist-info → MeUtils-2025.3.5.19.55.22.dist-info}/WHEEL +0 -0
  63. {MeUtils-2025.3.3.18.41.24.dist-info → MeUtils-2025.3.5.19.55.22.dist-info}/entry_points.txt +0 -0
  64. {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,212 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from __future__ import absolute_import
4
+
5
+ from .base import Type
6
+
7
+
8
+ class Midi(Type):
9
+ """
10
+ Implements the Midi audio type matcher.
11
+ """
12
+ MIME = 'audio/midi'
13
+ EXTENSION = 'midi'
14
+
15
+ def __init__(self):
16
+ super(Midi, self).__init__(
17
+ mime=Midi.MIME,
18
+ extension=Midi.EXTENSION
19
+ )
20
+
21
+ def match(self, buf):
22
+ return (len(buf) > 3 and
23
+ buf[0] == 0x4D and
24
+ buf[1] == 0x54 and
25
+ buf[2] == 0x68 and
26
+ buf[3] == 0x64)
27
+
28
+
29
+ class Mp3(Type):
30
+ """
31
+ Implements the MP3 audio type matcher.
32
+ """
33
+ MIME = 'audio/mpeg'
34
+ EXTENSION = 'mp3'
35
+
36
+ def __init__(self):
37
+ super(Mp3, self).__init__(
38
+ mime=Mp3.MIME,
39
+ extension=Mp3.EXTENSION
40
+ )
41
+
42
+ def match(self, buf):
43
+ return (len(buf) > 2 and
44
+ ((buf[0] == 0x49 and
45
+ buf[1] == 0x44 and
46
+ buf[2] == 0x33) or
47
+ (buf[0] == 0xFF and
48
+ buf[1] == 0xF2) or
49
+ (buf[0] == 0xFF and
50
+ buf[1] == 0xF3) or
51
+ (buf[0] == 0xFF and
52
+ buf[1] == 0xFB)))
53
+
54
+
55
+ class M4a(Type):
56
+ """
57
+ Implements the M4A audio type matcher.
58
+ """
59
+ MIME = 'audio/mp4'
60
+ EXTENSION = 'm4a'
61
+
62
+ def __init__(self):
63
+ super(M4a, self).__init__(
64
+ mime=M4a.MIME,
65
+ extension=M4a.EXTENSION
66
+ )
67
+
68
+ def match(self, buf):
69
+ return (len(buf) > 10 and
70
+ ((buf[4] == 0x66 and
71
+ buf[5] == 0x74 and
72
+ buf[6] == 0x79 and
73
+ buf[7] == 0x70 and
74
+ buf[8] == 0x4D and
75
+ buf[9] == 0x34 and
76
+ buf[10] == 0x41) or
77
+ (buf[0] == 0x4D and
78
+ buf[1] == 0x34 and
79
+ buf[2] == 0x41 and
80
+ buf[3] == 0x20)))
81
+
82
+
83
+ class Ogg(Type):
84
+ """
85
+ Implements the OGG audio type matcher.
86
+ """
87
+ MIME = 'audio/ogg'
88
+ EXTENSION = 'ogg'
89
+
90
+ def __init__(self):
91
+ super(Ogg, self).__init__(
92
+ mime=Ogg.MIME,
93
+ extension=Ogg.EXTENSION
94
+ )
95
+
96
+ def match(self, buf):
97
+ return (len(buf) > 3 and
98
+ buf[0] == 0x4F and
99
+ buf[1] == 0x67 and
100
+ buf[2] == 0x67 and
101
+ buf[3] == 0x53)
102
+
103
+
104
+ class Flac(Type):
105
+ """
106
+ Implements the FLAC audio type matcher.
107
+ """
108
+ MIME = 'audio/x-flac'
109
+ EXTENSION = 'flac'
110
+
111
+ def __init__(self):
112
+ super(Flac, self).__init__(
113
+ mime=Flac.MIME,
114
+ extension=Flac.EXTENSION
115
+ )
116
+
117
+ def match(self, buf):
118
+ return (len(buf) > 3 and
119
+ buf[0] == 0x66 and
120
+ buf[1] == 0x4C and
121
+ buf[2] == 0x61 and
122
+ buf[3] == 0x43)
123
+
124
+
125
+ class Wav(Type):
126
+ """
127
+ Implements the WAV audio type matcher.
128
+ """
129
+ MIME = 'audio/x-wav'
130
+ EXTENSION = 'wav'
131
+
132
+ def __init__(self):
133
+ super(Wav, self).__init__(
134
+ mime=Wav.MIME,
135
+ extension=Wav.EXTENSION
136
+ )
137
+
138
+ def match(self, buf):
139
+ return (len(buf) > 11 and
140
+ buf[0] == 0x52 and
141
+ buf[1] == 0x49 and
142
+ buf[2] == 0x46 and
143
+ buf[3] == 0x46 and
144
+ buf[8] == 0x57 and
145
+ buf[9] == 0x41 and
146
+ buf[10] == 0x56 and
147
+ buf[11] == 0x45)
148
+
149
+
150
+ class Amr(Type):
151
+ """
152
+ Implements the AMR audio type matcher.
153
+ """
154
+ MIME = 'audio/amr'
155
+ EXTENSION = 'amr'
156
+
157
+ def __init__(self):
158
+ super(Amr, self).__init__(
159
+ mime=Amr.MIME,
160
+ extension=Amr.EXTENSION
161
+ )
162
+
163
+ def match(self, buf):
164
+ return (len(buf) > 11 and
165
+ buf[0] == 0x23 and
166
+ buf[1] == 0x21 and
167
+ buf[2] == 0x41 and
168
+ buf[3] == 0x4D and
169
+ buf[4] == 0x52 and
170
+ buf[5] == 0x0A)
171
+
172
+
173
+ class Aac(Type):
174
+ """Implements the Aac audio type matcher."""
175
+
176
+ MIME = 'audio/aac'
177
+ EXTENSION = 'aac'
178
+
179
+ def __init__(self):
180
+ super(Aac, self).__init__(
181
+ mime=Aac.MIME,
182
+ extension=Aac.EXTENSION
183
+ )
184
+
185
+ def match(self, buf):
186
+ return (buf[:2] == bytearray([0xff, 0xf1]) or
187
+ buf[:2] == bytearray([0xff, 0xf9]))
188
+
189
+
190
+ class Aiff(Type):
191
+ """
192
+ Implements the AIFF audio type matcher.
193
+ """
194
+ MIME = 'audio/x-aiff'
195
+ EXTENSION = 'aiff'
196
+
197
+ def __init__(self):
198
+ super(Aiff, self).__init__(
199
+ mime=Aiff.MIME,
200
+ extension=Aiff.EXTENSION
201
+ )
202
+
203
+ def match(self, buf):
204
+ return (len(buf) > 11 and
205
+ buf[0] == 0x46 and
206
+ buf[1] == 0x4F and
207
+ buf[2] == 0x52 and
208
+ buf[3] == 0x4D and
209
+ buf[8] == 0x41 and
210
+ buf[9] == 0x49 and
211
+ buf[10] == 0x46 and
212
+ buf[11] == 0x46)
@@ -0,0 +1,29 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+
4
+ class Type(object):
5
+ """
6
+ Represents the file type object inherited by
7
+ specific file type matchers.
8
+ Provides convenient accessor and helper methods.
9
+ """
10
+ def __init__(self, mime, extension):
11
+ self.__mime = mime
12
+ self.__extension = extension
13
+
14
+ @property
15
+ def mime(self):
16
+ return self.__mime
17
+
18
+ @property
19
+ def extension(self):
20
+ return self.__extension
21
+
22
+ def is_extension(self, extension):
23
+ return self.__extension is extension
24
+
25
+ def is_mime(self, mime):
26
+ return self.__mime is mime
27
+
28
+ def match(self, buf):
29
+ raise NotImplementedError
@@ -0,0 +1,256 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from __future__ import absolute_import
4
+
5
+ from .base import Type
6
+
7
+
8
+ class ZippedDocumentBase(Type):
9
+ def match(self, buf):
10
+ # start by checking for ZIP local file header signature
11
+ idx = self.search_signature(buf, 0, 6000)
12
+ if idx != 0:
13
+ return
14
+
15
+ return self.match_document(buf)
16
+
17
+ def match_document(self, buf):
18
+ raise NotImplementedError
19
+
20
+ def compare_bytes(self, buf, subslice, start_offset):
21
+ sl = len(subslice)
22
+
23
+ if start_offset + sl > len(buf):
24
+ return False
25
+
26
+ return buf[start_offset:start_offset + sl] == subslice
27
+
28
+ def search_signature(self, buf, start, rangeNum):
29
+ signature = b"PK\x03\x04"
30
+ length = len(buf)
31
+
32
+ end = start + rangeNum
33
+ end = length if end > length else end
34
+
35
+ if start >= end:
36
+ return -1
37
+
38
+ try:
39
+ return buf.index(signature, start, end)
40
+ except ValueError:
41
+ return -1
42
+
43
+
44
+ class OpenDocument(ZippedDocumentBase):
45
+ def match_document(self, buf):
46
+ # Check if first file in archive is the identifying file
47
+ if not self.compare_bytes(buf, b"mimetype", 0x1E):
48
+ return
49
+
50
+ # Check content of mimetype file if it matches current mime
51
+ return self.compare_bytes(buf, bytes(self.mime, "ASCII"), 0x26)
52
+
53
+
54
+ class OfficeOpenXml(ZippedDocumentBase):
55
+ def match_document(self, buf):
56
+ # Check if first file in archive is the identifying file
57
+ ft = self.match_filename(buf, 0x1E)
58
+ if ft:
59
+ return ft
60
+
61
+ # Otherwise check that the fist file is one of these
62
+ if (
63
+ not self.compare_bytes(buf, b"[Content_Types].xml", 0x1E)
64
+ and not self.compare_bytes(buf, b"_rels/.rels", 0x1E)
65
+ and not self.compare_bytes(buf, b"docProps", 0x1E)
66
+ ):
67
+ return
68
+
69
+ # Loop through next 3 files and check if they match
70
+ # NOTE: OpenOffice/Libreoffice orders ZIP entry differently, so check the 4th file
71
+ # https://github.com/h2non/filetype/blob/d730d98ad5c990883148485b6fd5adbdd378364a/matchers/document.go#L134
72
+ idx = 0
73
+ for i in range(4):
74
+ # Search for next file header
75
+ idx = self.search_signature(buf, idx + 4, 6000)
76
+ if idx == -1:
77
+ return
78
+
79
+ # Filename is at file header + 30
80
+ ft = self.match_filename(buf, idx + 30)
81
+ if ft:
82
+ return ft
83
+
84
+ def match_filename(self, buf, offset):
85
+ if self.compare_bytes(buf, b"word/", offset):
86
+ return (
87
+ self.mime
88
+ == "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
89
+ )
90
+ if self.compare_bytes(buf, b"ppt/", offset):
91
+ return (
92
+ self.mime
93
+ == "application/vnd.openxmlformats-officedocument.presentationml.presentation"
94
+ )
95
+ if self.compare_bytes(buf, b"xl/", offset):
96
+ return (
97
+ self.mime
98
+ == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
99
+ )
100
+
101
+
102
+ class Doc(Type):
103
+ """
104
+ Implements the Microsoft Word (Office 97-2003) document type matcher.
105
+ """
106
+
107
+ MIME = "application/msword"
108
+ EXTENSION = "doc"
109
+
110
+ def __init__(self):
111
+ super(Doc, self).__init__(mime=Doc.MIME, extension=Doc.EXTENSION)
112
+
113
+ def match(self, buf):
114
+ if len(buf) > 515 and buf[0:8] == b"\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1":
115
+ if buf[512:516] == b"\xEC\xA5\xC1\x00":
116
+ return True
117
+ if (
118
+ len(buf) > 2142
119
+ and b"\x00\x0A\x00\x00\x00MSWordDoc\x00\x10\x00\x00\x00Word.Document.8\x00\xF49\xB2q"
120
+ in buf[2075:2142]
121
+ ):
122
+ return True
123
+
124
+ return False
125
+
126
+
127
+ class Docx(OfficeOpenXml):
128
+ """
129
+ Implements the Microsoft Word OOXML (Office 2007+) document type matcher.
130
+ """
131
+
132
+ MIME = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
133
+ EXTENSION = "docx"
134
+
135
+ def __init__(self):
136
+ super(Docx, self).__init__(mime=Docx.MIME, extension=Docx.EXTENSION)
137
+
138
+
139
+ class Odt(OpenDocument):
140
+ """
141
+ Implements the OpenDocument Text document type matcher.
142
+ """
143
+
144
+ MIME = "application/vnd.oasis.opendocument.text"
145
+ EXTENSION = "odt"
146
+
147
+ def __init__(self):
148
+ super(Odt, self).__init__(mime=Odt.MIME, extension=Odt.EXTENSION)
149
+
150
+
151
+ class Xls(Type):
152
+ """
153
+ Implements the Microsoft Excel (Office 97-2003) document type matcher.
154
+ """
155
+
156
+ MIME = "application/vnd.ms-excel"
157
+ EXTENSION = "xls"
158
+
159
+ def __init__(self):
160
+ super(Xls, self).__init__(mime=Xls.MIME, extension=Xls.EXTENSION)
161
+
162
+ def match(self, buf):
163
+ if len(buf) > 520 and buf[0:8] == b"\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1":
164
+ if buf[512:516] == b"\xFD\xFF\xFF\xFF" and (
165
+ buf[518] == 0x00 or buf[518] == 0x02
166
+ ):
167
+ return True
168
+ if buf[512:520] == b"\x09\x08\x10\x00\x00\x06\x05\x00":
169
+ return True
170
+ if (
171
+ len(buf) > 2095
172
+ and b"\xE2\x00\x00\x00\x5C\x00\x70\x00\x04\x00\x00Calc"
173
+ in buf[1568:2095]
174
+ ):
175
+ return True
176
+
177
+ return False
178
+
179
+
180
+ class Xlsx(OfficeOpenXml):
181
+ """
182
+ Implements the Microsoft Excel OOXML (Office 2007+) document type matcher.
183
+ """
184
+
185
+ MIME = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
186
+ EXTENSION = "xlsx"
187
+
188
+ def __init__(self):
189
+ super(Xlsx, self).__init__(mime=Xlsx.MIME, extension=Xlsx.EXTENSION)
190
+
191
+
192
+ class Ods(OpenDocument):
193
+ """
194
+ Implements the OpenDocument Spreadsheet document type matcher.
195
+ """
196
+
197
+ MIME = "application/vnd.oasis.opendocument.spreadsheet"
198
+ EXTENSION = "ods"
199
+
200
+ def __init__(self):
201
+ super(Ods, self).__init__(mime=Ods.MIME, extension=Ods.EXTENSION)
202
+
203
+
204
+ class Ppt(Type):
205
+ """
206
+ Implements the Microsoft PowerPoint (Office 97-2003) document type matcher.
207
+ """
208
+
209
+ MIME = "application/vnd.ms-powerpoint"
210
+ EXTENSION = "ppt"
211
+
212
+ def __init__(self):
213
+ super(Ppt, self).__init__(mime=Ppt.MIME, extension=Ppt.EXTENSION)
214
+
215
+ def match(self, buf):
216
+ if len(buf) > 524 and buf[0:8] == b"\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1":
217
+ if buf[512:516] == b"\xA0\x46\x1D\xF0":
218
+ return True
219
+ if buf[512:516] == b"\x00\x6E\x1E\xF0":
220
+ return True
221
+ if buf[512:516] == b"\x0F\x00\xE8\x03":
222
+ return True
223
+ if buf[512:516] == b"\xFD\xFF\xFF\xFF" and buf[522:524] == b"\x00\x00":
224
+ return True
225
+ if (
226
+ len(buf) > 2096
227
+ and buf[2072:2096]
228
+ == b"\x00\xB9\x29\xE8\x11\x00\x00\x00MS PowerPoint 97"
229
+ ):
230
+ return True
231
+
232
+ return False
233
+
234
+
235
+ class Pptx(OfficeOpenXml):
236
+ """
237
+ Implements the Microsoft PowerPoint OOXML (Office 2007+) document type matcher.
238
+ """
239
+
240
+ MIME = "application/vnd.openxmlformats-officedocument.presentationml.presentation"
241
+ EXTENSION = "pptx"
242
+
243
+ def __init__(self):
244
+ super(Pptx, self).__init__(mime=Pptx.MIME, extension=Pptx.EXTENSION)
245
+
246
+
247
+ class Odp(OpenDocument):
248
+ """
249
+ Implements the OpenDocument Presentation document type matcher.
250
+ """
251
+
252
+ MIME = "application/vnd.oasis.opendocument.presentation"
253
+ EXTENSION = "odp"
254
+
255
+ def __init__(self):
256
+ super(Odp, self).__init__(mime=Odp.MIME, extension=Odp.EXTENSION)
@@ -0,0 +1,115 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from __future__ import absolute_import
4
+
5
+ from .base import Type
6
+
7
+
8
+ class Woff(Type):
9
+ """
10
+ Implements the WOFF font type matcher.
11
+ """
12
+ MIME = 'application/font-woff'
13
+ EXTENSION = 'woff'
14
+
15
+ def __init__(self):
16
+ super(Woff, self).__init__(
17
+ mime=Woff.MIME,
18
+ extension=Woff.EXTENSION
19
+ )
20
+
21
+ def match(self, buf):
22
+ return (len(buf) > 7 and
23
+ buf[0] == 0x77 and
24
+ buf[1] == 0x4F and
25
+ buf[2] == 0x46 and
26
+ buf[3] == 0x46 and
27
+ ((buf[4] == 0x00 and
28
+ buf[5] == 0x01 and
29
+ buf[6] == 0x00 and
30
+ buf[7] == 0x00) or
31
+ (buf[4] == 0x4F and
32
+ buf[5] == 0x54 and
33
+ buf[6] == 0x54 and
34
+ buf[7] == 0x4F) or
35
+ (buf[4] == 0x74 and
36
+ buf[5] == 0x72 and
37
+ buf[6] == 0x75 and
38
+ buf[7] == 0x65)))
39
+
40
+
41
+ class Woff2(Type):
42
+ """
43
+ Implements the WOFF2 font type matcher.
44
+ """
45
+ MIME = 'application/font-woff'
46
+ EXTENSION = 'woff2'
47
+
48
+ def __init__(self):
49
+ super(Woff2, self).__init__(
50
+ mime=Woff2.MIME,
51
+ extension=Woff2.EXTENSION
52
+ )
53
+
54
+ def match(self, buf):
55
+ return (len(buf) > 7 and
56
+ buf[0] == 0x77 and
57
+ buf[1] == 0x4F and
58
+ buf[2] == 0x46 and
59
+ buf[3] == 0x32 and
60
+ ((buf[4] == 0x00 and
61
+ buf[5] == 0x01 and
62
+ buf[6] == 0x00 and
63
+ buf[7] == 0x00) or
64
+ (buf[4] == 0x4F and
65
+ buf[5] == 0x54 and
66
+ buf[6] == 0x54 and
67
+ buf[7] == 0x4F) or
68
+ (buf[4] == 0x74 and
69
+ buf[5] == 0x72 and
70
+ buf[6] == 0x75 and
71
+ buf[7] == 0x65)))
72
+
73
+
74
+ class Ttf(Type):
75
+ """
76
+ Implements the TTF font type matcher.
77
+ """
78
+ MIME = 'application/font-sfnt'
79
+ EXTENSION = 'ttf'
80
+
81
+ def __init__(self):
82
+ super(Ttf, self).__init__(
83
+ mime=Ttf.MIME,
84
+ extension=Ttf.EXTENSION
85
+ )
86
+
87
+ def match(self, buf):
88
+ return (len(buf) > 4 and
89
+ buf[0] == 0x00 and
90
+ buf[1] == 0x01 and
91
+ buf[2] == 0x00 and
92
+ buf[3] == 0x00 and
93
+ buf[4] == 0x00)
94
+
95
+
96
+ class Otf(Type):
97
+ """
98
+ Implements the OTF font type matcher.
99
+ """
100
+ MIME = 'application/font-sfnt'
101
+ EXTENSION = 'otf'
102
+
103
+ def __init__(self):
104
+ super(Otf, self).__init__(
105
+ mime=Otf.MIME,
106
+ extension=Otf.EXTENSION
107
+ )
108
+
109
+ def match(self, buf):
110
+ return (len(buf) > 4 and
111
+ buf[0] == 0x4F and
112
+ buf[1] == 0x54 and
113
+ buf[2] == 0x54 and
114
+ buf[3] == 0x4F and
115
+ buf[4] == 0x00)