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 15def _init(): 16 """ 17 Loads the shared library through ctypes and returns a library 18 L{ctypes.CDLL} instance 19 """ 20 return ctypes.cdll.LoadLibrary(find_library('magic')) 21 22_libraries = {} 23_libraries['magic'] = _init() 24 25# Flag constants for open and setflags 26MAGIC_NONE = NONE = 0 27MAGIC_DEBUG = DEBUG = 1 28MAGIC_SYMLINK = SYMLINK = 2 29MAGIC_COMPRESS = COMPRESS = 4 30MAGIC_DEVICES = DEVICES = 8 31MAGIC_MIME_TYPE = MIME_TYPE = 16 32MAGIC_CONTINUE = CONTINUE = 32 33MAGIC_CHECK = CHECK = 64 34MAGIC_PRESERVE_ATIME = PRESERVE_ATIME = 128 35MAGIC_RAW = RAW = 256 36MAGIC_ERROR = ERROR = 512 37MAGIC_MIME_ENCODING = MIME_ENCODING = 1024 38MAGIC_MIME = MIME = 1040 # MIME_TYPE + MIME_ENCODING 39MAGIC_APPLE = APPLE = 2048 40 41MAGIC_NO_CHECK_COMPRESS = NO_CHECK_COMPRESS = 4096 42MAGIC_NO_CHECK_TAR = NO_CHECK_TAR = 8192 43MAGIC_NO_CHECK_SOFT = NO_CHECK_SOFT = 16384 44MAGIC_NO_CHECK_APPTYPE = NO_CHECK_APPTYPE = 32768 45MAGIC_NO_CHECK_ELF = NO_CHECK_ELF = 65536 46MAGIC_NO_CHECK_TEXT = NO_CHECK_TEXT = 131072 47MAGIC_NO_CHECK_CDF = NO_CHECK_CDF = 262144 48MAGIC_NO_CHECK_TOKENS = NO_CHECK_TOKENS = 1048576 49MAGIC_NO_CHECK_ENCODING = NO_CHECK_ENCODING = 2097152 50 51MAGIC_NO_CHECK_BUILTIN = NO_CHECK_BUILTIN = 4173824 52 53FileMagic = namedtuple('FileMagic', ('mime_type', 'encoding', 'name')) 54 55 56class magic_set(Structure): 57 pass 58magic_set._fields_ = [] 59magic_t = POINTER(magic_set) 60 61_open = _libraries['magic'].magic_open 62_open.restype = magic_t 63_open.argtypes = [c_int] 64 65_close = _libraries['magic'].magic_close 66_close.restype = None 67_close.argtypes = [magic_t] 68 69_file = _libraries['magic'].magic_file 70_file.restype = c_char_p 71_file.argtypes = [magic_t, c_char_p] 72 73_descriptor = _libraries['magic'].magic_descriptor 74_descriptor.restype = c_char_p 75_descriptor.argtypes = [magic_t, c_int] 76 77_buffer = _libraries['magic'].magic_buffer 78_buffer.restype = c_char_p 79_buffer.argtypes = [magic_t, c_void_p, c_size_t] 80 81_error = _libraries['magic'].magic_error 82_error.restype = c_char_p 83_error.argtypes = [magic_t] 84 85_setflags = _libraries['magic'].magic_setflags 86_setflags.restype = c_int 87_setflags.argtypes = [magic_t, c_int] 88 89_load = _libraries['magic'].magic_load 90_load.restype = c_int 91_load.argtypes = [magic_t, c_char_p] 92 93_compile = _libraries['magic'].magic_compile 94_compile.restype = c_int 95_compile.argtypes = [magic_t, c_char_p] 96 97_check = _libraries['magic'].magic_check 98_check.restype = c_int 99_check.argtypes = [magic_t, c_char_p] 100 101_list = _libraries['magic'].magic_list 102_list.restype = c_int 103_list.argtypes = [magic_t, c_char_p] 104 105_errno = _libraries['magic'].magic_errno 106_errno.restype = c_int 107_errno.argtypes = [magic_t] 108 109 110class Magic(object): 111 def __init__(self, ms): 112 self._magic_t = ms 113 114 def close(self): 115 """ 116 Closes the magic database and deallocates any resources used. 117 """ 118 _close(self._magic_t) 119 120 def file(self, filename): 121 """ 122 Returns a textual description of the contents of the argument passed 123 as a filename or None if an error occurred and the MAGIC_ERROR flag 124 is set. A call to errno() will return the numeric error code. 125 """ 126 if isinstance(filename, bytes): 127 bi = filename 128 else: 129 try: # keep Python 2 compatibility 130 bi = bytes(filename, 'utf-8') 131 except TypeError: 132 bi = bytes(filename) 133 r = _file(self._magic_t, bi) 134 if isinstance(r, str): 135 return r 136 else: 137 return str(r).encode('utf-8') 138 139 def descriptor(self, fd): 140 """ 141 Like the file method, but the argument is a file descriptor. 142 """ 143 return _descriptor(self._magic_t, fd) 144 145 def buffer(self, buf): 146 """ 147 Returns a textual description of the contents of the argument passed 148 as a buffer or None if an error occurred and the MAGIC_ERROR flag 149 is set. A call to errno() will return the numeric error code. 150 """ 151 r = _buffer(self._magic_t, buf, len(buf)) 152 if isinstance(r, str): 153 return r 154 else: 155 return str(r).encode('utf-8') 156 157 def error(self): 158 """ 159 Returns a textual explanation of the last error or None 160 if there was no error. 161 """ 162 e = _error(self._magic_t) 163 if isinstance(e, str): 164 return e 165 else: 166 return str(e).encode('utf-8') 167 168 def setflags(self, flags): 169 """ 170 Set flags on the magic object which determine how magic checking 171 behaves; a bitwise OR of the flags described in libmagic(3), but 172 without the MAGIC_ prefix. 173 174 Returns -1 on systems that don't support utime(2) or utimes(2) 175 when PRESERVE_ATIME is set. 176 """ 177 return _setflags(self._magic_t, flags) 178 179 def load(self, filename=None): 180 """ 181 Must be called to load entries in the colon separated list of database 182 files passed as argument or the default database file if no argument 183 before any magic queries can be performed. 184 185 Returns 0 on success and -1 on failure. 186 """ 187 return _load(self._magic_t, filename) 188 189 def compile(self, dbs): 190 """ 191 Compile entries in the colon separated list of database files 192 passed as argument or the default database file if no argument. 193 Returns 0 on success and -1 on failure. 194 The compiled files created are named from the basename(1) of each file 195 argument with ".mgc" appended to it. 196 """ 197 return _compile(self._magic_t, dbs) 198 199 def check(self, dbs): 200 """ 201 Check the validity of entries in the colon separated list of 202 database files passed as argument or the default database file 203 if no argument. 204 Returns 0 on success and -1 on failure. 205 """ 206 return _check(self._magic_t, dbs) 207 208 def list(self, dbs): 209 """ 210 Check the validity of entries in the colon separated list of 211 database files passed as argument or the default database file 212 if no argument. 213 Returns 0 on success and -1 on failure. 214 """ 215 return _list(self._magic_t, dbs) 216 217 def errno(self): 218 """ 219 Returns a numeric error code. If return value is 0, an internal 220 magic error occurred. If return value is non-zero, the value is 221 an OS error code. Use the errno module or os.strerror() can be used 222 to provide detailed error information. 223 """ 224 return _errno(self._magic_t) 225 226 227def open(flags): 228 """ 229 Returns a magic object on success and None on failure. 230 Flags argument as for setflags. 231 """ 232 return Magic(_open(flags)) 233 234 235# Objects used by `detect_from_` functions 236mime_magic = Magic(_open(MAGIC_MIME)) 237mime_magic.load() 238none_magic = Magic(_open(MAGIC_NONE)) 239none_magic.load() 240 241 242def _create_filemagic(mime_detected, type_detected): 243 mime_type, mime_encoding = mime_detected.split('; ') 244 245 return FileMagic(name=type_detected, mime_type=mime_type, 246 encoding=mime_encoding.replace('charset=', '')) 247 248 249def detect_from_filename(filename): 250 '''Detect mime type, encoding and file type from a filename 251 252 Returns a `FileMagic` namedtuple. 253 ''' 254 255 return _create_filemagic(mime_magic.file(filename), 256 none_magic.file(filename)) 257 258 259def detect_from_fobj(fobj): 260 '''Detect mime type, encoding and file type from file-like object 261 262 Returns a `FileMagic` namedtuple. 263 ''' 264 265 file_descriptor = fobj.fileno() 266 return _create_filemagic(mime_magic.descriptor(file_descriptor), 267 none_magic.descriptor(file_descriptor)) 268 269 270def detect_from_content(byte_content): 271 '''Detect mime type, encoding and file type from bytes 272 273 Returns a `FileMagic` namedtuple. 274 ''' 275 276 return _create_filemagic(mime_magic.buffer(byte_content), 277 none_magic.buffer(byte_content)) 278