summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2012-09-14 18:04:12 -0400
committerMatthias Clasen <mclasen@redhat.com>2012-09-14 18:09:46 -0400
commit68349864941597053c5bba8a909a9022d904fc0c (patch)
treea6383414c5e59f3adbe73dc0cc9c0e7b92542914
parentaf558883d38263536219f9db7aa00a243fd26fee (diff)
downloadgdk-pixbuf-68349864941597053c5bba8a909a9022d904fc0c.tar.gz
Make the tiff loader threadsafe
The reason why the tiff loader was marked as not threadsafe is that libtiff only has a global error handler; while we still have to set an error handler to keep libtiff from spamming stderr, we just give up on collecting any error messages from it, and we also give up on the illusion that we can push/pop error handlers. That doesn't work without a stack, so we just keep forcing our do-nothing error handler on without ever taking it back.
-rw-r--r--gdk-pixbuf/io-tiff.c198
1 files changed, 59 insertions, 139 deletions
diff --git a/gdk-pixbuf/io-tiff.c b/gdk-pixbuf/io-tiff.c
index 49eea8917..daf096a03 100644
--- a/gdk-pixbuf/io-tiff.c
+++ b/gdk-pixbuf/io-tiff.c
@@ -59,78 +59,19 @@ struct _TiffContext
guint pos;
};
-
-
-static char *global_error = NULL;
-static TIFFErrorHandler orig_error_handler = NULL;
-static TIFFErrorHandler orig_warning_handler = NULL;
-
static void
tiff_warning_handler (const char *mod, const char *fmt, va_list ap)
{
/* Don't print anything; we should not be dumping junk to
* stderr, since that may be bad for some apps.
*/
-
- /* libTIFF seems to occasionally warn about things that
- * are really errors, so maybe we should just call tiff_error_handler
- * here.
- */
-}
-
-static void
-tiff_error_handler (const char *mod, const char *fmt, va_list ap)
-{
- if (global_error) {
- /* Blah, loader called us twice */
- return;
- }
-
- global_error = g_strdup_vprintf (fmt, ap);
-}
-
-static void
-tiff_push_handlers (void)
-{
- if (global_error)
- g_warning ("TIFF loader left crufty global_error around, FIXME");
-
- orig_error_handler = TIFFSetErrorHandler (tiff_error_handler);
- orig_warning_handler = TIFFSetWarningHandler (tiff_warning_handler);
-}
-
-static void
-tiff_pop_handlers (void)
-{
- if (global_error)
- g_warning ("TIFF loader left crufty global_error around, FIXME");
-
- TIFFSetErrorHandler (orig_error_handler);
- TIFFSetWarningHandler (orig_warning_handler);
}
static void
-tiff_set_error (GError **error,
- int error_code,
- const char *msg)
+tiff_set_handlers (void)
{
- /* Take the error message from libtiff and merge it with
- * some context we provide.
- */
- if (global_error) {
- g_set_error (error,
- GDK_PIXBUF_ERROR,
- error_code,
- "%s%s%s", msg, ": ", global_error);
-
- g_free (global_error);
- global_error = NULL;
- }
- else {
- g_set_error_literal (error,
- GDK_PIXBUF_ERROR,
- error_code, msg);
- }
+ TIFFSetErrorHandler (tiff_warning_handler);
+ TIFFSetWarningHandler (tiff_warning_handler);
}
@@ -155,20 +96,20 @@ tiff_image_parse (TIFF *tiff, TiffContext *context, GError **error)
gint retval;
/* We're called with the lock held. */
-
- g_return_val_if_fail (global_error == NULL, NULL);
- if (!TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width) || global_error) {
- tiff_set_error (error,
- GDK_PIXBUF_ERROR_FAILED,
- _("Could not get image width (bad TIFF file)"));
+ if (!TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width)) {
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_FAILED,
+ _("Could not get image width (bad TIFF file)"));
return NULL;
}
- if (!TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height) || global_error) {
- tiff_set_error (error,
- GDK_PIXBUF_ERROR_FAILED,
- _("Could not get image height (bad TIFF file)"));
+ if (!TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height)) {
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_FAILED,
+ _("Could not get image height (bad TIFF file)"));
return NULL;
}
@@ -288,10 +229,11 @@ tiff_image_parse (TIFF *tiff, TiffContext *context, GError **error)
if (context && context->prepare_func)
(* context->prepare_func) (pixbuf, NULL, context->user_data);
- if (!TIFFReadRGBAImageOriented (tiff, width, height, (uint32 *)pixels, ORIENTATION_TOPLEFT, 1) || global_error) {
- tiff_set_error (error,
- GDK_PIXBUF_ERROR_FAILED,
- _("Failed to load RGB data from TIFF file"));
+ if (!TIFFReadRGBAImageOriented (tiff, width, height, (uint32 *)pixels, ORIENTATION_TOPLEFT, 1)) {
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_FAILED,
+ _("Failed to load RGB data from TIFF file"));
g_object_unref (pixbuf);
return NULL;
}
@@ -332,8 +274,8 @@ gdk_pixbuf__tiff_image_load (FILE *f, GError **error)
g_return_val_if_fail (f != NULL, NULL);
- tiff_push_handlers ();
-
+ tiff_set_handlers ();
+
fd = fileno (f);
/* On OSF, apparently fseek() works in some on-demand way, so
@@ -343,26 +285,18 @@ gdk_pixbuf__tiff_image_load (FILE *f, GError **error)
*/
lseek (fd, 0, SEEK_SET);
tiff = TIFFFdOpen (fd, "libpixbuf-tiff", "r");
-
- if (!tiff || global_error) {
- tiff_set_error (error,
- GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
- _("Failed to open TIFF image"));
- tiff_pop_handlers ();
+ if (!tiff) {
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("Failed to open TIFF image"));
return NULL;
}
pixbuf = tiff_image_parse (tiff, NULL, error);
-
+
TIFFClose (tiff);
- if (global_error) {
- tiff_set_error (error,
- GDK_PIXBUF_ERROR_FAILED,
- _("TIFFClose operation failed"));
- }
-
- tiff_pop_handlers ();
return pixbuf;
}
@@ -479,17 +413,18 @@ gdk_pixbuf__tiff_image_stop_load (gpointer data,
g_return_val_if_fail (data != NULL, FALSE);
- tiff_push_handlers ();
-
+ tiff_set_handlers ();
+
tiff = TIFFClientOpen ("libtiff-pixbuf", "r", data,
tiff_load_read, tiff_load_write,
tiff_load_seek, tiff_load_close,
tiff_load_size,
tiff_load_map_file, tiff_load_unmap_file);
- if (!tiff || global_error) {
- tiff_set_error (error,
- GDK_PIXBUF_ERROR_FAILED,
- _("Failed to load TIFF image"));
+ if (!tiff) {
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_FAILED,
+ _("Failed to load TIFF image"));
retval = FALSE;
} else {
GdkPixbuf *pixbuf;
@@ -498,27 +433,21 @@ gdk_pixbuf__tiff_image_stop_load (gpointer data,
if (pixbuf)
g_object_unref (pixbuf);
retval = pixbuf != NULL;
- if (global_error)
- {
- tiff_set_error (error,
- GDK_PIXBUF_ERROR_FAILED,
- _("Failed to load TIFF image"));
- tiff_pop_handlers ();
-
+ if (!retval && error && !*error) {
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_FAILED,
+ _("Failed to load TIFF image"));
retval = FALSE;
- }
+ }
}
if (tiff)
TIFFClose (tiff);
- g_assert (!global_error);
-
g_free (context->buffer);
g_free (context);
- tiff_pop_handlers ();
-
return retval;
}
@@ -533,7 +462,7 @@ make_available_at_least (TiffContext *context, guint needed)
guint new_size = 1;
while (new_size < need_alloc)
new_size *= 2;
-
+
new_buffer = g_try_realloc (context->buffer, new_size);
if (new_buffer) {
context->buffer = new_buffer;
@@ -553,6 +482,8 @@ gdk_pixbuf__tiff_image_load_increment (gpointer data, const guchar *buf,
g_return_val_if_fail (data != NULL, FALSE);
+ tiff_set_handlers ();
+
if (!make_available_at_least (context, size)) {
g_set_error_literal (error,
GDK_PIXBUF_ERROR,
@@ -676,7 +607,7 @@ gdk_pixbuf__tiff_image_save_to_callback (GdkPixbufSaveFunc save_func,
guchar *icc_profile = NULL;
gsize icc_profile_size = 0;
- tiff_push_handlers ();
+ tiff_set_handlers ();
context = create_save_context ();
tiff = TIFFClientOpen ("libtiff-pixbuf", "w", context,
@@ -685,13 +616,11 @@ gdk_pixbuf__tiff_image_save_to_callback (GdkPixbufSaveFunc save_func,
tiff_save_size,
NULL, NULL);
- if (!tiff || global_error) {
- tiff_set_error (error,
- GDK_PIXBUF_ERROR_FAILED,
- _("Failed to save TIFF image"));
-
- tiff_pop_handlers ();
-
+ if (!tiff) {
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_FAILED,
+ _("Failed to save TIFF image"));
free_save_context (context);
return FALSE;
}
@@ -721,9 +650,10 @@ gdk_pixbuf__tiff_image_save_to_callback (GdkPixbufSaveFunc save_func,
if (TIFFIsCODECConfigured (codec))
TIFFSetField (tiff, TIFFTAG_COMPRESSION, codec);
else {
- tiff_set_error (error,
- GDK_PIXBUF_ERROR_FAILED,
- _("TIFF compression doesn't refer to a valid codec."));
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_FAILED,
+ _("TIFF compression doesn't refer to a valid codec."));
retval = FALSE;
goto cleanup;
}
@@ -755,37 +685,27 @@ gdk_pixbuf__tiff_image_save_to_callback (GdkPixbufSaveFunc save_func,
TIFFSetField (tiff, TIFFTAG_ICCPROFILE, icc_profile_size, icc_profile);
for (y = 0; y < height; y++) {
- if (TIFFWriteScanline (tiff, pixels + y * rowstride, y, 0) == -1 ||
- global_error)
+ if (TIFFWriteScanline (tiff, pixels + y * rowstride, y, 0) == -1)
break;
}
- if (global_error) {
- tiff_set_error (error,
- GDK_PIXBUF_ERROR_FAILED,
- _("Failed to write TIFF data"));
-
+ if (y < height) {
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_FAILED,
+ _("Failed to write TIFF data"));
TIFFClose (tiff);
retval = FALSE;
goto cleanup;
}
TIFFClose (tiff);
- if (global_error) {
- tiff_set_error (error,
- GDK_PIXBUF_ERROR_FAILED,
- _("TIFFClose operation failed"));
- retval = FALSE;
- goto cleanup;
- }
-
/* Now call the callback */
retval = save_func (context->buffer, context->used, error, user_data);
cleanup:
g_free (icc_profile);
- tiff_pop_handlers ();
free_save_context (context);
return retval;
}
@@ -869,6 +789,6 @@ MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
info->mime_types = mime_types;
info->extensions = extensions;
/* not threadsafe, due to the error handler handling */
- info->flags = GDK_PIXBUF_FORMAT_WRITABLE;
+ info->flags = GDK_PIXBUF_FORMAT_WRITABLE | GDK_PIXBUF_FORMAT_THREADSAFE;
info->license = "LGPL";
}