Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/magic/compat.py: 74%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

139 statements  

1# coding: utf-8 

2 

3''' 

4Python bindings for libmagic 

5''' 

6 

7import ctypes 

8 

9from collections import namedtuple 

10 

11from ctypes import * 

12from ctypes.util import find_library 

13 

14 

15from . import loader 

16 

17_libraries = {} 

18_libraries['magic'] = loader.load_lib() 

19 

20# Flag constants for open and setflags 

21MAGIC_NONE = NONE = 0 

22MAGIC_DEBUG = DEBUG = 1 

23MAGIC_SYMLINK = SYMLINK = 2 

24MAGIC_COMPRESS = COMPRESS = 4 

25MAGIC_DEVICES = DEVICES = 8 

26MAGIC_MIME_TYPE = MIME_TYPE = 16 

27MAGIC_CONTINUE = CONTINUE = 32 

28MAGIC_CHECK = CHECK = 64 

29MAGIC_PRESERVE_ATIME = PRESERVE_ATIME = 128 

30MAGIC_RAW = RAW = 256 

31MAGIC_ERROR = ERROR = 512 

32MAGIC_MIME_ENCODING = MIME_ENCODING = 1024 

33MAGIC_MIME = MIME = 1040 # MIME_TYPE + MIME_ENCODING 

34MAGIC_APPLE = APPLE = 2048 

35 

36MAGIC_NO_CHECK_COMPRESS = NO_CHECK_COMPRESS = 4096 

37MAGIC_NO_CHECK_TAR = NO_CHECK_TAR = 8192 

38MAGIC_NO_CHECK_SOFT = NO_CHECK_SOFT = 16384 

39MAGIC_NO_CHECK_APPTYPE = NO_CHECK_APPTYPE = 32768 

40MAGIC_NO_CHECK_ELF = NO_CHECK_ELF = 65536 

41MAGIC_NO_CHECK_TEXT = NO_CHECK_TEXT = 131072 

42MAGIC_NO_CHECK_CDF = NO_CHECK_CDF = 262144 

43MAGIC_NO_CHECK_TOKENS = NO_CHECK_TOKENS = 1048576 

44MAGIC_NO_CHECK_ENCODING = NO_CHECK_ENCODING = 2097152 

45 

46MAGIC_NO_CHECK_BUILTIN = NO_CHECK_BUILTIN = 4173824 

47 

48FileMagic = namedtuple('FileMagic', ('mime_type', 'encoding', 'name')) 

49 

50 

51class magic_set(Structure): 

52 pass 

53 

54 

55magic_set._fields_ = [] 

56magic_t = POINTER(magic_set) 

57 

58_open = _libraries['magic'].magic_open 

59_open.restype = magic_t 

60_open.argtypes = [c_int] 

61 

62_close = _libraries['magic'].magic_close 

63_close.restype = None 

64_close.argtypes = [magic_t] 

65 

66_file = _libraries['magic'].magic_file 

67_file.restype = c_char_p 

68_file.argtypes = [magic_t, c_char_p] 

69 

70_descriptor = _libraries['magic'].magic_descriptor 

71_descriptor.restype = c_char_p 

72_descriptor.argtypes = [magic_t, c_int] 

73 

74_buffer = _libraries['magic'].magic_buffer 

75_buffer.restype = c_char_p 

76_buffer.argtypes = [magic_t, c_void_p, c_size_t] 

77 

78_error = _libraries['magic'].magic_error 

79_error.restype = c_char_p 

80_error.argtypes = [magic_t] 

81 

82_setflags = _libraries['magic'].magic_setflags 

83_setflags.restype = c_int 

84_setflags.argtypes = [magic_t, c_int] 

85 

86_load = _libraries['magic'].magic_load 

87_load.restype = c_int 

88_load.argtypes = [magic_t, c_char_p] 

89 

90_compile = _libraries['magic'].magic_compile 

91_compile.restype = c_int 

92_compile.argtypes = [magic_t, c_char_p] 

93 

94_check = _libraries['magic'].magic_check 

95_check.restype = c_int 

96_check.argtypes = [magic_t, c_char_p] 

97 

98_list = _libraries['magic'].magic_list 

99_list.restype = c_int 

100_list.argtypes = [magic_t, c_char_p] 

101 

102_errno = _libraries['magic'].magic_errno 

103_errno.restype = c_int 

104_errno.argtypes = [magic_t] 

105 

106 

107class Magic(object): 

108 def __init__(self, ms): 

109 self._magic_t = ms 

110 

111 def close(self): 

112 """ 

113 Closes the magic database and deallocates any resources used. 

114 """ 

115 _close(self._magic_t) 

116 

117 @staticmethod 

118 def __tostr(s): 

119 if s is None: 

120 return None 

121 if isinstance(s, str): 

122 return s 

123 try: # keep Python 2 compatibility 

124 return str(s, 'utf-8') 

125 except TypeError: 

126 return str(s) 

127 

128 @staticmethod 

129 def __tobytes(b): 

130 if b is None: 

131 return None 

132 if isinstance(b, bytes): 

133 return b 

134 try: # keep Python 2 compatibility 

135 return bytes(b, 'utf-8') 

136 except TypeError: 

137 return bytes(b) 

138 

139 def file(self, filename): 

140 """ 

141 Returns a textual description of the contents of the argument passed 

142 as a filename or None if an error occurred and the MAGIC_ERROR flag 

143 is set. A call to errno() will return the numeric error code. 

144 """ 

145 return Magic.__tostr(_file(self._magic_t, Magic.__tobytes(filename))) 

146 

147 def descriptor(self, fd): 

148 """ 

149 Returns a textual description of the contents of the argument passed 

150 as a file descriptor or None if an error occurred and the MAGIC_ERROR 

151 flag is set. A call to errno() will return the numeric error code. 

152 """ 

153 return Magic.__tostr(_descriptor(self._magic_t, fd)) 

154 

155 def buffer(self, buf): 

156 """ 

157 Returns a textual description of the contents of the argument passed 

158 as a buffer or None if an error occurred and the MAGIC_ERROR flag 

159 is set. A call to errno() will return the numeric error code. 

160 """ 

161 return Magic.__tostr(_buffer(self._magic_t, buf, len(buf))) 

162 

163 def error(self): 

164 """ 

165 Returns a textual explanation of the last error or None 

166 if there was no error. 

167 """ 

168 return Magic.__tostr(_error(self._magic_t)) 

169 

170 def setflags(self, flags): 

171 """ 

172 Set flags on the magic object which determine how magic checking 

173 behaves; a bitwise OR of the flags described in libmagic(3), but 

174 without the MAGIC_ prefix. 

175 

176 Returns -1 on systems that don't support utime(2) or utimes(2) 

177 when PRESERVE_ATIME is set. 

178 """ 

179 return _setflags(self._magic_t, flags) 

180 

181 def load(self, filename=None): 

182 """ 

183 Must be called to load entries in the colon separated list of database 

184 files passed as argument or the default database file if no argument 

185 before any magic queries can be performed. 

186 

187 Returns 0 on success and -1 on failure. 

188 """ 

189 return _load(self._magic_t, Magic.__tobytes(filename)) 

190 

191 def compile(self, dbs): 

192 """ 

193 Compile entries in the colon separated list of database files 

194 passed as argument or the default database file if no argument. 

195 The compiled files created are named from the basename(1) of each file 

196 argument with ".mgc" appended to it. 

197 

198 Returns 0 on success and -1 on failure. 

199 """ 

200 return _compile(self._magic_t, Magic.__tobytes(dbs)) 

201 

202 def check(self, dbs): 

203 """ 

204 Check the validity of entries in the colon separated list of 

205 database files passed as argument or the default database file 

206 if no argument. 

207 

208 Returns 0 on success and -1 on failure. 

209 """ 

210 return _check(self._magic_t, Magic.__tobytes(dbs)) 

211 

212 def list(self, dbs): 

213 """ 

214 Check the validity of entries in the colon separated list of 

215 database files passed as argument or the default database file 

216 if no argument. 

217 

218 Returns 0 on success and -1 on failure. 

219 """ 

220 return _list(self._magic_t, Magic.__tobytes(dbs)) 

221 

222 def errno(self): 

223 """ 

224 Returns a numeric error code. If return value is 0, an internal 

225 magic error occurred. If return value is non-zero, the value is 

226 an OS error code. Use the errno module or os.strerror() can be used 

227 to provide detailed error information. 

228 """ 

229 return _errno(self._magic_t) 

230 

231 

232def open(flags): 

233 """ 

234 Returns a magic object on success and None on failure. 

235 Flags argument as for setflags. 

236 """ 

237 return Magic(_open(flags)) 

238 

239 

240# Objects used by `detect_from_` functions 

241mime_magic = Magic(_open(MAGIC_MIME)) 

242mime_magic.load() 

243none_magic = Magic(_open(MAGIC_NONE)) 

244none_magic.load() 

245 

246 

247def _create_filemagic(mime_detected, type_detected): 

248 splat = mime_detected.split('; ') 

249 mime_type = splat[0] 

250 if len(splat) == 2: 

251 mime_encoding = splat[1] 

252 else: 

253 mime_encoding = '' 

254 

255 return FileMagic(name=type_detected, mime_type=mime_type, 

256 encoding=mime_encoding.replace('charset=', '')) 

257 

258 

259def detect_from_filename(filename): 

260 '''Detect mime type, encoding and file type from a filename 

261 

262 Returns a `FileMagic` namedtuple. 

263 ''' 

264 

265 return _create_filemagic(mime_magic.file(filename), 

266 none_magic.file(filename)) 

267 

268 

269def detect_from_fobj(fobj): 

270 '''Detect mime type, encoding and file type from file-like object 

271 

272 Returns a `FileMagic` namedtuple. 

273 ''' 

274 

275 file_descriptor = fobj.fileno() 

276 return _create_filemagic(mime_magic.descriptor(file_descriptor), 

277 none_magic.descriptor(file_descriptor)) 

278 

279 

280def detect_from_content(byte_content): 

281 '''Detect mime type, encoding and file type from bytes 

282 

283 Returns a `FileMagic` namedtuple. 

284 ''' 

285 

286 return _create_filemagic(mime_magic.buffer(byte_content), 

287 none_magic.buffer(byte_content))