import ctypes
import threading
from collections import namedtuple
from ctypes import *
from ctypes.util import find_library
def _init():
return ctypes.cdll.LoadLibrary(find_library('magic'))
_libraries = {}
_libraries['magic'] = _init()
MAGIC_NONE = NONE = 0
MAGIC_DEBUG = DEBUG = 1
MAGIC_SYMLINK = SYMLINK = 2
MAGIC_COMPRESS = COMPRESS = 4
MAGIC_DEVICES = DEVICES = 8
MAGIC_MIME_TYPE = MIME_TYPE = 16
MAGIC_CONTINUE = CONTINUE = 32
MAGIC_CHECK = CHECK = 64
MAGIC_PRESERVE_ATIME = PRESERVE_ATIME = 128
MAGIC_RAW = RAW = 256
MAGIC_ERROR = ERROR = 512
MAGIC_MIME_ENCODING = MIME_ENCODING = 1024
MAGIC_MIME = MIME = 1040 MAGIC_APPLE = APPLE = 2048
MAGIC_NO_CHECK_COMPRESS = NO_CHECK_COMPRESS = 4096
MAGIC_NO_CHECK_TAR = NO_CHECK_TAR = 8192
MAGIC_NO_CHECK_SOFT = NO_CHECK_SOFT = 16384
MAGIC_NO_CHECK_APPTYPE = NO_CHECK_APPTYPE = 32768
MAGIC_NO_CHECK_ELF = NO_CHECK_ELF = 65536
MAGIC_NO_CHECK_TEXT = NO_CHECK_TEXT = 131072
MAGIC_NO_CHECK_CDF = NO_CHECK_CDF = 262144
MAGIC_NO_CHECK_TOKENS = NO_CHECK_TOKENS = 1048576
MAGIC_NO_CHECK_ENCODING = NO_CHECK_ENCODING = 2097152
MAGIC_NO_CHECK_BUILTIN = NO_CHECK_BUILTIN = 4173824
MAGIC_PARAM_INDIR_MAX = PARAM_INDIR_MAX = 0
MAGIC_PARAM_NAME_MAX = PARAM_NAME_MAX = 1
MAGIC_PARAM_ELF_PHNUM_MAX = PARAM_ELF_PHNUM_MAX = 2
MAGIC_PARAM_ELF_SHNUM_MAX = PARAM_ELF_SHNUM_MAX = 3
MAGIC_PARAM_ELF_NOTES_MAX = PARAM_ELF_NOTES_MAX = 4
MAGIC_PARAM_REGEX_MAX = PARAM_REGEX_MAX = 5
MAGIC_PARAM_BYTES_MAX = PARAM_BYTES_MAX = 6
FileMagic = namedtuple('FileMagic', ('mime_type', 'encoding', 'name'))
class magic_set(Structure):
pass
magic_set._fields_ = []
magic_t = POINTER(magic_set)
_open = _libraries['magic'].magic_open
_open.restype = magic_t
_open.argtypes = [c_int]
_close = _libraries['magic'].magic_close
_close.restype = None
_close.argtypes = [magic_t]
_file = _libraries['magic'].magic_file
_file.restype = c_char_p
_file.argtypes = [magic_t, c_char_p]
_descriptor = _libraries['magic'].magic_descriptor
_descriptor.restype = c_char_p
_descriptor.argtypes = [magic_t, c_int]
_buffer = _libraries['magic'].magic_buffer
_buffer.restype = c_char_p
_buffer.argtypes = [magic_t, c_void_p, c_size_t]
_error = _libraries['magic'].magic_error
_error.restype = c_char_p
_error.argtypes = [magic_t]
_setflags = _libraries['magic'].magic_setflags
_setflags.restype = c_int
_setflags.argtypes = [magic_t, c_int]
_load = _libraries['magic'].magic_load
_load.restype = c_int
_load.argtypes = [magic_t, c_char_p]
_compile = _libraries['magic'].magic_compile
_compile.restype = c_int
_compile.argtypes = [magic_t, c_char_p]
_check = _libraries['magic'].magic_check
_check.restype = c_int
_check.argtypes = [magic_t, c_char_p]
_list = _libraries['magic'].magic_list
_list.restype = c_int
_list.argtypes = [magic_t, c_char_p]
_errno = _libraries['magic'].magic_errno
_errno.restype = c_int
_errno.argtypes = [magic_t]
_getparam = _libraries['magic'].magic_getparam
_getparam.restype = c_int
_getparam.argtypes = [magic_t, c_int, c_void_p]
_setparam = _libraries['magic'].magic_setparam
_setparam.restype = c_int
_setparam.argtypes = [magic_t, c_int, c_void_p]
class Magic(object):
def __init__(self, ms):
self._magic_t = ms
def close(self):
_close(self._magic_t)
@staticmethod
def __tostr(s):
if s is None:
return None
if isinstance(s, str):
return s
try: return str(s, 'utf-8')
except TypeError:
return str(s)
@staticmethod
def __tobytes(b):
if b is None:
return None
if isinstance(b, bytes):
return b
try: return bytes(b, 'utf-8')
except TypeError:
return bytes(b)
def file(self, filename):
return Magic.__tostr(_file(self._magic_t, Magic.__tobytes(filename)))
def descriptor(self, fd):
return Magic.__tostr(_descriptor(self._magic_t, fd))
def buffer(self, buf):
return Magic.__tostr(_buffer(self._magic_t, buf, len(buf)))
def error(self):
return Magic.__tostr(_error(self._magic_t))
def setflags(self, flags):
return _setflags(self._magic_t, flags)
def load(self, filename=None):
return _load(self._magic_t, Magic.__tobytes(filename))
def compile(self, dbs):
return _compile(self._magic_t, Magic.__tobytes(dbs))
def check(self, dbs):
return _check(self._magic_t, Magic.__tobytes(dbs))
def list(self, dbs):
return _list(self._magic_t, Magic.__tobytes(dbs))
def errno(self):
return _errno(self._magic_t)
def getparam(self, param):
v = c_int()
i = _getparam(self._magic_t, param, byref(v))
if i == -1:
return -1
return v.value
def setparam(self, param, value):
v = c_int(value)
return _setparam(self._magic_t, param, byref(v))
def open(flags):
magic_t = _open(flags)
if magic_t is None:
return None
return Magic(magic_t)
class error(Exception):
pass
class MagicDetect(object):
def __init__(self):
self.mime_magic = open(MAGIC_MIME)
if self.mime_magic is None:
raise error
if self.mime_magic.load() == -1:
self.mime_magic.close()
self.mime_magic = None
raise error
self.none_magic = open(MAGIC_NONE)
if self.none_magic is None:
self.mime_magic.close()
self.mime_magic = None
raise error
if self.none_magic.load() == -1:
self.none_magic.close()
self.none_magic = None
self.mime_magic.close()
self.mime_magic = None
raise error
def __del__(self):
if self.mime_magic is not None:
self.mime_magic.close()
if self.none_magic is not None:
self.none_magic.close()
threadlocal = threading.local()
def _detect_make():
v = getattr(threadlocal, "magic_instance", None)
if v is None:
v = MagicDetect()
setattr(threadlocal, "magic_instance", v)
return v
def _create_filemagic(mime_detected, type_detected):
try:
mime_type, mime_encoding = mime_detected.split('; ')
except ValueError:
raise ValueError(mime_detected)
return FileMagic(name=type_detected, mime_type=mime_type,
encoding=mime_encoding.replace('charset=', ''))
def detect_from_filename(filename):
x = _detect_make()
return _create_filemagic(x.mime_magic.file(filename),
x.none_magic.file(filename))
def detect_from_fobj(fobj):
file_descriptor = fobj.fileno()
x = _detect_make()
return _create_filemagic(x.mime_magic.descriptor(file_descriptor),
x.none_magic.descriptor(file_descriptor))
def detect_from_content(byte_content):
x = _detect_make()
return _create_filemagic(x.mime_magic.buffer(byte_content),
x.none_magic.buffer(byte_content))