Skip to content

Commit aeda67e

Browse files
committed
updated third-party magic library
1 parent 9e2f013 commit aeda67e

1 file changed

Lines changed: 109 additions & 57 deletions

File tree

thirdparty/magic/magic.py

Lines changed: 109 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,23 @@
1-
#!/usr/bin/env python
2-
31
"""
4-
Adam Hupp <adam@hupp.org>
2+
magic is a wrapper around the libmagic file identification library.
3+
4+
See README for more information.
5+
6+
Usage:
7+
8+
>>> import magic
9+
>>> magic.from_file("testdata/test.pdf")
10+
'PDF document, version 1.2'
11+
>>> magic.from_file("testdata/test.pdf", mime=True)
12+
'application/pdf'
13+
>>> magic.from_buffer(open("testdata/test.pdf").read(1024))
14+
'PDF document, version 1.2'
15+
>>>
516
6-
Reference: http://hupp.org/adam/hg/python-magic
717
8-
License: PSF (http://www.python.org/psf/license/)
918
"""
1019

20+
import sys
1121
import os.path
1222
import ctypes
1323
import ctypes.util
@@ -18,26 +28,30 @@ class MagicException(Exception): pass
1828

1929
class Magic:
2030
"""
21-
Magic is a wrapper around the libmagic C library.
31+
Magic is a wrapper around the libmagic C library.
2232
2333
"""
2434

25-
def __init__(self, mime=False, magic_file=None):
35+
def __init__(self, mime=False, magic_file=None, mime_encoding=False):
2636
"""
2737
Create a new libmagic wrapper.
2838
2939
mime - if True, mimetypes are returned instead of textual descriptions
40+
mime_encoding - if True, codec is returned
3041
magic_file - use a mime database other than the system default
3142
3243
"""
3344
flags = MAGIC_NONE
3445
if mime:
3546
flags |= MAGIC_MIME
47+
elif mime_encoding:
48+
flags |= MAGIC_MIME_ENCODING
3649

3750
self.cookie = magic_open(flags)
3851

3952
magic_load(self.cookie, magic_file)
4053

54+
4155
def from_buffer(self, buf):
4256
"""
4357
Identify the contents of `buf`
@@ -56,10 +70,10 @@ def from_file(self, filename):
5670
return magic_file(self.cookie, filename)
5771

5872
def __del__(self):
59-
try:
73+
# during shutdown magic_close may have been cleared already
74+
if self.cookie and magic_close:
6075
magic_close(self.cookie)
61-
except Exception, _:
62-
pass
76+
self.cookie = None
6377

6478
_magic_mime = None
6579
_magic = None
@@ -90,66 +104,102 @@ def from_buffer(buffer, mime=False):
90104
m = _get_magic_type(mime)
91105
return m.from_buffer(buffer)
92106

93-
try:
94-
libmagic = ctypes.CDLL(ctypes.util.find_library('magic'))
95107

96-
magic_t = ctypes.c_void_p
97108

98-
def errorcheck(result, func, args):
99-
err = magic_error(args[0])
100-
if err is not None:
101-
raise MagicException(err)
102-
else:
103-
return result
104109

105-
magic_open = libmagic.magic_open
106-
magic_open.restype = magic_t
107-
magic_open.argtypes = [c_int]
110+
libmagic = None
111+
# Let's try to find magic or magic1
112+
dll = ctypes.util.find_library('magic') or ctypes.util.find_library('magic1')
113+
114+
# This is necessary because find_library returns None if it doesn't find the library
115+
if dll:
116+
libmagic = ctypes.CDLL(dll)
117+
118+
if not libmagic or not libmagic._name:
119+
import sys
120+
platform_to_lib = {'darwin': ['/opt/local/lib/libmagic.dylib',
121+
'/usr/local/lib/libmagic.dylib',
122+
'/usr/local/Cellar/libmagic/5.10/lib/libmagic.dylib'],
123+
'win32': ['magic1.dll']}
124+
for dll in platform_to_lib.get(sys.platform, []):
125+
try:
126+
libmagic = ctypes.CDLL(dll)
127+
except OSError:
128+
pass
129+
130+
if not libmagic or not libmagic._name:
131+
# It is better to raise an ImportError since we are importing magic module
132+
raise ImportError('failed to find libmagic. Check your installation')
133+
134+
magic_t = ctypes.c_void_p
135+
136+
def errorcheck(result, func, args):
137+
err = magic_error(args[0])
138+
if err is not None:
139+
raise MagicException(err)
140+
else:
141+
return result
142+
143+
def coerce_filename(filename):
144+
if filename is None:
145+
return None
146+
return filename.encode(sys.getfilesystemencoding())
147+
148+
magic_open = libmagic.magic_open
149+
magic_open.restype = magic_t
150+
magic_open.argtypes = [c_int]
151+
152+
magic_close = libmagic.magic_close
153+
magic_close.restype = None
154+
magic_close.argtypes = [magic_t]
108155

109-
magic_close = libmagic.magic_close
110-
magic_close.restype = None
111-
magic_close.argtypes = [magic_t]
112-
magic_close.errcheck = errorcheck
156+
magic_error = libmagic.magic_error
157+
magic_error.restype = c_char_p
158+
magic_error.argtypes = [magic_t]
113159

114-
magic_error = libmagic.magic_error
115-
magic_error.restype = c_char_p
116-
magic_error.argtypes = [magic_t]
160+
magic_errno = libmagic.magic_errno
161+
magic_errno.restype = c_int
162+
magic_errno.argtypes = [magic_t]
117163

118-
magic_errno = libmagic.magic_errno
119-
magic_errno.restype = c_int
120-
magic_errno.argtypes = [magic_t]
164+
_magic_file = libmagic.magic_file
165+
_magic_file.restype = c_char_p
166+
_magic_file.argtypes = [magic_t, c_char_p]
167+
_magic_file.errcheck = errorcheck
121168

122-
magic_file = libmagic.magic_file
123-
magic_file.restype = c_char_p
124-
magic_file.argtypes = [magic_t, c_char_p]
125-
magic_file.errcheck = errorcheck
169+
def magic_file(cookie, filename):
170+
return _magic_file(cookie, coerce_filename(filename))
126171

127-
_magic_buffer = libmagic.magic_buffer
128-
_magic_buffer.restype = c_char_p
129-
_magic_buffer.argtypes = [magic_t, c_void_p, c_size_t]
130-
_magic_buffer.errcheck = errorcheck
172+
_magic_buffer = libmagic.magic_buffer
173+
_magic_buffer.restype = c_char_p
174+
_magic_buffer.argtypes = [magic_t, c_void_p, c_size_t]
175+
_magic_buffer.errcheck = errorcheck
131176

132-
def magic_buffer(cookie, buf):
133-
return _magic_buffer(cookie, buf, len(buf))
134177

135-
magic_load = libmagic.magic_load
136-
magic_load.restype = c_int
137-
magic_load.argtypes = [magic_t, c_char_p]
138-
magic_load.errcheck = errorcheck
178+
def magic_buffer(cookie, buf):
179+
return _magic_buffer(cookie, buf, len(buf))
139180

140-
magic_setflags = libmagic.magic_setflags
141-
magic_setflags.restype = c_int
142-
magic_setflags.argtypes = [magic_t, c_int]
143181

144-
magic_check = libmagic.magic_check
145-
magic_check.restype = c_int
146-
magic_check.argtypes = [magic_t, c_char_p]
182+
_magic_load = libmagic.magic_load
183+
_magic_load.restype = c_int
184+
_magic_load.argtypes = [magic_t, c_char_p]
185+
_magic_load.errcheck = errorcheck
186+
187+
def magic_load(cookie, filename):
188+
return _magic_load(cookie, coerce_filename(filename))
189+
190+
magic_setflags = libmagic.magic_setflags
191+
magic_setflags.restype = c_int
192+
magic_setflags.argtypes = [magic_t, c_int]
193+
194+
magic_check = libmagic.magic_check
195+
magic_check.restype = c_int
196+
magic_check.argtypes = [magic_t, c_char_p]
197+
198+
magic_compile = libmagic.magic_compile
199+
magic_compile.restype = c_int
200+
magic_compile.argtypes = [magic_t, c_char_p]
201+
147202

148-
magic_compile = libmagic.magic_compile
149-
magic_compile.restype = c_int
150-
magic_compile.argtypes = [magic_t, c_char_p]
151-
except:
152-
pass
153203

154204
MAGIC_NONE = 0x000000 # No flags
155205

@@ -163,6 +213,8 @@ def magic_buffer(cookie, buf):
163213

164214
MAGIC_MIME = 0x000010 # Return a mime string
165215

216+
MAGIC_MIME_ENCODING = 0x000400 # Return the MIME encoding
217+
166218
MAGIC_CONTINUE = 0x000020 # Return all matches
167219

168220
MAGIC_CHECK = 0x000040 # Print warnings to stderr

0 commit comments

Comments
 (0)