Loading README.md +2 −0 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -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 | Loading config.mk +6 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ curl ?= 1 debug ?= 0 exif ?= 0 help ?= 0 magic ?= 1 mkstemps ?= 1 verscmp ?= 1 xinerama ?= 1 Loading Loading @@ -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 Loading src/feh.h +4 −0 Original line number Diff line number Diff line Loading @@ -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); Loading src/imlib.c +64 −82 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading @@ -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 if (!magic) { 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; magic_setflags(magic, MAGIC_MIME_TYPE | MAGIC_SYMLINK | magic_flags); mime_type = magic_file(magic, file->filename); if (!mime_type) { return 0; } 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. D(("file %s has mime type: %s\n", file->filename, mime_type)); if (strncmp(mime_type, "image/", 6) == 0) { 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; /* no infinite loop on compressed content, please */ if (magic_flags) { return 0; } buf[15] = 0; if (strstr((char *)buf, "XPM")) { // XPM 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); } 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; return 0; } // moved to the end as this variable won't be set in most cases if (getenv("FEH_SKIP_MAGIC")) { #else int feh_is_image(__attribute__((unused)) feh_file * file, __attribute__((unused)) int magic_flags) { return 1; } return 0; } #endif int feh_load_image(Imlib_Image * im, feh_file * file) { Loading @@ -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; Loading src/main.c +9 −0 Original line number Diff line number Diff line Loading @@ -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(); Loading Loading @@ -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 Loading Loading
README.md +2 −0 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -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 | Loading
config.mk +6 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ curl ?= 1 debug ?= 0 exif ?= 0 help ?= 0 magic ?= 1 mkstemps ?= 1 verscmp ?= 1 xinerama ?= 1 Loading Loading @@ -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 Loading
src/feh.h +4 −0 Original line number Diff line number Diff line Loading @@ -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); Loading
src/imlib.c +64 −82 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading @@ -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 if (!magic) { 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; magic_setflags(magic, MAGIC_MIME_TYPE | MAGIC_SYMLINK | magic_flags); mime_type = magic_file(magic, file->filename); if (!mime_type) { return 0; } 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. D(("file %s has mime type: %s\n", file->filename, mime_type)); if (strncmp(mime_type, "image/", 6) == 0) { 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; /* no infinite loop on compressed content, please */ if (magic_flags) { return 0; } buf[15] = 0; if (strstr((char *)buf, "XPM")) { // XPM 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); } 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; return 0; } // moved to the end as this variable won't be set in most cases if (getenv("FEH_SKIP_MAGIC")) { #else int feh_is_image(__attribute__((unused)) feh_file * file, __attribute__((unused)) int magic_flags) { return 1; } return 0; } #endif int feh_load_image(Imlib_Image * im, feh_file * file) { Loading @@ -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; Loading
src/main.c +9 −0 Original line number Diff line number Diff line Loading @@ -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(); Loading Loading @@ -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 Loading