diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-09-02 08:54:31 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-09-02 08:54:31 +0000 |
commit | 10429269fbeb9442be4c5592b9111ccedbfefd0d (patch) | |
tree | ec492f5b26d71445da74668b4c967621e9ebc556 /python/magic.py | |
parent | 670c2bbcffe873a2b8589ed140c12e7923ef20c0 (diff) | |
download | file-master.tar.gz |
Diffstat (limited to 'python/magic.py')
-rw-r--r-- | python/magic.py | 116 |
1 files changed, 90 insertions, 26 deletions
diff --git a/python/magic.py b/python/magic.py index a17e8da..662569e 100644 --- a/python/magic.py +++ b/python/magic.py @@ -1,10 +1,13 @@ -#!/usr/bin/env python +# coding: utf-8 + ''' Python bindings for libmagic ''' import ctypes +from collections import namedtuple + from ctypes import * from ctypes.util import find_library @@ -32,7 +35,7 @@ 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_MIME = MIME = 1040 # MIME_TYPE + MIME_ENCODING MAGIC_APPLE = APPLE = 2048 MAGIC_NO_CHECK_COMPRESS = NO_CHECK_COMPRESS = 4096 @@ -47,6 +50,8 @@ MAGIC_NO_CHECK_ENCODING = NO_CHECK_ENCODING = 2097152 MAGIC_NO_CHECK_BUILTIN = NO_CHECK_BUILTIN = 4173824 +FileMagic = namedtuple('FileMagic', ('mime_type', 'encoding', 'name')) + class magic_set(Structure): pass @@ -112,26 +117,43 @@ class Magic(object): """ _close(self._magic_t) + @staticmethod + def __tostr(s): + if s is None: + return None + if isinstance(s, str): + return s + try: # keep Python 2 compatibility + 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: # keep Python 2 compatibility + return bytes(b, 'utf-8') + except TypeError: + return bytes(b) + def file(self, filename): """ Returns a textual description of the contents of the argument passed as a filename or None if an error occurred and the MAGIC_ERROR flag - is set. A call to errno() will return the numeric error code. + is set. A call to errno() will return the numeric error code. """ - try: # attempt python3 approach first - if isinstance(filename, bytes): - bi = filename - else: - bi = bytes(filename, 'utf-8') - return str(_file(self._magic_t, bi), 'utf-8') - except: - return _file(self._magic_t, filename.encode('utf-8')) + return Magic.__tostr(_file(self._magic_t, Magic.__tobytes(filename))) def descriptor(self, fd): """ - Like the file method, but the argument is a file descriptor. + Returns a textual description of the contents of the argument passed + as a file descriptor or None if an error occurred and the MAGIC_ERROR + flag is set. A call to errno() will return the numeric error code. """ - return _descriptor(self._magic_t, fd) + return Magic.__tostr(_descriptor(self._magic_t, fd)) def buffer(self, buf): """ @@ -139,20 +161,14 @@ class Magic(object): as a buffer or None if an error occurred and the MAGIC_ERROR flag is set. A call to errno() will return the numeric error code. """ - try: # attempt python3 approach first - return str(_buffer(self._magic_t, buf, len(buf)), 'utf-8') - except: - return _buffer(self._magic_t, buf, len(buf)) + return Magic.__tostr(_buffer(self._magic_t, buf, len(buf))) def error(self): """ Returns a textual explanation of the last error or None if there was no error. """ - try: # attempt python3 approach first - return str(_error(self._magic_t), 'utf-8') - except: - return _error(self._magic_t) + return Magic.__tostr(_error(self._magic_t)) def setflags(self, flags): """ @@ -173,35 +189,38 @@ class Magic(object): Returns 0 on success and -1 on failure. """ - return _load(self._magic_t, filename) + return _load(self._magic_t, Magic.__tobytes(filename)) def compile(self, dbs): """ Compile entries in the colon separated list of database files passed as argument or the default database file if no argument. - Returns 0 on success and -1 on failure. The compiled files created are named from the basename(1) of each file argument with ".mgc" appended to it. + + Returns 0 on success and -1 on failure. """ - return _compile(self._magic_t, dbs) + return _compile(self._magic_t, Magic.__tobytes(dbs)) def check(self, dbs): """ Check the validity of entries in the colon separated list of database files passed as argument or the default database file if no argument. + Returns 0 on success and -1 on failure. """ - return _check(self._magic_t, dbs) + return _check(self._magic_t, Magic.__tobytes(dbs)) def list(self, dbs): """ Check the validity of entries in the colon separated list of database files passed as argument or the default database file if no argument. + Returns 0 on success and -1 on failure. """ - return _list(self._magic_t, dbs) + return _list(self._magic_t, Magic.__tobytes(dbs)) def errno(self): """ @@ -219,3 +238,48 @@ def open(flags): Flags argument as for setflags. """ return Magic(_open(flags)) + + +# Objects used by `detect_from_` functions +mime_magic = Magic(_open(MAGIC_MIME)) +mime_magic.load() +none_magic = Magic(_open(MAGIC_NONE)) +none_magic.load() + + +def _create_filemagic(mime_detected, type_detected): + mime_type, mime_encoding = mime_detected.split('; ') + + return FileMagic(name=type_detected, mime_type=mime_type, + encoding=mime_encoding.replace('charset=', '')) + + +def detect_from_filename(filename): + '''Detect mime type, encoding and file type from a filename + + Returns a `FileMagic` namedtuple. + ''' + + return _create_filemagic(mime_magic.file(filename), + none_magic.file(filename)) + + +def detect_from_fobj(fobj): + '''Detect mime type, encoding and file type from file-like object + + Returns a `FileMagic` namedtuple. + ''' + + file_descriptor = fobj.fileno() + return _create_filemagic(mime_magic.descriptor(file_descriptor), + none_magic.descriptor(file_descriptor)) + + +def detect_from_content(byte_content): + '''Detect mime type, encoding and file type from bytes + + Returns a `FileMagic` namedtuple. + ''' + + return _create_filemagic(mime_magic.buffer(byte_content), + none_magic.buffer(byte_content)) |