diff options
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | config.mk | 6 | ||||
-rw-r--r-- | src/feh.h | 4 | ||||
-rw-r--r-- | src/imlib.c | 146 | ||||
-rw-r--r-- | src/main.c | 9 |
5 files changed, 85 insertions, 82 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 @@ -145,6 +145,10 @@ void init_slideshow_mode(void); void init_list_mode(void); void init_loadables_mode(void); void init_unloadables_mode(void); +#ifdef HAVE_LIBMAGIC +void uninit_magic(void); +void init_magic(void); +#endif void feh_clean_exit(void); int feh_should_ignore_image(Imlib_Image * im); int feh_load_image(Imlib_Image * im, feh_file * file); diff --git a/src/imlib.c b/src/imlib.c index 6d709a2..0accbdc 100644 --- a/src/imlib.c +++ b/src/imlib.c @@ -44,6 +44,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "exif.h" #endif +#ifdef HAVE_LIBMAGIC +#include <magic.h> + +magic_t magic = NULL; +#endif + Display *disp = NULL; Visual *vis = NULL; Screen *scr = NULL; @@ -235,6 +241,33 @@ void feh_print_load_error(char *file, winwidget w, Imlib_Load_Error err, enum fe } } +#ifdef HAVE_LIBMAGIC +void uninit_magic(void) +{ + if (!magic) { + return; + } + + magic_close(magic); + magic = NULL; +} +void init_magic(void) +{ + if (getenv("FEH_SKIP_MAGIC")) { + return; + } + + if (!(magic = magic_open(MAGIC_NONE))) { + weprintf("unable to initialize magic library\n"); + return; + } + + if (magic_load(magic, NULL) != 0) { + weprintf("cannot load magic database: %s\n", magic_error(magic)); + uninit_magic(); + } +} + /* * This is a workaround for an Imlib2 regression, causing unloadable image * detection to be excessively slow (and, thus, causing feh to hang for a while @@ -242,99 +275,48 @@ 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) +int feh_is_image(feh_file * file, int magic_flags) { - 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); + const char * mime_type = NULL; - 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. + if (!magic) { 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. - return 1; + + magic_setflags(magic, MAGIC_MIME_TYPE | MAGIC_SYMLINK | magic_flags); + mime_type = magic_file(magic, file->filename); + + if (!mime_type) { + return 0; } - buf[15] = 0; - if (strstr((char *)buf, "XPM")) { - // XPM + + D(("file %s has mime type: %s\n", file->filename, mime_type)); + + if (strncmp(mime_type, "image/", 6) == 0) { return 1; } - 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; + + /* no infinite loop on compressed content, please */ + if (magic_flags) { + return 0; } - // moved to the end as this variable won't be set in most cases - if (getenv("FEH_SKIP_MAGIC")) { - return 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) { + return feh_is_image(file, MAGIC_COMPRESS); } + return 0; } +#else +int feh_is_image(__attribute__((unused)) feh_file * file, __attribute__((unused)) int magic_flags) +{ + return 1; +} +#endif int feh_load_image(Imlib_Image * im, feh_file * file) { @@ -358,7 +340,7 @@ int feh_load_image(Imlib_Image * im, feh_file * file) } } else { - if (feh_is_image(file)) { + if (feh_is_image(file, 0)) { *im = imlib_load_image_with_error_return(file->filename, &err); } else { feh_err = LOAD_ERROR_MAGICBYTES; @@ -49,6 +49,11 @@ int main(int argc, char **argv) srandom(getpid() * time(NULL) % ((unsigned int) -1)); setup_signal_handlers(); + +#ifdef HAVE_LIBMAGIC + init_magic(); +#endif + init_parse_options(argc, argv); init_imlib_fonts(); @@ -262,6 +267,10 @@ void feh_clean_exit(void) if(disp) XCloseDisplay(disp); +#ifdef HAVE_LIBMAGIC + uninit_magic(); +#endif + /* * Only restore the old terminal settings if * - we changed them in the first place |