summaryrefslogtreecommitdiff
path: root/src/imlib.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/imlib.c')
-rw-r--r--src/imlib.c193
1 files changed, 103 insertions, 90 deletions
diff --git a/src/imlib.c b/src/imlib.c
index ea2f49c..143807d 100644
--- a/src/imlib.c
+++ b/src/imlib.c
@@ -1,7 +1,7 @@
/* imlib.c
Copyright (C) 1999-2003 Tom Gilbert.
-Copyright (C) 2010-2020 Daniel Friesel.
+Copyright (C) 2010-2020 Birte Kristina Friesel.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
@@ -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;
@@ -227,6 +233,14 @@ void feh_print_load_error(char *file, winwidget w, Imlib_Load_Error err, enum fe
case IMLIB_LOAD_ERROR_OUT_OF_DISK_SPACE:
im_weprintf(w, "%s - Cannot write - out of disk space", file);
break;
+#if defined(IMLIB2_VERSION_MAJOR) && defined(IMLIB2_VERSION_MINOR) && (IMLIB2_VERSION_MAJOR > 1 || IMLIB2_VERSION_MINOR > 7)
+ case IMLIB_LOAD_ERROR_IMAGE_READ:
+ im_weprintf(w, "%s - Invalid image file", file);
+ break;
+ case IMLIB_LOAD_ERROR_IMAGE_FRAME:
+ im_weprintf(w, "%s - Requested frame not in image", file);
+ break;
+#endif
default:
im_weprintf(w, "While loading %s - Unknown error (%d)",
file, err);
@@ -235,6 +249,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 +283,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.
+ if (!magic) {
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.
- 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 +348,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;
@@ -462,8 +452,9 @@ int feh_load_image(Imlib_Image * im, feh_file * file)
if (file->ed) {
ExifByteOrder byteOrder = exif_data_get_byte_order(file->ed);
ExifEntry *exifEntry = exif_data_get_entry(file->ed, EXIF_TAG_ORIENTATION);
- if (exifEntry && opt.auto_rotate)
+ if (exifEntry && opt.auto_rotate) {
orientation = exif_get_short(exifEntry->data, byteOrder);
+ }
}
if (orientation == 2)
@@ -869,15 +860,32 @@ static char *feh_http_load_image(char *url)
}
basename = strrchr(url, '/') + 1;
- tmpname = feh_unique_filename(path, basename);
- if (strlen(tmpname) > (NAME_MAX-6))
- tmpname[NAME_MAX-7] = '\0';
+#ifdef HAVE_MKSTEMPS
+ tmpname = estrjoin("_", "feh_curl_XXXXXX", basename, NULL);
- sfn = estrjoin("_", tmpname, "XXXXXX", NULL);
+ if (strlen(tmpname) > NAME_MAX) {
+ tmpname[NAME_MAX] = '\0';
+ }
+#else
+ if (strlen(basename) > NAME_MAX-7) {
+ tmpname = estrdup("feh_curl_XXXXXX");
+ } else {
+ tmpname = estrjoin("_", "feh_curl", basename, "XXXXXX", NULL);
+ }
+#endif
+
+ sfn = estrjoin("", path, tmpname, NULL);
free(tmpname);
+ D(("sfn is %s\n", sfn))
+
+#ifdef HAVE_MKSTEMPS
+ fd = mkstemps(sfn, strlen(basename) + 1);
+#else
fd = mkstemp(sfn);
+#endif
+
if (fd != -1) {
sfp = fdopen(fd, "w+");
if (sfp != NULL) {
@@ -886,8 +894,8 @@ static char *feh_http_load_image(char *url)
#endif
/*
* Do not allow requests to take longer than 30 minutes.
- * This should be sufficiently high to accomodate use cases with
- * unusually high latencies, while at the sime time avoiding
+ * This should be sufficiently high to accommodate use cases with
+ * unusually high latencies, while at the same time avoiding
* feh hanging indefinitely in unattended slideshows.
*/
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1800);
@@ -895,6 +903,7 @@ static char *feh_http_load_image(char *url)
curl_easy_setopt(curl, CURLOPT_WRITEDATA, sfp);
ebuff = emalloc(CURL_ERROR_SIZE);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, ebuff);
+ curl_easy_setopt(curl, CURLOPT_USERAGENT, PACKAGE "/" VERSION);
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
#if LIBCURL_VERSION_NUM >= 0x072000 /* 07.32.0 */
@@ -936,7 +945,11 @@ static char *feh_http_load_image(char *url)
close(fd);
}
} else {
+#ifdef HAVE_MKSTEMPS
+ weprintf("open url: mkstemps failed:");
+#else
weprintf("open url: mkstemp failed:");
+#endif
free(sfn);
}
curl_easy_cleanup(curl);