From 0110e0a5d2efaf837f5c8627036d613d42b38160 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C5=99emysl=20Eric=20Janouch?=
Date: Wed, 29 Dec 2021 01:54:40 +0100
Subject: [PATCH] Check wide thumbnail metadata
---
fiv-thumbnail.c | 82 +++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 70 insertions(+), 12 deletions(-)
diff --git a/fiv-thumbnail.c b/fiv-thumbnail.c
index 24063f3..1d7ad2b 100644
--- a/fiv-thumbnail.c
+++ b/fiv-thumbnail.c
@@ -15,6 +15,8 @@
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
+#include "config.h"
+
#include
#include
#include
@@ -73,6 +75,14 @@ FivThumbnailSizeInfo
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#define THUMB_URI "Thumb::URI"
+#define THUMB_MTIME "Thumb::MTime"
+#define THUMB_SIZE "Thumb::Size"
+#define THUMB_IMAGE_WIDTH "Thumb::Image::Width"
+#define THUMB_IMAGE_HEIGHT "Thumb::Image::Height"
+#define THUMB_COLORSPACE "Thumb::ColorSpace"
+#define THUMB_COLORSPACE_SRGB "sRGB"
+
cairo_user_data_key_t fiv_thumbnail_key_lq;
static void
@@ -250,20 +260,20 @@ fiv_thumbnail_produce(GFile *target, FivThumbnailSize max_size, GError **error)
GString *thum = g_string_new("");
g_string_append_printf(
- thum, "%s%c%s%c", "Thumb::URI", 0, uri, 0);
+ thum, "%s%c%s%c", THUMB_URI, 0, uri, 0);
g_string_append_printf(
- thum, "%s%c%ld%c", "Thumb::Mtime", 0, (long) st.st_mtim.tv_sec, 0);
+ thum, "%s%c%ld%c", THUMB_MTIME, 0, (long) st.st_mtim.tv_sec, 0);
g_string_append_printf(
- thum, "%s%c%ld%c", "Thumb::Size", 0, (long) filesize, 0);
- g_string_append_printf(thum, "%s%c%d%c", "Thumb::Image::Width", 0,
+ thum, "%s%c%ld%c", THUMB_SIZE, 0, (long) filesize, 0);
+ g_string_append_printf(thum, "%s%c%d%c", THUMB_IMAGE_WIDTH, 0,
cairo_image_surface_get_width(surface), 0);
- g_string_append_printf(thum, "%s%c%d%c", "Thumb::Image::Height", 0,
+ g_string_append_printf(thum, "%s%c%d%c", THUMB_IMAGE_HEIGHT, 0,
cairo_image_surface_get_height(surface), 0);
// Without a CMM, no conversion is attempted.
if (sRGB) {
g_string_append_printf(
- thum, "%s%c%s%c", "Thumb::ColorSpace", 0, "sRGB", 0);
+ thum, "%s%c%s%c", THUMB_COLORSPACE, 0, THUMB_COLORSPACE_SRGB, 0);
}
for (int use = max_size; use >= FIV_THUMBNAIL_SIZE_MIN; use--) {
@@ -285,14 +295,62 @@ fiv_thumbnail_produce(GFile *target, FivThumbnailSize max_size, GError **error)
return TRUE;
}
+static bool
+check_wide_thumbnail_texts(GBytes *thum, const gchar *target, time_t mtime,
+ bool *sRGB)
+{
+ gsize len = 0;
+ const gchar *s = g_bytes_get_data(thum, &len), *end = s + len;
+
+ // Similar to PNG below, but we're following our own specification.
+ const gchar *key = NULL, *nul = NULL;
+ bool have_uri = false, have_mtime = false;
+ for (; (nul = memchr(s, '\0', end - s)); s = ++nul) {
+ if (!key) {
+ key = s;
+ continue;
+ } else if (!strcmp(key, THUMB_URI)) {
+ have_uri = true;
+ if (strcmp(target, s))
+ return false;
+ } else if (!strcmp(key, THUMB_MTIME)) {
+ have_mtime = true;
+ if (atol(s) != mtime)
+ return false;
+ } else if (!strcmp(key, THUMB_COLORSPACE))
+ *sRGB = !strcmp(s, THUMB_COLORSPACE_SRGB);
+
+ key = NULL;
+ }
+ return have_uri && have_mtime;
+}
+
static cairo_surface_t *
read_wide_thumbnail(
const gchar *path, const gchar *uri, time_t mtime, GError **error)
{
- // TODO(p): Validate fiv_io_key_thum.
- (void) uri;
- (void) mtime;
- return fiv_io_open(path, NULL, FALSE, error);
+ cairo_surface_t *surface = fiv_io_open(path, NULL, FALSE, error);
+ if (!surface)
+ return NULL;
+
+ bool sRGB = false;
+ GBytes *thum = cairo_surface_get_user_data(surface, &fiv_io_key_thum);
+ if (!thum) {
+ set_error(error, "not a thumbnail");
+ } else if (!check_wide_thumbnail_texts(thum, uri, mtime, &sRGB)) {
+ set_error(error, "mismatch");
+ } else {
+ // TODO(p): Add a function or a non-valueless define to check
+ // for CMM presence, then remove this ifdef.
+#ifdef HAVE_LCMS2
+ if (!sRGB)
+ mark_thumbnail_lq(surface);
+#endif // HAVE_LCMS2
+ return surface;
+ }
+
+ cairo_surface_destroy(surface);
+ return NULL;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -306,12 +364,12 @@ check_spng_thumbnail_texts(struct spng_text *texts, uint32_t texts_len,
bool need_uri = true, need_mtime = true;
for (uint32_t i = 0; i < texts_len; i++) {
struct spng_text *text = texts + i;
- if (!strcmp(text->keyword, "Thumb::URI")) {
+ if (!strcmp(text->keyword, THUMB_URI)) {
need_uri = false;
if (strcmp(target, text->text))
return false;
}
- if (!strcmp(text->keyword, "Thumb::MTime")) {
+ if (!strcmp(text->keyword, THUMB_MTIME)) {
need_mtime = false;
if (atol(text->text) != mtime)
return false;