44Python bindings for libmagic
55'''
66
7- import ctypes
8-
7+ import threading
98from collections import namedtuple
109
1110from ctypes import *
1211from ctypes .util import find_library
1312
14-
1513from . import loader
1614
1715_libraries = {}
4543
4644MAGIC_NO_CHECK_BUILTIN = NO_CHECK_BUILTIN = 4173824
4745
46+ MAGIC_PARAM_INDIR_MAX = PARAM_INDIR_MAX = 0
47+ MAGIC_PARAM_NAME_MAX = PARAM_NAME_MAX = 1
48+ MAGIC_PARAM_ELF_PHNUM_MAX = PARAM_ELF_PHNUM_MAX = 2
49+ MAGIC_PARAM_ELF_SHNUM_MAX = PARAM_ELF_SHNUM_MAX = 3
50+ MAGIC_PARAM_ELF_NOTES_MAX = PARAM_ELF_NOTES_MAX = 4
51+ MAGIC_PARAM_REGEX_MAX = PARAM_REGEX_MAX = 5
52+ MAGIC_PARAM_BYTES_MAX = PARAM_BYTES_MAX = 6
53+
4854FileMagic = namedtuple ('FileMagic' , ('mime_type' , 'encoding' , 'name' ))
4955
5056
5157class magic_set (Structure ):
5258 pass
53-
54-
5559magic_set ._fields_ = []
5660magic_t = POINTER (magic_set )
5761
@@ -103,6 +107,14 @@ class magic_set(Structure):
103107_errno .restype = c_int
104108_errno .argtypes = [magic_t ]
105109
110+ _getparam = _libraries ['magic' ].magic_getparam
111+ _getparam .restype = c_int
112+ _getparam .argtypes = [magic_t , c_int , c_void_p ]
113+
114+ _setparam = _libraries ['magic' ].magic_setparam
115+ _setparam .restype = c_int
116+ _setparam .argtypes = [magic_t , c_int , c_void_p ]
117+
106118
107119class Magic (object ):
108120 def __init__ (self , ms ):
@@ -228,29 +240,81 @@ def errno(self):
228240 """
229241 return _errno (self ._magic_t )
230242
243+ def getparam (self , param ):
244+ """
245+ Returns the param value if successful and -1 if the parameter
246+ was unknown.
247+ """
248+ v = c_int ()
249+ i = _getparam (self ._magic_t , param , byref (v ))
250+ if i == - 1 :
251+ return - 1
252+ return v .value
253+
254+ def setparam (self , param , value ):
255+ """
256+ Returns 0 if successful and -1 if the parameter was unknown.
257+ """
258+ v = c_int (value )
259+ return _setparam (self ._magic_t , param , byref (v ))
260+
231261
232262def open (flags ):
233263 """
234264 Returns a magic object on success and None on failure.
235265 Flags argument as for setflags.
236266 """
237- return Magic (_open (flags ))
267+ magic_t = _open (flags )
268+ if magic_t is None :
269+ return None
270+ return Magic (magic_t )
238271
239272
240273# Objects used by `detect_from_` functions
241- mime_magic = Magic (_open (MAGIC_MIME ))
242- mime_magic .load ()
243- none_magic = Magic (_open (MAGIC_NONE ))
244- none_magic .load ()
274+ class error (Exception ):
275+ pass
245276
277+ class MagicDetect (object ):
278+ def __init__ (self ):
279+ self .mime_magic = open (MAGIC_MIME )
280+ if self .mime_magic is None :
281+ raise error
282+ if self .mime_magic .load () == - 1 :
283+ self .mime_magic .close ()
284+ self .mime_magic = None
285+ raise error
286+ self .none_magic = open (MAGIC_NONE )
287+ if self .none_magic is None :
288+ self .mime_magic .close ()
289+ self .mime_magic = None
290+ raise error
291+ if self .none_magic .load () == - 1 :
292+ self .none_magic .close ()
293+ self .none_magic = None
294+ self .mime_magic .close ()
295+ self .mime_magic = None
296+ raise error
297+
298+ def __del__ (self ):
299+ if self .mime_magic is not None :
300+ self .mime_magic .close ()
301+ if self .none_magic is not None :
302+ self .none_magic .close ()
303+
304+ threadlocal = threading .local ()
305+
306+ def _detect_make ():
307+ v = getattr (threadlocal , "magic_instance" , None )
308+ if v is None :
309+ v = MagicDetect ()
310+ setattr (threadlocal , "magic_instance" , v )
311+ return v
246312
247313def _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 = ''
314+ try :
315+ mime_type , mime_encoding = mime_detected .split ('; ' )
316+ except ValueError :
317+ raise ValueError (mime_detected )
254318
255319 return FileMagic (name = type_detected , mime_type = mime_type ,
256320 encoding = mime_encoding .replace ('charset=' , '' ))
@@ -261,9 +325,9 @@ def detect_from_filename(filename):
261325
262326 Returns a `FileMagic` namedtuple.
263327 '''
264-
265- return _create_filemagic (mime_magic .file (filename ),
266- none_magic .file (filename ))
328+ x = _detect_make ()
329+ return _create_filemagic (x . mime_magic .file (filename ),
330+ x . none_magic .file (filename ))
267331
268332
269333def detect_from_fobj (fobj ):
@@ -273,8 +337,9 @@ def detect_from_fobj(fobj):
273337 '''
274338
275339 file_descriptor = fobj .fileno ()
276- return _create_filemagic (mime_magic .descriptor (file_descriptor ),
277- none_magic .descriptor (file_descriptor ))
340+ x = _detect_make ()
341+ return _create_filemagic (x .mime_magic .descriptor (file_descriptor ),
342+ x .none_magic .descriptor (file_descriptor ))
278343
279344
280345def detect_from_content (byte_content ):
@@ -283,5 +348,6 @@ def detect_from_content(byte_content):
283348 Returns a `FileMagic` namedtuple.
284349 '''
285350
286- return _create_filemagic (mime_magic .buffer (byte_content ),
287- none_magic .buffer (byte_content ))
351+ x = _detect_make ()
352+ return _create_filemagic (x .mime_magic .buffer (byte_content ),
353+ x .none_magic .buffer (byte_content ))
0 commit comments