diff options
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | config.mk | 6 | ||||
-rw-r--r-- | src/imlib.c | 134 |
3 files changed, 59 insertions, 83 deletions
@@ -22,6 +22,7 @@ Dependencies * Imlib2 * libcurl (disable with make curl=0) + * libmagic (disable with make magic=0) * libpng * libX11 * libXinerama (disable with make xinerama=0) @@ -91,6 +92,7 @@ indicates that the corresponding feature is enabled by default. | help | 0 | include help text (refers to the manpage otherwise) | | inotify | 0 | enable inotify, needed for `--auto-reload` | | stat64 | 0 | Support CIFS shares from 64bit hosts on 32bit machines | +| magic | 1 | Build against libmagic to filter unsupported file formats | | mkstemps | 1 | Whether your libc provides `mkstemps()`. If set to 0, feh will be unable to load gif images via libcurl | | verscmp | 1 | Whether your libc provides `strvercmp()`. If set to 0, feh will use an internal implementation. | | xinerama | 1 | Support Xinerama/XRandR multiscreen setups | @@ -6,6 +6,7 @@ curl ?= 1 debug ?= 0 exif ?= 0 help ?= 0 +magic ?= 1 mkstemps ?= 1 verscmp ?= 1 xinerama ?= 1 @@ -68,6 +69,11 @@ ifeq (${mkstemps},1) CFLAGS += -DHAVE_MKSTEMPS endif +ifeq (${magic},1) + CFLAGS += -DHAVE_LIBMAGIC + LDLIBS += -lmagic +endif + ifeq (${verscmp},1) CFLAGS += -DHAVE_STRVERSCMP endif diff --git a/src/imlib.c b/src/imlib.c index 6d709a2..70d459f 100644 --- a/src/imlib.c +++ b/src/imlib.c @@ -44,6 +44,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "exif.h" #endif +#ifdef HAVE_LIBMAGIC +#include <magic.h> +#endif + Display *disp = NULL; Visual *vis = NULL; Screen *scr = NULL; @@ -242,98 +246,62 @@ void feh_print_load_error(char *file, winwidget w, Imlib_Load_Error err, enum fe * avoid calling Imlib2 for files it probably cannot handle. See * <https://phab.enlightenment.org/T8739> and * <https://github.com/derf/feh/issues/505>. - * - * Note that this drops support for bz2-compressed files, unless - * FEH_SKIP_MAGIC is set */ int feh_is_image(feh_file * file) { - unsigned char buf[16]; - FILE *fh = fopen(file->filename, "r"); - if (!fh) { - return 0; - } - // Files smaller than buf will be padded with zeroes - memset(buf, 0, sizeof(buf)); - if (fread(buf, 1, 16, fh) <= 0) { - fclose(fh); - return 0; - } - fclose(fh); +#ifdef HAVE_LIBMAGIC + magic_t magic; + const char * mime_type; + int is_image = 0; - if (buf[0] == 0xff && buf[1] == 0xd8) { - // JPEG - return 1; - } - if (!memcmp(buf, "\x89PNG\x0d\x0a\x1a\x0a", 8)) { - // PNG - return 1; - } - if (buf[0] == 'A' && buf[1] == 'R' && buf[2] == 'G' && buf[3] == 'B') { - // ARGB - return 1; - } - if (buf[0] == 'B' && buf[1] == 'M') { - // BMP - return 1; - } - if (!memcmp(buf, "farbfeld", 8)) { - // farbfeld - return 1; - } - if (buf[0] == 'G' && buf[1] == 'I' && buf[2] == 'F') { - // GIF - return 1; - } - if (buf[0] == 0x00 && buf[1] == 0x00 && buf[2] <= 0x02 && buf[3] == 0x00) { - // ICO - return 1; - } - if (!memcmp(buf, "FORM", 4)) { - // Amiga IFF ILBM - return 1; - } - if (buf[0] == 'P' && buf[1] >= '1' && buf[1] <= '7') { - // PNM et al. - return 1; - } - if (strstr(file->filename, ".tga")) { - // TGA - return 1; - } - if (!memcmp(buf, "II\x2a\x00", 4) || !memcmp(buf, "MM\x00\x2a", 4)) { - // TIFF - return 1; - } - if (!memcmp(buf, "RIFF", 4)) { - // might be webp - return 1; - } - if (!memcmp(buf + 4, "ftyphei", 7) || !memcmp(buf + 4, "ftypmif1", 8)) { - // HEIC/HEIF - note that this is only supported in imlib2-heic. Ordinary - // imlib2 releases do not support heic/heif images as of 2021-01. - return 1; - } - if ((buf[0] == 0xff && buf[1] == 0x0a) || !memcmp(buf, "\x00\x00\x00\x0cJXL \x0d\x0a\x87\x0a", 12)) { - // JXL - note that this is only supported in imlib2-jxl. Ordinary - // imlib2 releases do not support JXL images as of 2021-06. + if (getenv("FEH_SKIP_MAGIC")) { return 1; } - buf[15] = 0; - if (strstr((char *)buf, "XPM")) { - // XPM - return 1; + + if (!(magic = magic_open(MAGIC_MIME_TYPE | MAGIC_SYMLINK))) { + weprintf("unable to initialize magic library\n"); + return 0; } - if (strstr(file->filename, ".bz2") || strstr(file->filename, ".gz")) { - // Imlib2 supports compressed images. It relies on the filename to - // determine the appropriate loader and does not use magic bytes here. - return 1; + + if (magic_load(magic, NULL) != 0) { + weprintf("cannot load magic database: %s\n", magic_error(magic)); + magic_close(magic); + return 0; } - // moved to the end as this variable won't be set in most cases - if (getenv("FEH_SKIP_MAGIC")) { - return 1; + + mime_type = magic_file(magic, file->filename); + + if (mime_type) { + D(("file %s has mime type: %s\n", file->filename, mime_type)); + + if (strncmp(mime_type, "image/", 6) == 0) { + is_image = 1; + } + + /* imlib2 supports loading compressed images, let's have a look inside */ + if (strcmp(mime_type, "application/gzip") == 0 || + strcmp(mime_type, "application/x-bzip2") == 0 || + strcmp(mime_type, "application/x-xz") == 0) { + magic_setflags(magic, magic_getflags(magic) | MAGIC_COMPRESS); + mime_type = magic_file(magic, file->filename); + + if (mime_type) { + D(("uncompressed file %s has mime type: %s\n", file->filename, mime_type)); + + if (strncmp(mime_type, "image/", 6) == 0) { + is_image = 1; + } + } + } } - return 0; + + magic_close(magic); + + return is_image; +#else + (void)file; + return 1; +#endif } int feh_load_image(Imlib_Image * im, feh_file * file) |