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 @staticmethod 121 def __tostr(s): 122 if s is None: 123 return None 124 if isinstance(s, str): 125 return s 126 try: # keep Python 2 compatibility 127 return str(s, 'utf-8') 128 except TypeError: 129 return str(s) 130 131 @staticmethod 132 def __tobytes(b): 133 if b is None: 134 return None 135 if isinstance(b, bytes): 136 return b 137 try: # keep Python 2 compatibility 138 return bytes(b, 'utf-8') 139 except TypeError: 140 return bytes(b) 141 142 def file(self, filename): 143 """ 144 Returns a textual description of the contents of the argument passed 145 as a filename or None if an error occurred and the MAGIC_ERROR flag 146 is set. A call to errno() will return the numeric error code. 147 """ 148 return Magic.__tostr(_file(self._magic_t, Magic.__tobytes(filename))) 149 150 def descriptor(self, fd): 151 """ 152 Returns a textual description of the contents of the argument passed 153 as a file descriptor or None if an error occurred and the MAGIC_ERROR 154 flag is set. A call to errno() will return the numeric error code. 155 """ 156 return Magic.__tostr(_descriptor(self._magic_t, fd)) 157 158 def buffer(self, buf): 159 """ 160 Returns a textual description of the contents of the argument passed 161 as a buffer or None if an error occurred and the MAGIC_ERROR flag 162 is set. A call to errno() will return the numeric error code. 163 """ 164 return Magic.__tostr(_buffer(self._magic_t, buf, len(buf))) 165 166 def error(self): 167 """ 168 Returns a textual explanation of the last error or None 169 if there was no error. 170 """ 171 return Magic.__tostr(_error(self._magic_t)) 172 173 def setflags(self, flags): 174 """ 175 Set flags on the magic object which determine how magic checking 176 behaves; a bitwise OR of the flags described in libmagic(3), but 177 without the MAGIC_ prefix. 178 179 Returns -1 on systems that don't support utime(2) or utimes(2) 180 when PRESERVE_ATIME is set. 181 """ 182 return _setflags(self._magic_t, flags) 183 184 def load(self, filename=None): 185 """ 186 Must be called to load entries in the colon separated list of database 187 files passed as argument or the default database file if no argument 188 before any magic queries can be performed. 189 190 Returns 0 on success and -1 on failure. 191 """ 192 return _load(self._magic_t, Magic.__tobytes(filename)) 193 194 def compile(self, dbs): 195 """ 196 Compile entries in the colon separated list of database files 197 passed as argument or the default database file if no argument. 198 The compiled files created are named from the basename(1) of each file 199 argument with ".mgc" appended to it. 200 201 Returns 0 on success and -1 on failure. 202 """ 203 return _compile(self._magic_t, Magic.__tobytes(dbs)) 204 205 def check(self, dbs): 206 """ 207 Check the validity of entries in the colon separated list of 208 database files passed as argument or the default database file 209 if no argument. 210 211 Returns 0 on success and -1 on failure. 212 """ 213 return _check(self._magic_t, Magic.__tobytes(dbs)) 214 215 def list(self, dbs): 216 """ 217 Check the validity of entries in the colon separated list of 218 database files passed as argument or the default database file 219 if no argument. 220 221 Returns 0 on success and -1 on failure. 222 """ 223 return _list(self._magic_t, Magic.__tobytes(dbs)) 224 225 def errno(self): 226 """ 227 Returns a numeric error code. If return value is 0, an internal 228 magic error occurred. If return value is non-zero, the value is 229 an OS error code. Use the errno module or os.strerror() can be used 230 to provide detailed error information. 231 """ 232 return _errno(self._magic_t) 233 234 235def open(flags): 236 """ 237 Returns a magic object on success and None on failure. 238 Flags argument as for setflags. 239 """ 240 return Magic(_open(flags)) 241 242 243# Objects used by `detect_from_` functions 244mime_magic = Magic(_open(MAGIC_MIME)) 245mime_magic.load() 246none_magic = Magic(_open(MAGIC_NONE)) 247none_magic.load() 248 249 250def _create_filemagic(mime_detected, type_detected): 251 try: 252 mime_type, mime_encoding = mime_detected.split('; ') 253 except ValueError: 254 raise ValueError(mime_detected) 255 256 return FileMagic(name=type_detected, mime_type=mime_type, 257 encoding=mime_encoding.replace('charset=', '')) 258 259 260def detect_from_filename(filename): 261 '''Detect mime type, encoding and file type from a filename 262 263 Returns a `FileMagic` namedtuple. 264 ''' 265 266 return _create_filemagic(mime_magic.file(filename), 267 none_magic.file(filename)) 268 269 270def detect_from_fobj(fobj): 271 '''Detect mime type, encoding and file type from file-like object 272 273 Returns a `FileMagic` namedtuple. 274 ''' 275 276 file_descriptor = fobj.fileno() 277 return _create_filemagic(mime_magic.descriptor(file_descriptor), 278 none_magic.descriptor(file_descriptor)) 279 280 281def detect_from_content(byte_content): 282 '''Detect mime type, encoding and file type from bytes 283 284 Returns a `FileMagic` namedtuple. 285 ''' 286 287 return _create_filemagic(mime_magic.buffer(byte_content), 288 none_magic.buffer(byte_content)) 289