Index: Makefile
===================================================================
--- Makefile (nonexistent)
+++ Makefile (revision 5)
@@ -0,0 +1,56 @@
+
+COMPONENT_TARGETS = $(HARDWARE_NOARCH)
+
+
+include ../../../../build-system/constants.mk
+
+
+url = $(DOWNLOAD_SERVER)/sources/GNOME/core/gdk-pixbuf
+
+versions = 2.42.9
+pkgname = gdk-pixbuf
+suffix = tar.xz
+
+tarballs = $(addsuffix .$(suffix), $(addprefix $(pkgname)-, $(versions)))
+sha1s = $(addsuffix .sha1sum, $(tarballs))
+
+patches = $(CURDIR)/patches/gdk-pixbuf-2.42.9-dirname.patch
+
+.NOTPARALLEL: $(patches)
+
+
+BUILD_TARGETS = $(tarballs) $(sha1s) $(patches)
+
+
+include ../../../../build-system/core.mk
+
+
+.PHONY: download_clean
+
+
+$(tarballs):
+ @echo -e "\n======= Downloading source tarballs =======" ; \
+ for tarball in $(tarballs) ; do \
+ echo "$(url)/$$tarball" | xargs -n 1 -P 100 wget $(WGET_OPTIONS) - & \
+ done ; wait
+
+$(sha1s): $(tarballs)
+ @for sha in $@ ; do \
+ echo -e "\n======= Downloading '$$sha' signature =======\n" ; \
+ echo "$(url)/$$sha" | xargs -n 1 -P 100 wget $(WGET_OPTIONS) - & wait %1 ; \
+ touch $$sha ; \
+ echo -e "\n======= Check the '$$sha' sha1sum =======\n" ; \
+ sha1sum --check $$sha ; ret="$$?" ; \
+ if [ "$$ret" == "1" ]; then \
+ echo -e "\n======= ERROR: Bad '$$sha' sha1sum =======\n" ; \
+ exit 1 ; \
+ fi ; \
+ done
+
+$(patches): $(sha1s)
+ @echo -e "\n======= Create Patches =======\n" ; \
+ ( cd create-2.42.9-dirname-patch ; ./create.patch.sh ) ; \
+ echo -e "\n"
+
+download_clean:
+ @rm -f $(tarballs) $(sha1s) $(patches)
Index: create-2.42.9-dirname-patch/create.patch.sh
===================================================================
--- create-2.42.9-dirname-patch/create.patch.sh (nonexistent)
+++ create-2.42.9-dirname-patch/create.patch.sh (revision 5)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+VERSION=2.42.9
+
+tar --files-from=file.list -xJvf ../gdk-pixbuf-$VERSION.tar.xz
+mv gdk-pixbuf-$VERSION gdk-pixbuf-$VERSION-orig
+
+cp -rf ./gdk-pixbuf-$VERSION-new ./gdk-pixbuf-$VERSION
+
+diff -b --unified -Nr gdk-pixbuf-$VERSION-orig gdk-pixbuf-$VERSION > gdk-pixbuf-$VERSION-dirname.patch
+
+mv gdk-pixbuf-$VERSION-dirname.patch ../patches
+
+rm -rf ./gdk-pixbuf-$VERSION
+rm -rf ./gdk-pixbuf-$VERSION-orig
Property changes on: create-2.42.9-dirname-patch/create.patch.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: create-2.42.9-dirname-patch/file.list
===================================================================
--- create-2.42.9-dirname-patch/file.list (nonexistent)
+++ create-2.42.9-dirname-patch/file.list (revision 5)
@@ -0,0 +1,2 @@
+gdk-pixbuf-2.42.9/gdk-pixbuf/gdk-pixbuf-io.c
+gdk-pixbuf-2.42.9/gdk-pixbuf/queryloaders.c
Index: create-2.42.9-dirname-patch/gdk-pixbuf-2.42.9-new/gdk-pixbuf/gdk-pixbuf-io.c
===================================================================
--- create-2.42.9-dirname-patch/gdk-pixbuf-2.42.9-new/gdk-pixbuf/gdk-pixbuf-io.c (nonexistent)
+++ create-2.42.9-dirname-patch/gdk-pixbuf-2.42.9-new/gdk-pixbuf/gdk-pixbuf-io.c (revision 5)
@@ -0,0 +1,3526 @@
+/* GdkPixbuf library - Main loading interface.
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Miguel de Icaza <miguel@gnu.org>
+ * Federico Mena-Quintero <federico@gimp.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#include "gdk-pixbuf-private.h"
+#include "gdk-pixbuf-loader.h"
+#include "gdk-pixdata.h"
+
+#include <glib/gstdio.h>
+
+#ifdef G_OS_WIN32
+#define STRICT
+#include <windows.h>
+#undef STRICT
+#endif
+#ifdef OS_DARWIN
+#include <mach-o/dyld.h>
+#endif
+
+/**
+ * GdkPixbufModule:
+ * @module_name: the name of the module, usually the same as the
+ * usual file extension for images of this type, eg. "xpm", "jpeg" or "png".
+ * @module_path: the path from which the module is loaded.
+ * @module: the loaded `GModule`.
+ * @info: a `GdkPixbufFormat` holding information about the module.
+ * @load: loads an image from a file.
+ * @load_xpm_data: loads an image from data in memory.
+ * @begin_load: begins an incremental load.
+ * @stop_load: stops an incremental load.
+ * @load_increment: continues an incremental load.
+ * @load_animation: loads an animation from a file.
+ * @save: saves a `GdkPixbuf` to a file.
+ * @save_to_callback: saves a `GdkPixbuf` by calling the given `GdkPixbufSaveFunc`.
+ * @is_save_option_supported: returns whether a save option key is supported by the module
+ *
+ * A `GdkPixbufModule` contains the necessary functions to load and save
+ * images in a certain file format.
+ *
+ * If `GdkPixbuf` has been compiled with `GModule` support, it can be extended
+ * by modules which can load (and perhaps also save) new image and animation
+ * formats.
+ *
+ * ## Implementing modules
+ *
+ * The `GdkPixbuf` interfaces needed for implementing modules are contained in
+ * `gdk-pixbuf-io.h` (and `gdk-pixbuf-animation.h` if the module supports
+ * animations). They are not covered by the same stability guarantees as the
+ * regular GdkPixbuf API. To underline this fact, they are protected by the
+ * `GDK_PIXBUF_ENABLE_BACKEND` pre-processor symbol.
+ *
+ * Each loadable module must contain a `GdkPixbufModuleFillVtableFunc` function
+ * named `fill_vtable`, which will get called when the module
+ * is loaded and must set the function pointers of the `GdkPixbufModule`.
+ *
+ * In order to make format-checking work before actually loading the modules
+ * (which may require calling `dlopen` to load image libraries), modules export
+ * their signatures (and other information) via the `fill_info` function. An
+ * external utility, `gdk-pixbuf-query-loaders`, uses this to create a text
+ * file containing a list of all available loaders and their signatures.
+ * This file is then read at runtime by `GdkPixbuf` to obtain the list of
+ * available loaders and their signatures.
+ *
+ * Modules may only implement a subset of the functionality available via
+ * `GdkPixbufModule`. If a particular functionality is not implemented, the
+ * `fill_vtable` function will simply not set the corresponding
+ * function pointers of the `GdkPixbufModule` structure. If a module supports
+ * incremental loading (i.e. provides `begin_load`, `stop_load` and
+ * `load_increment`), it doesn't have to implement `load`, since `GdkPixbuf`
+ * can supply a generic `load` implementation wrapping the incremental loading.
+ *
+ * ## Installing modules
+ *
+ * Installing a module is a two-step process:
+ *
+ * - copy the module file(s) to the loader directory (normally
+ * `$libdir/gdk-pixbuf-2.0/$version/loaders`, unless overridden by the
+ * environment variable `GDK_PIXBUF_MODULEDIR`)
+ * - call `gdk-pixbuf-query-loaders` to update the module file (normally
+ * `$libdir/gdk-pixbuf-2.0/$version/loaders.cache`, unless overridden
+ * by the environment variable `GDK_PIXBUF_MODULE_FILE`)
+ */
+
+static gint
+format_check (GdkPixbufModule *module, guchar *buffer, int size)
+{
+ int i, j;
+ gchar m;
+ GdkPixbufModulePattern *pattern;
+ gboolean anchored;
+ guchar *prefix;
+ gchar *mask;
+
+ for (pattern = module->info->signature; pattern->prefix; pattern++) {
+ if (pattern->mask && pattern->mask[0] == '*') {
+ prefix = (guchar *)pattern->prefix + 1;
+ mask = pattern->mask + 1;
+ anchored = FALSE;
+ }
+ else {
+ prefix = (guchar *)pattern->prefix;
+ mask = pattern->mask;
+ anchored = TRUE;
+ }
+ for (i = 0; i < size; i++) {
+ for (j = 0; i + j < size && prefix[j] != 0; j++) {
+ m = mask ? mask[j] : ' ';
+ if (m == ' ') {
+ if (buffer[i + j] != prefix[j])
+ break;
+ }
+ else if (m == '!') {
+ if (buffer[i + j] == prefix[j])
+ break;
+ }
+ else if (m == 'z') {
+ if (buffer[i + j] != 0)
+ break;
+ }
+ else if (m == 'n') {
+ if (buffer[i + j] == 0)
+ break;
+ }
+ }
+
+ if (prefix[j] == 0)
+ return pattern->relevance;
+
+ if (anchored)
+ break;
+ }
+ }
+ return 0;
+}
+
+G_LOCK_DEFINE_STATIC (init_lock);
+
+static gboolean file_formats_inited;
+static GSList *file_formats = NULL;
+
+static gboolean gdk_pixbuf_io_init (void);
+
+static GSList *
+get_file_formats (void)
+{
+ G_LOCK (init_lock);
+ if (file_formats == NULL ||
+ !file_formats_inited)
+ file_formats_inited = gdk_pixbuf_io_init ();
+ G_UNLOCK (init_lock);
+
+ return file_formats;
+}
+
+#ifdef GDK_PIXBUF_RELOCATABLE // implies that gdk-pixbuf is built as a dll on windows
+
+#ifdef G_OS_WIN32
+
+/* DllMain function needed to tuck away the gdk-pixbuf DLL handle */
+
+static HMODULE gdk_pixbuf_dll;
+
+BOOL WINAPI
+DllMain (HINSTANCE hinstDLL,
+ DWORD fdwReason,
+ LPVOID lpvReserved)
+{
+ switch (fdwReason) {
+ case DLL_PROCESS_ATTACH:
+ gdk_pixbuf_dll = (HMODULE) hinstDLL;
+ break;
+ }
+
+ return TRUE;
+}
+#endif
+
+gchar *
+gdk_pixbuf_get_toplevel (void)
+{
+ static gchar *toplevel = NULL;
+
+ if (toplevel == NULL) {
+#if defined(G_OS_WIN32)
+ toplevel = g_win32_get_package_installation_directory_of_module (gdk_pixbuf_dll);
+#elif defined(OS_DARWIN)
+ char pathbuf[PATH_MAX + 1];
+ uint32_t bufsize = sizeof(pathbuf);
+ gchar *bin_dir;
+
+ _NSGetExecutablePath(pathbuf, &bufsize);
+ bin_dir = g_path_get_dirname(pathbuf);
+ toplevel = g_build_path (G_DIR_SEPARATOR_S, bin_dir, "..", NULL);
+ g_free (bin_dir);
+#elif defined (OS_LINUX)
+ gchar *exe_path, *bin_dir;
+
+ exe_path = g_file_read_link ("/proc/self/exe", NULL);
+ bin_dir = g_path_get_dirname(exe_path);
+ toplevel = g_build_path (G_DIR_SEPARATOR_S, bin_dir, "..", NULL);
+ g_free (exe_path);
+ g_free (bin_dir);
+#else
+#error "Relocations not supported for this platform"
+#endif
+ }
+ return toplevel;
+}
+
+#endif /* GDK_PIXBUF_RELOCATABLE */
+
+
+#ifdef USE_GMODULE
+
+static gboolean
+scan_string (const char **pos, GString *out)
+{
+ const char *p = *pos, *q = *pos;
+ char *tmp, *tmp2;
+ gboolean quoted;
+
+ while (g_ascii_isspace (*p))
+ p++;
+
+ if (!*p)
+ return FALSE;
+ else if (*p == '"') {
+ p++;
+ quoted = FALSE;
+ for (q = p; (*q != '"') || quoted; q++) {
+ if (!*q)
+ return FALSE;
+ quoted = (*q == '\\') && !quoted;
+ }
+
+ tmp = g_strndup (p, q - p);
+ tmp2 = g_strcompress (tmp);
+ g_string_truncate (out, 0);
+ g_string_append (out, tmp2);
+ g_free (tmp);
+ g_free (tmp2);
+ }
+
+ q++;
+ *pos = q;
+
+ return TRUE;
+}
+
+static gboolean
+scan_int (const char **pos, int *out)
+{
+ int i = 0;
+ char buf[32];
+ const char *p = *pos;
+
+ while (g_ascii_isspace (*p))
+ p++;
+
+ if (*p < '0' || *p > '9')
+ return FALSE;
+
+ while ((*p >= '0') && (*p <= '9') && i < sizeof (buf)) {
+ buf[i] = *p;
+ i++;
+ p++;
+ }
+
+ if (i == sizeof (buf))
+ return FALSE;
+ else
+ buf[i] = '\0';
+
+ *out = atoi (buf);
+
+ *pos = p;
+
+ return TRUE;
+}
+
+static gboolean
+skip_space (const char **pos)
+{
+ const char *p = *pos;
+
+ while (g_ascii_isspace (*p))
+ p++;
+
+ *pos = p;
+
+ return !(*p == '\0');
+}
+
+#ifdef GDK_PIXBUF_RELOCATABLE
+
+static char *
+get_libdir (void)
+{
+ static char *libdir = NULL;
+
+ if (libdir == NULL)
+ libdir = g_build_filename (gdk_pixbuf_get_toplevel (), "lib", NULL);
+
+ return libdir;
+}
+
+#undef GDK_PIXBUF_LIBDIR
+#define GDK_PIXBUF_LIBDIR get_libdir()
+
+#endif /* GDK_PIXBUF_RELOCATABLE */
+
+/* In case we have a relative module path in the loaders cache
+ * prepend the toplevel dir */
+static gchar *
+build_module_path (const gchar *path)
+{
+#ifdef GDK_PIXBUF_RELOCATABLE
+ if (g_path_is_absolute (path)) {
+ return g_strdup (path);
+ } else {
+ return g_build_filename (gdk_pixbuf_get_toplevel (), path, NULL);
+ }
+#else
+ return g_strdup (path);
+#endif
+}
+
+static gchar *
+gdk_pixbuf_get_module_file (void)
+{
+ gchar *result = g_strdup (g_getenv ("GDK_PIXBUF_MODULE_FILE"));
+
+ if (!result)
+ result = g_build_filename (GDK_PIXBUF_LIBDIR, "gdk-pixbuf-2.0", GDK_PIXBUF_BINARY_VERSION, "loaders.cache", NULL);
+
+ return result;
+}
+
+#endif /* USE_GMODULE */
+
+
+static gboolean
+gdk_pixbuf_load_module_unlocked (GdkPixbufModule *image_module,
+ GError **error);
+
+static gboolean
+gdk_pixbuf_io_init_modules (const char *filename,
+ GError **error)
+{
+#ifdef USE_GMODULE
+ GIOChannel *channel;
+ gchar *line_buf;
+ gsize term;
+ GString *tmp_buf = g_string_new (NULL);
+ gboolean have_error = FALSE;
+ GdkPixbufModule *module = NULL;
+ int flags = 0;
+ int n_patterns = 0;
+ GdkPixbufModulePattern *pattern;
+ GError *local_error = NULL;
+ guint num_formats;
+
+ channel = g_io_channel_new_file (filename, "r", &local_error);
+ if (!channel) {
+ char *filename_utf8 = g_filename_display_name (filename);
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ "Cannot open pixbuf loader module file '%s': %s\n\n"
+ "This likely means that your installation is broken.\n"
+ "Try running the command\n"
+ " gdk-pixbuf-query-loaders > %s\n"
+ "to make things work again for the time being.",
+ filename_utf8, local_error->message, filename_utf8);
+ g_clear_error (&local_error);
+ g_string_free (tmp_buf, TRUE);
+ g_free (filename_utf8);
+ return FALSE;
+ }
+
+ num_formats = g_slist_length (file_formats);
+
+ while (!have_error && g_io_channel_read_line (channel, &line_buf, NULL, &term, NULL) == G_IO_STATUS_NORMAL) {
+ const char *p;
+
+ p = line_buf;
+
+ line_buf[term] = 0;
+
+ if (!skip_space (&p)) {
+ /* Blank line marking the end of a module */
+ if (module && *p != '#') {
+ file_formats = g_slist_prepend (file_formats, module);
+ module = NULL;
+ }
+
+ goto next_line;
+ }
+
+ if (*p == '#')
+ goto next_line;
+
+ if (!module) {
+ /* Read a module location */
+ module = g_new0 (GdkPixbufModule, 1);
+ n_patterns = 0;
+
+ if (!scan_string (&p, tmp_buf)) {
+ g_warning ("Error parsing loader info in '%s'\n %s",
+ filename, line_buf);
+ have_error = TRUE;
+ }
+ module->module_path = build_module_path (tmp_buf->str);
+ }
+ else if (!module->module_name) {
+ module->info = g_new0 (GdkPixbufFormat, 1);
+ if (!scan_string (&p, tmp_buf)) {
+ g_warning ("Error parsing loader info in '%s'\n %s",
+ filename, line_buf);
+ have_error = TRUE;
+ }
+ module->info->name = g_strdup (tmp_buf->str);
+ module->module_name = module->info->name;
+
+ flags = 0;
+ if (!scan_int (&p, &flags)) {
+ g_warning ("Error parsing loader info in '%s'\n %s",
+ filename, line_buf);
+ have_error = TRUE;
+ }
+ module->info->flags = flags;
+
+ if (!scan_string (&p, tmp_buf)) {
+ g_warning ("Error parsing loader info in '%s'\n %s",
+ filename, line_buf);
+ have_error = TRUE;
+ }
+ if (tmp_buf->str[0] != 0)
+ module->info->domain = g_strdup (tmp_buf->str);
+
+ if (!scan_string (&p, tmp_buf)) {
+ g_warning ("Error parsing loader info in '%s'\n %s",
+ filename, line_buf);
+ have_error = TRUE;
+ }
+ module->info->description = g_strdup (tmp_buf->str);
+
+ if (scan_string (&p, tmp_buf)) {
+ module->info->license = g_strdup (tmp_buf->str);
+ }
+ }
+ else if (!module->info->mime_types) {
+ int n = 1;
+ module->info->mime_types = g_new0 (gchar*, 1);
+ while (scan_string (&p, tmp_buf)) {
+ if (tmp_buf->str[0] != 0) {
+ module->info->mime_types =
+ g_realloc (module->info->mime_types, (n + 1) * sizeof (gchar*));
+ module->info->mime_types[n - 1] = g_strdup (tmp_buf->str);
+ module->info->mime_types[n] = NULL;
+ n++;
+ }
+ }
+ }
+ else if (!module->info->extensions) {
+ int n = 1;
+ module->info->extensions = g_new0 (gchar*, 1);
+ while (scan_string (&p, tmp_buf)) {
+ if (tmp_buf->str[0] != 0) {
+ module->info->extensions =
+ g_realloc (module->info->extensions, (n + 1) * sizeof (gchar*));
+ module->info->extensions[n - 1] = g_strdup (tmp_buf->str);
+ module->info->extensions[n] = NULL;
+ n++;
+ }
+ }
+ }
+ else {
+ n_patterns++;
+ module->info->signature = (GdkPixbufModulePattern *)
+ g_realloc (module->info->signature, (n_patterns + 1) * sizeof (GdkPixbufModulePattern));
+ pattern = module->info->signature + n_patterns;
+ pattern->prefix = NULL;
+ pattern->mask = NULL;
+ pattern->relevance = 0;
+ pattern--;
+ if (!scan_string (&p, tmp_buf))
+ goto context_error;
+ pattern->prefix = g_strdup (tmp_buf->str);
+
+ if (!scan_string (&p, tmp_buf))
+ goto context_error;
+ if (*tmp_buf->str)
+ pattern->mask = g_strdup (tmp_buf->str);
+ else
+ pattern->mask = NULL;
+
+ if (!scan_int (&p, &pattern->relevance))
+ goto context_error;
+
+ goto next_line;
+
+ context_error:
+ g_free (pattern->prefix);
+ g_free (pattern->mask);
+ g_free (pattern);
+ g_warning ("Error parsing loader info in '%s'\n %s",
+ filename, line_buf);
+ have_error = TRUE;
+ }
+ next_line:
+ g_free (line_buf);
+ }
+ g_string_free (tmp_buf, TRUE);
+ g_io_channel_unref (channel);
+
+ if (g_slist_length (file_formats) <= num_formats) {
+ char *filename_utf8 = g_filename_display_name (filename);
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_INITIALIZED,
+ "No new GdkPixbufModule loaded from '%s'",
+ filename_utf8);
+ g_free (filename_utf8);
+ return FALSE;
+ }
+#endif
+ return TRUE;
+}
+
+/**
+ * gdk_pixbuf_init_modules:
+ * @path: Path to directory where the `loaders.cache` is installed
+ * @error: return location for a `GError`
+ *
+ * Initalizes the gdk-pixbuf loader modules referenced by the `loaders.cache`
+ * file present inside that directory.
+ *
+ * This is to be used by applications that want to ship certain loaders
+ * in a different location from the system ones.
+ *
+ * This is needed when the OS or runtime ships a minimal number of loaders
+ * so as to reduce the potential attack surface of carefully crafted image
+ * files, especially for uncommon file types. Applications that require
+ * broader image file types coverage, such as image viewers, would be
+ * expected to ship the gdk-pixbuf modules in a separate location, bundled
+ * with the application in a separate directory from the OS or runtime-
+ * provided modules.
+ *
+ * Since: 2.40
+ */
+gboolean
+gdk_pixbuf_init_modules (const char *path,
+ GError **error)
+{
+ char *filename;
+ gboolean ret;
+
+ g_return_val_if_fail (path != NULL, FALSE);
+ filename = g_build_filename (path, "loaders.cache", NULL);
+ ret = gdk_pixbuf_io_init_modules (filename, error);
+ g_free (filename);
+ return ret;
+}
+
+static void
+gdk_pixbuf_io_init_builtin (void)
+{
+#define load_one_builtin_module(format) G_STMT_START { \
+ GdkPixbufModule *__builtin_module = g_new0 (GdkPixbufModule, 1); \
+ __builtin_module->module_name = #format; \
+ if (gdk_pixbuf_load_module_unlocked (__builtin_module, NULL)) \
+ file_formats = g_slist_prepend (file_formats, __builtin_module); \
+ else \
+ g_free (__builtin_module); } G_STMT_END
+
+#ifdef INCLUDE_ani
+ load_one_builtin_module (ani);
+#endif
+#ifdef INCLUDE_png
+ load_one_builtin_module (png);
+#endif
+#ifdef INCLUDE_bmp
+ load_one_builtin_module (bmp);
+#endif
+#ifdef INCLUDE_gif
+ load_one_builtin_module (gif);
+#endif
+#ifdef INCLUDE_ico
+ load_one_builtin_module (ico);
+#endif
+#ifdef INCLUDE_jpeg
+ load_one_builtin_module (jpeg);
+#endif
+#ifdef INCLUDE_pnm
+ load_one_builtin_module (pnm);
+#endif
+#ifdef INCLUDE_tiff
+ load_one_builtin_module (tiff);
+#endif
+#ifdef INCLUDE_xpm
+ load_one_builtin_module (xpm);
+#endif
+#ifdef INCLUDE_xbm
+ load_one_builtin_module (xbm);
+#endif
+#ifdef INCLUDE_tga
+ load_one_builtin_module (tga);
+#endif
+#ifdef INCLUDE_icns
+ load_one_builtin_module (icns);
+#endif
+#ifdef INCLUDE_qtif
+ load_one_builtin_module (qtif);
+#endif
+#ifdef INCLUDE_gdiplus
+ /* We don't bother having the GDI+ loaders individually selectable
+ * for building in or not.
+ */
+ load_one_builtin_module (ico);
+ load_one_builtin_module (wmf);
+ load_one_builtin_module (emf);
+ load_one_builtin_module (bmp);
+ load_one_builtin_module (gif);
+ load_one_builtin_module (jpeg);
+ load_one_builtin_module (tiff);
+#endif
+#ifdef INCLUDE_gdip_png
+ /* Except the gdip-png loader which normally isn't built at all even */
+ load_one_builtin_module (png);
+#endif
+
+#undef load_one_builtin_module
+}
+
+static gboolean
+gdk_pixbuf_io_init (void)
+{
+ char *module_file;
+ gboolean ret;
+
+ gdk_pixbuf_io_init_builtin ();
+#ifdef USE_GMODULE
+ module_file = gdk_pixbuf_get_module_file ();
+#endif
+ ret = gdk_pixbuf_io_init_modules (module_file, NULL);
+ g_free (module_file);
+ return ret;
+}
+
+#define module(type) \
+ extern void _gdk_pixbuf__##type##_fill_info (GdkPixbufFormat *info); \
+ extern void _gdk_pixbuf__##type##_fill_vtable (GdkPixbufModule *module)
+
+module (png);
+module (jpeg);
+module (gif);
+module (ico);
+module (ani);
+module (xpm);
+module (tiff);
+module (pnm);
+module (bmp);
+module (xbm);
+module (tga);
+module (icns);
+module (qtif);
+module (gdip_ico);
+module (gdip_wmf);
+module (gdip_emf);
+module (gdip_bmp);
+module (gdip_gif);
+module (gdip_jpeg);
+module (gdip_png);
+module (gdip_tiff);
+
+#undef module
+
+/* actually load the image handler - gdk_pixbuf_get_module only get a */
+/* reference to the module to load, it doesn't actually load it */
+/* perhaps these actions should be combined in one function */
+static gboolean
+gdk_pixbuf_load_module_unlocked (GdkPixbufModule *image_module,
+ GError **error)
+{
+ GdkPixbufModuleFillInfoFunc fill_info = NULL;
+ GdkPixbufModuleFillVtableFunc fill_vtable = NULL;
+
+ if (image_module->module != NULL)
+ return TRUE;
+
+#define try_module(format,id) \
+ if (fill_info == NULL && \
+ strcmp (image_module->module_name, #format) == 0) { \
+ fill_info = _gdk_pixbuf__##id##_fill_info; \
+ fill_vtable = _gdk_pixbuf__##id##_fill_vtable; \
+ }
+
+#ifdef INCLUDE_gdiplus
+ try_module (ico,gdip_ico);
+ try_module (wmf,gdip_wmf);
+ try_module (emf,gdip_emf);
+ try_module (bmp,gdip_bmp);
+ try_module (gif,gdip_gif);
+ try_module (jpeg,gdip_jpeg);
+ try_module (tiff,gdip_tiff);
+#endif
+#ifdef INCLUDE_gdip_png
+ try_module (png,gdip_png);
+#endif
+#ifdef INCLUDE_png
+ try_module (png,png);
+#endif
+#ifdef INCLUDE_bmp
+ try_module (bmp,bmp);
+#endif
+#ifdef INCLUDE_gif
+ try_module (gif,gif);
+#endif
+#ifdef INCLUDE_ico
+ try_module (ico,ico);
+#endif
+#ifdef INCLUDE_ani
+ try_module (ani,ani);
+#endif
+#ifdef INCLUDE_jpeg
+ try_module (jpeg,jpeg);
+#endif
+#ifdef INCLUDE_pnm
+ try_module (pnm,pnm);
+#endif
+#ifdef INCLUDE_tiff
+ try_module (tiff,tiff);
+#endif
+#ifdef INCLUDE_xpm
+ try_module (xpm,xpm);
+#endif
+#ifdef INCLUDE_xbm
+ try_module (xbm,xbm);
+#endif
+#ifdef INCLUDE_tga
+ try_module (tga,tga);
+#endif
+#ifdef INCLUDE_icns
+ try_module (icns,icns);
+#endif
+#ifdef INCLUDE_qtif
+ try_module (qtif,qtif);
+#endif
+
+#undef try_module
+
+ if (fill_vtable) {
+ image_module->module = (void *) 1;
+ (* fill_vtable) (image_module);
+ if (image_module->info == NULL) {
+ image_module->info = g_new0 (GdkPixbufFormat, 1);
+ (* fill_info) (image_module->info);
+ }
+ return TRUE;
+ }
+ else
+#ifdef USE_GMODULE
+ {
+ char *path;
+ GModule *module;
+ gpointer sym;
+
+ path = image_module->module_path;
+ module = g_module_open (path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
+
+ if (!module) {
+ char *path_utf8 = g_filename_display_name (path);
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_FAILED,
+ _("Unable to load image-loading module: %s: %s"),
+ path_utf8, g_module_error ());
+ g_free (path_utf8);
+ return FALSE;
+ }
+
+ image_module->module = module;
+
+ if (g_module_symbol (module, "fill_vtable", &sym)) {
+ fill_vtable = (GdkPixbufModuleFillVtableFunc) sym;
+ (* fill_vtable) (image_module);
+ return TRUE;
+ } else {
+ char *path_utf8 = g_filename_display_name (path);
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_FAILED,
+ _("Image-loading module %s does not export the proper interface; perhaps it’s from a different gdk-pixbuf version?"),
+ path_utf8);
+ g_free (path_utf8);
+ return FALSE;
+ }
+ }
+#else
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+ _("Image type “%s” is not supported"),
+ image_module->module_name);
+ return FALSE;
+#endif /* !USE_GMODULE */
+}
+
+
+gboolean
+_gdk_pixbuf_load_module (GdkPixbufModule *image_module,
+ GError **error)
+{
+ gboolean ret;
+
+ G_LOCK (init_lock);
+
+ ret = gdk_pixbuf_load_module_unlocked (image_module, error);
+
+ G_UNLOCK (init_lock);
+
+ return ret;
+}
+
+
+
+GdkPixbufModule *
+_gdk_pixbuf_get_named_module (const char *name,
+ GError **error)
+{
+ GSList *modules;
+
+ for (modules = get_file_formats (); modules; modules = g_slist_next (modules)) {
+ GdkPixbufModule *module = (GdkPixbufModule *)modules->data;
+
+ if (module->info->disabled)
+ continue;
+
+ if (!strcmp (name, module->module_name))
+ return module;
+ }
+
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+ _("Image type “%s” is not supported"),
+ name);
+
+ return NULL;
+}
+
+GdkPixbufModule *
+_gdk_pixbuf_get_module (guchar *buffer, guint size,
+ const gchar *filename,
+ GError **error)
+{
+ GSList *modules;
+
+ GdkPixbufModule *selected = NULL;
+ gchar *display_name = NULL;
+#ifdef GDK_PIXBUF_USE_GIO_MIME
+ gchar *mime_type;
+ gchar **mimes;
+ gchar *type;
+ gint j;
+ gboolean uncertain;
+
+ mime_type = g_content_type_guess (NULL, buffer, size, &uncertain);
+ if ((uncertain || g_str_equal (mime_type, "text/plain") || g_str_equal (mime_type, "application/gzip")) && filename != NULL) {
+ g_free (mime_type);
+ mime_type = g_content_type_guess (filename, buffer, size, NULL);
+ }
+
+ for (modules = get_file_formats (); modules; modules = g_slist_next (modules)) {
+ GdkPixbufModule *module = (GdkPixbufModule *)modules->data;
+ GdkPixbufFormat *info = module->info;
+
+ if (info->disabled)
+ continue;
+
+ mimes = info->mime_types;
+ for (j = 0; mimes[j] != NULL; j++) {
+ type = g_content_type_from_mime_type (mimes[j]);
+ if (g_content_type_equals (type, mime_type)) {
+ g_free (type);
+ selected = module;
+ break;
+ }
+ g_free (type);
+ }
+
+ if (selected != NULL)
+ break;
+
+ /* Make sure the builtin GdkPixdata support works even without mime sniffing */
+ if (strcmp (info->name, "GdkPixdata") == 0 &&
+ format_check (module, buffer, size) == 100) {
+ selected = module;
+ break;
+ }
+ }
+ g_free (mime_type);
+#else
+ gint score, best = 0;
+
+ for (modules = get_file_formats (); modules; modules = g_slist_next (modules)) {
+ GdkPixbufModule *module = (GdkPixbufModule *)modules->data;
+
+ if (module->info->disabled)
+ continue;
+
+ score = format_check (module, buffer, size);
+ if (score > best) {
+ best = score;
+ selected = module;
+ }
+ if (score >= 100)
+ break;
+ }
+#endif
+
+ if (selected != NULL)
+ return selected;
+
+ if (filename)
+ {
+ display_name = g_filename_display_name (filename);
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+ _("Couldn’t recognize the image file format for file “%s”"),
+ display_name);
+ g_free (display_name);
+ }
+ else
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+ _("Unrecognized image file format"));
+
+
+ return NULL;
+}
+
+static
+GdkPixbufModule *
+_gdk_pixbuf_get_module_for_file (FILE *f, const gchar *filename, GError **error)
+{
+ guchar buffer[SNIFF_BUFFER_SIZE];
+ int size;
+
+ size = fread (&buffer, 1, sizeof (buffer), f);
+ if (size == 0) {
+ gchar *display_name;
+ display_name = g_filename_display_name (filename);
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("Image file “%s” contains no data"),
+ display_name);
+ g_free (display_name);
+ return NULL;
+ }
+
+ return _gdk_pixbuf_get_module (buffer, size, filename, error);
+}
+
+static void
+noop_size_notify (gint *width,
+ gint *height,
+ gpointer data)
+{
+}
+
+static void
+prepared_notify (GdkPixbuf *pixbuf,
+ GdkPixbufAnimation *anim,
+ gpointer user_data)
+{
+ if (pixbuf != NULL)
+ g_object_ref (pixbuf);
+ *((GdkPixbuf **)user_data) = pixbuf;
+}
+
+static void
+noop_updated_notify (GdkPixbuf *pixbuf,
+ int x,
+ int y,
+ int width,
+ int height,
+ gpointer user_data)
+{
+}
+
+static GdkPixbuf *
+generic_load_incrementally (GdkPixbufModule *module, FILE *f, GError **error)
+{
+ GdkPixbuf *pixbuf = NULL;
+ gpointer context;
+
+ context = module->begin_load (noop_size_notify, prepared_notify, noop_updated_notify, &pixbuf, error);
+
+ if (!context)
+ goto out;
+
+ while (!feof (f) && !ferror (f)) {
+ guchar buffer[LOAD_BUFFER_SIZE];
+ size_t length;
+
+ length = fread (buffer, 1, sizeof (buffer), f);
+ if (length > 0) {
+ if (!module->load_increment (context, buffer, length, error)) {
+ module->stop_load (context, NULL);
+ if (pixbuf != NULL) {
+ g_object_unref (pixbuf);
+ pixbuf = NULL;
+ }
+ goto out;
+ }
+ }
+ }
+
+ if (!module->stop_load (context, error)) {
+ if (pixbuf != NULL) {
+ g_object_unref (pixbuf);
+ pixbuf = NULL;
+ }
+ }
+
+out:
+ return pixbuf;
+}
+
+GdkPixbuf *
+_gdk_pixbuf_generic_image_load (GdkPixbufModule *module, FILE *f, GError **error)
+{
+ GdkPixbuf *pixbuf = NULL;
+
+ if (module->load != NULL) {
+ pixbuf = (* module->load) (f, error);
+ } else if (module->begin_load != NULL) {
+ pixbuf = generic_load_incrementally (module, f, error);
+ } else if (module->load_animation != NULL) {
+ GdkPixbufAnimation *animation;
+
+ animation = (* module->load_animation) (f, error);
+ if (animation != NULL) {
+ pixbuf = gdk_pixbuf_animation_get_static_image (animation);
+
+ g_object_ref (pixbuf);
+ g_object_unref (animation);
+ }
+ }
+
+ return pixbuf;
+}
+
+/**
+ * gdk_pixbuf_new_from_file: (constructor)
+ * @filename: (type filename): Name of file to load, in the GLib file
+ * name encoding
+ * @error: (out): Return location for an error
+ *
+ * Creates a new pixbuf by loading an image from a file.
+ *
+ * The file format is detected automatically.
+ *
+ * If `NULL` is returned, then @error will be set. Possible errors are:
+ *
+ * - the file could not be opened
+ * - there is no loader for the file's format
+ * - there is not enough memory to allocate the image buffer
+ * - the image buffer contains invalid data
+ *
+ * The error domains are `GDK_PIXBUF_ERROR` and `G_FILE_ERROR`.
+ *
+ * Return value: (transfer full) (nullable): A newly-created pixbuf
+ */
+GdkPixbuf *
+gdk_pixbuf_new_from_file (const char *filename,
+ GError **error)
+{
+ GdkPixbuf *pixbuf;
+ FILE *f;
+ GdkPixbufModule *image_module;
+
+ g_return_val_if_fail (filename != NULL, NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ f = g_fopen (filename, "rb");
+ if (!f) {
+ gint save_errno = errno;
+ gchar *display_name;
+ display_name = g_filename_display_name (filename);
+ g_set_error (error,
+ G_FILE_ERROR,
+ g_file_error_from_errno (save_errno),
+ _("Failed to open file “%s”: %s"),
+ display_name,
+ g_strerror (save_errno));
+ g_free (display_name);
+ return NULL;
+ }
+
+ image_module = _gdk_pixbuf_get_module_for_file (f, filename, error);
+ if (image_module == NULL) {
+ fclose (f);
+ return NULL;
+ }
+
+ if (!_gdk_pixbuf_load_module (image_module, error)) {
+ fclose (f);
+ return NULL;
+ }
+
+ fseek (f, 0, SEEK_SET);
+ pixbuf = _gdk_pixbuf_generic_image_load (image_module, f, error);
+ fclose (f);
+
+ if (pixbuf == NULL && error != NULL && *error == NULL) {
+
+ /* I don't trust these crufty longjmp()'ing image libs
+ * to maintain proper error invariants, and I don't
+ * want user code to segfault as a result. We need to maintain
+ * the invariant that error gets set if NULL is returned.
+ */
+
+ gchar *display_name;
+ display_name = g_filename_display_name (filename);
+ g_warning ("Bug! gdk-pixbuf loader '%s' didn't set an error on failure.", image_module->module_name);
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_FAILED,
+ _("Failed to load image “%s”: reason not known, probably a corrupt image file"),
+ display_name);
+ g_free (display_name);
+ } else if (error != NULL && *error != NULL) {
+ /* Add the filename to the error message */
+ GError *e = *error;
+ gchar *old;
+ gchar *display_name;
+
+ display_name = g_filename_display_name (filename);
+ old = e->message;
+ e->message = g_strdup_printf (_("Failed to load image “%s”: %s"),
+ display_name,
+ old);
+ g_free (old);
+ g_free (display_name);
+ }
+
+ return pixbuf;
+}
+
+#ifdef G_OS_WIN32
+
+/**
+ * gdk_pixbuf_new_from_file_utf8:
+ * @filename: (type filename): Name of file to load, in the GLib file name encoding
+ * @error: Return location for an error
+ *
+ * Same as gdk_pixbuf_new_from_file()
+ *
+ * Return value: A newly-created pixbuf with a reference count of 1, or `NULL` if
+ * any of several error conditions occurred: the file could not be opened,
+ * there was no loader for the file's format, there was not enough memory to
+ * allocate the image buffer, or the image file contained invalid data.
+ **/
+GdkPixbuf *
+gdk_pixbuf_new_from_file_utf8 (const char *filename,
+ GError **error)
+{
+ return gdk_pixbuf_new_from_file (filename, error);
+}
+
+#endif
+
+
+/**
+ * gdk_pixbuf_new_from_file_at_size: (constructor)
+ * @filename: (type filename): Name of file to load, in the GLib file
+ * name encoding
+ * @width: The width the image should have or -1 to not constrain the width
+ * @height: The height the image should have or -1 to not constrain the height
+ * @error: (out): Return location for an error
+ *
+ * Creates a new pixbuf by loading an image from a file.
+ *
+ * The file format is detected automatically.
+ *
+ * If `NULL` is returned, then @error will be set. Possible errors are:
+ *
+ * - the file could not be opened
+ * - there is no loader for the file's format
+ * - there is not enough memory to allocate the image buffer
+ * - the image buffer contains invalid data
+ *
+ * The error domains are `GDK_PIXBUF_ERROR` and `G_FILE_ERROR`.
+ *
+ * The image will be scaled to fit in the requested size, preserving
+ * the image's aspect ratio. Note that the returned pixbuf may be smaller
+ * than `width` x `height`, if the aspect ratio requires it. To load
+ * and image at the requested size, regardless of aspect ratio, use
+ * [ctor@GdkPixbuf.Pixbuf.new_from_file_at_scale].
+ *
+ * Return value: (transfer full) (nullable): A newly-created pixbuf
+ *
+ * Since: 2.4
+ **/
+GdkPixbuf *
+gdk_pixbuf_new_from_file_at_size (const char *filename,
+ int width,
+ int height,
+ GError **error)
+{
+ return gdk_pixbuf_new_from_file_at_scale (filename,
+ width, height,
+ TRUE, error);
+}
+
+#ifdef G_OS_WIN32
+
+/**
+ * gdk_pixbuf_new_from_file_at_size_utf8:
+ * @filename: (type filename): Name of file to load, in the GLib file name encoding
+ * @width: The width the image should have or -1 to not constrain the width
+ * @height: The height the image should have or -1 to not constrain the height
+ * @error: Return location for an error
+ *
+ * Same as gdk_pixbuf_new_from_file_at_size()
+ *
+ * Return value: A newly-created pixbuf with a reference count of 1, or
+ * `NULL` if any of several error conditions occurred: the file could not
+ * be opened, there was no loader for the file's format, there was not
+ * enough memory to allocate the image buffer, or the image file contained
+ * invalid data.
+ *
+ * Since: 2.4
+ **/
+GdkPixbuf *
+gdk_pixbuf_new_from_file_at_size_utf8 (const char *filename,
+ int width,
+ int height,
+ GError **error)
+{
+ return gdk_pixbuf_new_from_file_at_size (filename, width, height, error);
+}
+
+#endif
+
+typedef struct {
+ gint width;
+ gint height;
+ gboolean preserve_aspect_ratio;
+} AtScaleData;
+
+static void
+at_scale_data_async_data_free (AtScaleData *data)
+{
+ g_slice_free (AtScaleData, data);
+}
+
+static void
+at_scale_size_prepared_cb (GdkPixbufLoader *loader,
+ int width,
+ int height,
+ gpointer data)
+{
+ AtScaleData *info = data;
+
+ g_return_if_fail (width > 0 && height > 0);
+
+ if (info->preserve_aspect_ratio &&
+ (info->width > 0 || info->height > 0)) {
+ if (info->width < 0)
+ {
+ width = width * (double)info->height/(double)height;
+ height = info->height;
+ }
+ else if (info->height < 0)
+ {
+ height = height * (double)info->width/(double)width;
+ width = info->width;
+ }
+ else if ((double)height * (double)info->width >
+ (double)width * (double)info->height) {
+ width = 0.5 + (double)width * (double)info->height / (double)height;
+ height = info->height;
+ } else {
+ height = 0.5 + (double)height * (double)info->width / (double)width;
+ width = info->width;
+ }
+ } else {
+ if (info->width > 0)
+ width = info->width;
+ if (info->height > 0)
+ height = info->height;
+ }
+
+ width = MAX (width, 1);
+ height = MAX (height, 1);
+
+ gdk_pixbuf_loader_set_size (loader, width, height);
+}
+
+/**
+ * gdk_pixbuf_new_from_file_at_scale: (constructor)
+ * @filename: (type filename): Name of file to load, in the GLib file
+ * name encoding
+ * @width: The width the image should have or -1 to not constrain the width
+ * @height: The height the image should have or -1 to not constrain the height
+ * @preserve_aspect_ratio: `TRUE` to preserve the image's aspect ratio
+ * @error: Return location for an error
+ *
+ * Creates a new pixbuf by loading an image from a file.
+ *
+ * The file format is detected automatically.
+ *
+ * If `NULL` is returned, then @error will be set. Possible errors are:
+ *
+ * - the file could not be opened
+ * - there is no loader for the file's format
+ * - there is not enough memory to allocate the image buffer
+ * - the image buffer contains invalid data
+ *
+ * The error domains are `GDK_PIXBUF_ERROR` and `G_FILE_ERROR`.
+ *
+ * The image will be scaled to fit in the requested size, optionally preserving
+ * the image's aspect ratio.
+ *
+ * When preserving the aspect ratio, a `width` of -1 will cause the image
+ * to be scaled to the exact given height, and a `height` of -1 will cause
+ * the image to be scaled to the exact given width. When not preserving
+ * aspect ratio, a `width` or `height` of -1 means to not scale the image
+ * at all in that dimension. Negative values for `width` and `height` are
+ * allowed since 2.8.
+ *
+ * Return value: (transfer full) (nullable): A newly-created pixbuf
+ *
+ * Since: 2.6
+ **/
+GdkPixbuf *
+gdk_pixbuf_new_from_file_at_scale (const char *filename,
+ int width,
+ int height,
+ gboolean preserve_aspect_ratio,
+ GError **error)
+{
+
+ GdkPixbufLoader *loader;
+ GdkPixbuf *pixbuf;
+ guchar buffer[LOAD_BUFFER_SIZE];
+ int length;
+ FILE *f;
+ AtScaleData info;
+ GdkPixbufAnimation *animation;
+ GdkPixbufAnimationIter *iter;
+ gboolean has_frame;
+
+ g_return_val_if_fail (filename != NULL, NULL);
+ g_return_val_if_fail (width > 0 || width == -1, NULL);
+ g_return_val_if_fail (height > 0 || height == -1, NULL);
+
+ f = g_fopen (filename, "rb");
+ if (!f) {
+ gint save_errno = errno;
+ gchar *display_name = g_filename_display_name (filename);
+ g_set_error (error,
+ G_FILE_ERROR,
+ g_file_error_from_errno (save_errno),
+ _("Failed to open file “%s”: %s"),
+ display_name,
+ g_strerror (save_errno));
+ g_free (display_name);
+ return NULL;
+ }
+
+ loader = _gdk_pixbuf_loader_new_with_filename (filename);
+
+ info.width = width;
+ info.height = height;
+ info.preserve_aspect_ratio = preserve_aspect_ratio;
+
+ g_signal_connect (loader, "size-prepared",
+ G_CALLBACK (at_scale_size_prepared_cb), &info);
+
+ has_frame = FALSE;
+ while (!has_frame && !feof (f) && !ferror (f)) {
+ length = fread (buffer, 1, sizeof (buffer), f);
+ if (length > 0)
+ if (!gdk_pixbuf_loader_write (loader, buffer, length, error)) {
+ gdk_pixbuf_loader_close (loader, NULL);
+ fclose (f);
+ g_object_unref (loader);
+ return NULL;
+ }
+
+ animation = gdk_pixbuf_loader_get_animation (loader);
+ if (animation) {
+ iter = gdk_pixbuf_animation_get_iter (animation, NULL);
+ if (!gdk_pixbuf_animation_iter_on_currently_loading_frame (iter)) {
+ has_frame = TRUE;
+ }
+ g_object_unref (iter);
+ }
+ }
+
+ fclose (f);
+
+ if (!gdk_pixbuf_loader_close (loader, error) && !has_frame) {
+ g_object_unref (loader);
+ return NULL;
+ }
+
+ pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+
+ if (!pixbuf) {
+ gchar *display_name = g_filename_display_name (filename);
+ g_object_unref (loader);
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_FAILED,
+ _("Failed to load image “%s”: reason not known, probably a corrupt image file"),
+ display_name);
+ g_free (display_name);
+ return NULL;
+ }
+
+ g_object_ref (pixbuf);
+
+ g_object_unref (loader);
+
+ return pixbuf;
+}
+
+#ifdef G_OS_WIN32
+
+/**
+ * gdk_pixbuf_new_from_file_at_scale_utf8:
+ * @filename: (type filename): Name of file to load, in the GLib file name encoding
+ * @width: The width the image should have or -1 to not constrain the width
+ * @height: The height the image should have or -1 to not constrain the height
+ * @preserve_aspect_ratio: `TRUE` to preserve the image's aspect ratio
+ * @error: Return location for an error
+ *
+ * Same as gdk_pixbuf_new_from_file_at_scale().
+ *
+ * Return value: A newly-created pixbuf with a reference count of 1, or `NULL`
+ * if any of several error conditions occurred: the file could not be opened,
+ * there was no loader for the file's format, there was not enough memory to
+ * allocate the image buffer, or the image file contained invalid data.
+ *
+ * Since: 2.6
+ **/
+GdkPixbuf *
+gdk_pixbuf_new_from_file_at_scale_utf8 (const char *filename,
+ int width,
+ int height,
+ gboolean preserve_aspect_ratio,
+ GError **error)
+{
+ return gdk_pixbuf_new_from_file_at_scale (filename, width, height,
+ preserve_aspect_ratio, error);
+}
+#endif
+
+
+static GdkPixbuf *
+load_from_stream (GdkPixbufLoader *loader,
+ GInputStream *stream,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GdkPixbuf *pixbuf;
+ gssize n_read;
+ guchar buffer[LOAD_BUFFER_SIZE];
+
+ while (1) {
+ n_read = g_input_stream_read (stream,
+ buffer,
+ sizeof (buffer),
+ cancellable,
+ error);
+ if (n_read < 0) {
+ gdk_pixbuf_loader_close (loader, NULL);
+ return NULL;
+ }
+
+ if (n_read == 0)
+ break;
+
+ if (!gdk_pixbuf_loader_write (loader,
+ buffer,
+ n_read,
+ error)) {
+ gdk_pixbuf_loader_close (loader, NULL);
+ return NULL;
+ }
+ }
+
+ if (!gdk_pixbuf_loader_close (loader, error))
+ return NULL;
+
+ pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+ if (pixbuf == NULL)
+ return NULL;
+
+ return g_object_ref (pixbuf);
+}
+
+
+/**
+ * gdk_pixbuf_new_from_stream_at_scale: (constructor)
+ * @stream: a `GInputStream` to load the pixbuf from
+ * @width: The width the image should have or -1 to not constrain the width
+ * @height: The height the image should have or -1 to not constrain the height
+ * @preserve_aspect_ratio: `TRUE` to preserve the image's aspect ratio
+ * @cancellable: (allow-none): optional `GCancellable` object, `NULL` to ignore
+ * @error: Return location for an error
+ *
+ * Creates a new pixbuf by loading an image from an input stream.
+ *
+ * The file format is detected automatically. If `NULL` is returned, then
+ * @error will be set. The @cancellable can be used to abort the operation
+ * from another thread. If the operation was cancelled, the error
+ * `G_IO_ERROR_CANCELLED` will be returned. Other possible errors are in
+ * the `GDK_PIXBUF_ERROR` and `G_IO_ERROR` domains.
+ *
+ * The image will be scaled to fit in the requested size, optionally
+ * preserving the image's aspect ratio.
+ *
+ * When preserving the aspect ratio, a `width` of -1 will cause the image to be
+ * scaled to the exact given height, and a `height` of -1 will cause the image
+ * to be scaled to the exact given width. If both `width` and `height` are
+ * given, this function will behave as if the smaller of the two values
+ * is passed as -1.
+ *
+ * When not preserving aspect ratio, a `width` or `height` of -1 means to not
+ * scale the image at all in that dimension.
+ *
+ * The stream is not closed.
+ *
+ * Return value: (transfer full) (nullable): A newly-created pixbuf
+ *
+ * Since: 2.14
+ */
+GdkPixbuf *
+gdk_pixbuf_new_from_stream_at_scale (GInputStream *stream,
+ gint width,
+ gint height,
+ gboolean preserve_aspect_ratio,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GdkPixbufLoader *loader;
+ GdkPixbuf *pixbuf;
+ AtScaleData info;
+
+ loader = gdk_pixbuf_loader_new ();
+ info.width = width;
+ info.height = height;
+ info.preserve_aspect_ratio = preserve_aspect_ratio;
+
+ g_signal_connect (loader, "size-prepared",
+ G_CALLBACK (at_scale_size_prepared_cb), &info);
+
+ pixbuf = load_from_stream (loader, stream, cancellable, error);
+ g_object_unref (loader);
+
+ return pixbuf;
+}
+
+
+static void
+load_from_stream_async_cb (GObject *stream,
+ GAsyncResult *res,
+ gpointer data)
+{
+ GTask *task = data;
+ GdkPixbufLoader *loader;
+ GdkPixbuf *pixbuf;
+ GError *error = NULL;
+ GBytes *bytes = NULL;
+
+ loader = g_task_get_task_data (task);
+
+ bytes = g_input_stream_read_bytes_finish (G_INPUT_STREAM (stream), res, &error);
+
+ if (bytes == NULL) {
+ gdk_pixbuf_loader_close (loader, NULL);
+ g_task_return_error (task, error);
+ } else if (g_bytes_get_size (bytes) > 0) {
+ if (!gdk_pixbuf_loader_write (loader,
+ g_bytes_get_data (bytes, NULL),
+ g_bytes_get_size (bytes),
+ &error)) {
+ gdk_pixbuf_loader_close (loader, NULL);
+ g_task_return_error (task, error);
+ goto out;
+ }
+ g_input_stream_read_bytes_async (G_INPUT_STREAM (stream),
+ LOAD_BUFFER_SIZE,
+ G_PRIORITY_DEFAULT,
+ g_task_get_cancellable (task),
+ load_from_stream_async_cb,
+ g_object_ref (task));
+
+ } else {
+ if (!gdk_pixbuf_loader_close (loader, &error)) {
+ g_task_return_error (task, error);
+ goto out;
+ }
+
+ pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+ g_task_return_pointer (task, g_object_ref (pixbuf), g_object_unref);
+ }
+
+out:
+ g_bytes_unref (bytes);
+ g_object_unref (task);
+}
+
+
+/**
+ * gdk_pixbuf_new_from_stream_at_scale_async:
+ * @stream: a `GInputStream` from which to load the pixbuf
+ * @width: the width the image should have or -1 to not constrain the width
+ * @height: the height the image should have or -1 to not constrain the height
+ * @preserve_aspect_ratio: `TRUE` to preserve the image's aspect ratio
+ * @cancellable: (allow-none): optional `GCancellable` object, `NULL` to ignore
+ * @callback: a `GAsyncReadyCallback` to call when the pixbuf is loaded
+ * @user_data: the data to pass to the callback function
+ *
+ * Creates a new pixbuf by asynchronously loading an image from an input stream.
+ *
+ * For more details see gdk_pixbuf_new_from_stream_at_scale(), which is the synchronous
+ * version of this function.
+ *
+ * When the operation is finished, @callback will be called in the main thread.
+ * You can then call gdk_pixbuf_new_from_stream_finish() to get the result of the operation.
+ *
+ * Since: 2.24
+ **/
+void
+gdk_pixbuf_new_from_stream_at_scale_async (GInputStream *stream,
+ gint width,
+ gint height,
+ gboolean preserve_aspect_ratio,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ AtScaleData *data;
+ GdkPixbufLoader *loader;
+
+ g_return_if_fail (G_IS_INPUT_STREAM (stream));
+ g_return_if_fail (callback != NULL);
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ data = g_slice_new (AtScaleData);
+ data->width = width;
+ data->height = height;
+ data->preserve_aspect_ratio = preserve_aspect_ratio;
+
+ loader = gdk_pixbuf_loader_new ();
+ g_signal_connect (loader, "size-prepared",
+ G_CALLBACK (at_scale_size_prepared_cb), data);
+ g_object_set_data_full (G_OBJECT (loader),
+ "gdk-pixbuf-please-kill-me-later",
+ data,
+ (GDestroyNotify) at_scale_data_async_data_free);
+
+ task = g_task_new (stream, cancellable, callback, user_data);
+ g_task_set_source_tag (task, gdk_pixbuf_new_from_stream_at_scale_async);
+ g_task_set_task_data (task, loader, g_object_unref);
+
+ g_input_stream_read_bytes_async (stream,
+ LOAD_BUFFER_SIZE,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ load_from_stream_async_cb,
+ task);
+}
+
+/**
+ * gdk_pixbuf_new_from_stream: (constructor)
+ * @stream: a `GInputStream` to load the pixbuf from
+ * @cancellable: (allow-none): optional `GCancellable` object, `NULL` to ignore
+ * @error: Return location for an error
+ *
+ * Creates a new pixbuf by loading an image from an input stream.
+ *
+ * The file format is detected automatically.
+ *
+ * If `NULL` is returned, then `error` will be set.
+ *
+ * The `cancellable` can be used to abort the operation from another thread.
+ * If the operation was cancelled, the error `G_IO_ERROR_CANCELLED` will be
+ * returned. Other possible errors are in the `GDK_PIXBUF_ERROR` and
+ * `G_IO_ERROR` domains.
+ *
+ * The stream is not closed.
+ *
+ * Return value: (transfer full) (nullable): A newly-created pixbuf
+ *
+ * Since: 2.14
+ **/
+GdkPixbuf *
+gdk_pixbuf_new_from_stream (GInputStream *stream,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GdkPixbuf *pixbuf;
+ GdkPixbufLoader *loader;
+
+ loader = gdk_pixbuf_loader_new ();
+ pixbuf = load_from_stream (loader, stream, cancellable, error);
+ g_object_unref (loader);
+
+ return pixbuf;
+}
+
+GdkPixbuf *
+_gdk_pixbuf_new_from_resource_try_pixdata (const char *resource_path)
+{
+ gsize data_size;
+ GBytes *bytes;
+
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+ /* We specialize GdkPixdata files, making these a reference to the
+ * compiled-in resource data, whether uncompressed and mmap'ed, or
+ * compressed, and uncompressed on-the-fly.
+ */
+ if (g_resources_get_info (resource_path, 0, &data_size, NULL, NULL) &&
+ data_size > sizeof(guint32) &&
+ (bytes = g_resources_lookup_data (resource_path, 0, NULL)) != NULL) {
+ GdkPixbuf*pixbuf = NULL;
+ const guint8 *stream = g_bytes_get_data (bytes, NULL);
+ GdkPixdata pixdata;
+ guint32 magic;
+
+ magic = (stream[0] << 24) + (stream[1] << 16) + (stream[2] << 8) + stream[3];
+ if (magic == GDK_PIXBUF_MAGIC_NUMBER &&
+ gdk_pixdata_deserialize (&pixdata, data_size, stream, NULL)) {
+ pixbuf = gdk_pixbuf_from_pixdata (&pixdata, FALSE, NULL);
+ }
+
+ if (pixbuf) {
+ /* Free the GBytes with the pixbuf */
+ g_object_set_data_full (G_OBJECT (pixbuf), "gdk-pixbuf-resource-bytes", bytes, (GDestroyNotify) g_bytes_unref);
+ return pixbuf;
+ } else {
+ g_bytes_unref (bytes);
+ }
+ }
+G_GNUC_END_IGNORE_DEPRECATIONS
+
+ return NULL;
+}
+
+/**
+ * gdk_pixbuf_new_from_resource: (constructor)
+ * @resource_path: the path of the resource file
+ * @error: Return location for an error
+ *
+ * Creates a new pixbuf by loading an image from an resource.
+ *
+ * The file format is detected automatically. If `NULL` is returned, then
+ * @error will be set.
+ *
+ * Return value: (transfer full) (nullable): A newly-created pixbuf
+ *
+ * Since: 2.26
+ **/
+GdkPixbuf *
+gdk_pixbuf_new_from_resource (const gchar *resource_path,
+ GError **error)
+{
+ GInputStream *stream;
+ GdkPixbuf *pixbuf;
+
+ pixbuf = _gdk_pixbuf_new_from_resource_try_pixdata (resource_path);
+ if (pixbuf)
+ return pixbuf;
+
+ stream = g_resources_open_stream (resource_path, 0, error);
+ if (stream == NULL)
+ return NULL;
+
+ pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, error);
+ g_object_unref (stream);
+ return pixbuf;
+}
+
+/**
+ * gdk_pixbuf_new_from_resource_at_scale: (constructor)
+ * @resource_path: the path of the resource file
+ * @width: The width the image should have or -1 to not constrain the width
+ * @height: The height the image should have or -1 to not constrain the height
+ * @preserve_aspect_ratio: `TRUE` to preserve the image's aspect ratio
+ * @error: Return location for an error
+ *
+ * Creates a new pixbuf by loading an image from an resource.
+ *
+ * The file format is detected automatically. If `NULL` is returned, then
+ * @error will be set.
+ *
+ * The image will be scaled to fit in the requested size, optionally
+ * preserving the image's aspect ratio. When preserving the aspect ratio,
+ * a @width of -1 will cause the image to be scaled to the exact given
+ * height, and a @height of -1 will cause the image to be scaled to the
+ * exact given width. When not preserving aspect ratio, a @width or
+ * @height of -1 means to not scale the image at all in that dimension.
+ *
+ * The stream is not closed.
+ *
+ * Return value: (transfer full) (nullable): A newly-created pixbuf
+ *
+ * Since: 2.26
+ */
+GdkPixbuf *
+gdk_pixbuf_new_from_resource_at_scale (const char *resource_path,
+ int width,
+ int height,
+ gboolean preserve_aspect_ratio,
+ GError **error)
+{
+ GInputStream *stream;
+ GdkPixbuf *pixbuf;
+
+ stream = g_resources_open_stream (resource_path, 0, error);
+ if (stream == NULL)
+ return NULL;
+
+ pixbuf = gdk_pixbuf_new_from_stream_at_scale (stream, width, height, preserve_aspect_ratio, NULL, error);
+ g_object_unref (stream);
+ return pixbuf;
+}
+
+/**
+ * gdk_pixbuf_new_from_stream_async:
+ * @stream: a `GInputStream` from which to load the pixbuf
+ * @cancellable: (allow-none): optional `GCancellable` object, `NULL` to ignore
+ * @callback: a `GAsyncReadyCallback` to call when the pixbuf is loaded
+ * @user_data: the data to pass to the callback function
+ *
+ * Creates a new pixbuf by asynchronously loading an image from an input stream.
+ *
+ * For more details see gdk_pixbuf_new_from_stream(), which is the synchronous
+ * version of this function.
+ *
+ * When the operation is finished, @callback will be called in the main thread.
+ * You can then call gdk_pixbuf_new_from_stream_finish() to get the result of
+ * the operation.
+ *
+ * Since: 2.24
+ **/
+void
+gdk_pixbuf_new_from_stream_async (GInputStream *stream,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+
+ g_return_if_fail (G_IS_INPUT_STREAM (stream));
+ g_return_if_fail (callback != NULL);
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = g_task_new (stream, cancellable, callback, user_data);
+ g_task_set_source_tag (task, gdk_pixbuf_new_from_stream_async);
+ g_task_set_task_data (task, gdk_pixbuf_loader_new (), g_object_unref);
+
+ g_input_stream_read_bytes_async (stream,
+ LOAD_BUFFER_SIZE,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ load_from_stream_async_cb,
+ task);
+}
+
+/**
+ * gdk_pixbuf_new_from_stream_finish:
+ * @async_result: a `GAsyncResult`
+ * @error: a `GError`, or `NULL`
+ *
+ * Finishes an asynchronous pixbuf creation operation started with
+ * gdk_pixbuf_new_from_stream_async().
+ *
+ * Return value: (transfer full) (nullable): the newly created pixbuf
+ *
+ * Since: 2.24
+ **/
+GdkPixbuf *
+gdk_pixbuf_new_from_stream_finish (GAsyncResult *async_result,
+ GError **error)
+{
+ GTask *task;
+
+ g_return_val_if_fail (G_IS_TASK (async_result), NULL);
+ g_return_val_if_fail (!error || (error && !*error), NULL);
+
+ task = G_TASK (async_result);
+
+ g_warn_if_fail (g_task_get_source_tag (task) == gdk_pixbuf_new_from_stream_async ||
+ g_task_get_source_tag (task) == gdk_pixbuf_new_from_stream_at_scale_async);
+
+ return g_task_propagate_pointer (task, error);
+}
+
+static void
+info_cb (GdkPixbufLoader *loader,
+ int width,
+ int height,
+ gpointer data)
+{
+ struct {
+ GdkPixbufFormat *format;
+ int width;
+ int height;
+ } *info = data;
+
+ g_return_if_fail (width > 0 && height > 0);
+
+ info->format = gdk_pixbuf_loader_get_format (loader);
+ info->width = width;
+ info->height = height;
+
+ gdk_pixbuf_loader_set_size (loader, 0, 0);
+}
+
+/**
+ * gdk_pixbuf_get_file_info:
+ * @filename: (type filename): The name of the file to identify.
+ * @width: (optional) (out): Return location for the width of the image
+ * @height: (optional) (out): Return location for the height of the image
+ *
+ * Parses an image file far enough to determine its format and size.
+ *
+ * Returns: (nullable) (transfer none): A `GdkPixbufFormat` describing
+ * the image format of the file
+ *
+ * Since: 2.4
+ **/
+GdkPixbufFormat *
+gdk_pixbuf_get_file_info (const gchar *filename,
+ gint *width,
+ gint *height)
+{
+ GdkPixbufLoader *loader;
+ guchar buffer[SNIFF_BUFFER_SIZE];
+ int length;
+ FILE *f;
+ struct {
+ GdkPixbufFormat *format;
+ gint width;
+ gint height;
+ } info;
+
+ g_return_val_if_fail (filename != NULL, NULL);
+
+ f = g_fopen (filename, "rb");
+ if (!f)
+ return NULL;
+
+ loader = _gdk_pixbuf_loader_new_with_filename (filename);
+
+ info.format = NULL;
+ info.width = -1;
+ info.height = -1;
+
+ g_signal_connect (loader, "size-prepared", G_CALLBACK (info_cb), &info);
+
+ while (!feof (f) && !ferror (f)) {
+ length = fread (buffer, 1, sizeof (buffer), f);
+ if (length > 0) {
+ if (!gdk_pixbuf_loader_write (loader, buffer, length, NULL))
+ break;
+ }
+ if (info.format != NULL)
+ break;
+ }
+
+ fclose (f);
+ gdk_pixbuf_loader_close (loader, NULL);
+ g_object_unref (loader);
+
+ if (width)
+ *width = info.width;
+ if (height)
+ *height = info.height;
+
+ return info.format;
+}
+
+typedef struct {
+ gchar *filename;
+ gint width;
+ gint height;
+} GetFileInfoAsyncData;
+
+static void
+get_file_info_async_data_free (GetFileInfoAsyncData *data)
+{
+ g_free (data->filename);
+ g_slice_free (GetFileInfoAsyncData, data);
+}
+
+static void
+get_file_info_thread (GTask *task,
+ gpointer source_object,
+ GetFileInfoAsyncData *data,
+ GCancellable *cancellable)
+{
+ GdkPixbufFormat *format;
+
+ format = gdk_pixbuf_get_file_info (data->filename, &data->width, &data->height);
+ if (format == NULL) {
+ g_task_return_new_error (task,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+ "Failed to recognize image format");
+ } else {
+ g_task_return_pointer (task,
+ gdk_pixbuf_format_copy (format),
+ (GDestroyNotify) gdk_pixbuf_format_free);
+ }
+}
+
+/**
+ * gdk_pixbuf_get_file_info_async:
+ * @filename: (type filename): The name of the file to identify
+ * @cancellable: (allow-none): optional `GCancellable` object, `NULL` to ignore
+ * @callback: a `GAsyncReadyCallback` to call when the file info is available
+ * @user_data: the data to pass to the callback function
+ *
+ * Asynchronously parses an image file far enough to determine its
+ * format and size.
+ *
+ * For more details see gdk_pixbuf_get_file_info(), which is the synchronous
+ * version of this function.
+ *
+ * When the operation is finished, @callback will be called in the
+ * main thread. You can then call gdk_pixbuf_get_file_info_finish() to
+ * get the result of the operation.
+ *
+ * Since: 2.32
+ **/
+void
+gdk_pixbuf_get_file_info_async (const gchar *filename,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GetFileInfoAsyncData *data;
+ GTask *task;
+
+ g_return_if_fail (filename != NULL);
+ g_return_if_fail (callback != NULL);
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ data = g_slice_new0 (GetFileInfoAsyncData);
+ data->filename = g_strdup (filename);
+
+ task = g_task_new (NULL, cancellable, callback, user_data);
+ g_task_set_return_on_cancel (task, TRUE);
+ g_task_set_source_tag (task, gdk_pixbuf_get_file_info_async);
+ g_task_set_task_data (task, data, (GDestroyNotify) get_file_info_async_data_free);
+ g_task_run_in_thread (task, (GTaskThreadFunc) get_file_info_thread);
+ g_object_unref (task);
+}
+
+/**
+ * gdk_pixbuf_get_file_info_finish:
+ * @async_result: a `GAsyncResult`
+ * @width: (out): Return location for the width of the image, or `NULL`
+ * @height: (out): Return location for the height of the image, or `NULL`
+ * @error: a `GError`, or `NULL`
+ *
+ * Finishes an asynchronous pixbuf parsing operation started with
+ * gdk_pixbuf_get_file_info_async().
+ *
+ * Returns: (transfer none) (nullable): A `GdkPixbufFormat` describing the
+ * image format of the file
+ *
+ * Since: 2.32
+ **/
+GdkPixbufFormat *
+gdk_pixbuf_get_file_info_finish (GAsyncResult *async_result,
+ gint *width,
+ gint *height,
+ GError **error)
+{
+ GetFileInfoAsyncData *data;
+ GTask *task;
+
+ g_return_val_if_fail (g_task_is_valid (async_result, NULL), NULL);
+
+ task = G_TASK (async_result);
+
+ g_return_val_if_fail (!error || (error && !*error), NULL);
+ g_warn_if_fail (g_task_get_source_tag (task) == gdk_pixbuf_get_file_info_async);
+
+ data = g_task_get_task_data (task);
+
+ if (!g_task_had_error (task)) {
+ if (width)
+ *width = data->width;
+ if (height)
+ *height = data->height;
+ }
+
+ return g_task_propagate_pointer (task, error);
+}
+
+/**
+ * gdk_pixbuf_new_from_xpm_data:
+ * @data: (array zero-terminated=1): Pointer to inline XPM data.
+ *
+ * Creates a new pixbuf by parsing XPM data in memory.
+ *
+ * This data is commonly the result of including an XPM file into a
+ * program's C source.
+ *
+ * Return value: A newly-created pixbuf
+ **/
+GdkPixbuf *
+gdk_pixbuf_new_from_xpm_data (const char **data)
+{
+ GdkPixbuf *(* load_xpm_data) (const char **data);
+ GdkPixbuf *pixbuf;
+ GError *error = NULL;
+ GdkPixbufModule *xpm_module;
+
+ g_return_val_if_fail (data != NULL, NULL);
+
+ xpm_module = _gdk_pixbuf_get_named_module ("xpm", &error);
+ if (xpm_module == NULL) {
+ g_warning ("Error loading XPM image loader: %s", error->message);
+ g_error_free (error);
+ return NULL;
+ }
+
+ if (!_gdk_pixbuf_load_module (xpm_module, &error)) {
+ g_warning ("Error loading XPM image loader: %s", error->message);
+ g_error_free (error);
+ return NULL;
+ }
+
+ if (xpm_module->load_xpm_data == NULL) {
+ g_warning ("gdk-pixbuf XPM module lacks XPM data capability");
+ pixbuf = NULL;
+ } else {
+ load_xpm_data = xpm_module->load_xpm_data;
+ pixbuf = (* load_xpm_data) (data);
+ }
+
+ return pixbuf;
+}
+
+static void
+collect_save_options (va_list opts,
+ gchar ***keys,
+ gchar ***vals)
+{
+ gchar *key;
+ gchar *val;
+ gchar *next;
+ gint count;
+
+ count = 0;
+ *keys = NULL;
+ *vals = NULL;
+
+ next = va_arg (opts, gchar*);
+ while (next)
+ {
+ key = next;
+ val = va_arg (opts, gchar*);
+
+ ++count;
+
+ /* woo, slow */
+ *keys = g_realloc (*keys, sizeof(gchar*) * (count + 1));
+ *vals = g_realloc (*vals, sizeof(gchar*) * (count + 1));
+
+ (*keys)[count-1] = g_strdup (key);
+ (*vals)[count-1] = g_strdup (val);
+
+ (*keys)[count] = NULL;
+ (*vals)[count] = NULL;
+
+ next = va_arg (opts, gchar*);
+ }
+}
+
+static gboolean
+save_to_file_callback (const gchar *buf,
+ gsize count,
+ GError **error,
+ gpointer data)
+{
+ FILE *filehandle = data;
+ gsize n;
+
+ n = fwrite (buf, 1, count, filehandle);
+ if (n != count) {
+ gint save_errno = errno;
+ g_set_error (error,
+ G_FILE_ERROR,
+ g_file_error_from_errno (save_errno),
+ _("Error writing to image file: %s"),
+ g_strerror (save_errno));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+gdk_pixbuf_real_save (GdkPixbuf *pixbuf,
+ FILE *filehandle,
+ const char *type,
+ gchar **keys,
+ gchar **values,
+ GError **error)
+{
+ gboolean ret;
+ GdkPixbufModule *image_module = NULL;
+
+ image_module = _gdk_pixbuf_get_named_module (type, error);
+
+ if (image_module == NULL)
+ return FALSE;
+
+ if (!_gdk_pixbuf_load_module (image_module, error))
+ return FALSE;
+
+ if (image_module->save) {
+ /* save normally */
+ ret = (* image_module->save) (filehandle, pixbuf,
+ keys, values,
+ error);
+ } else if (image_module->save_to_callback) {
+ /* save with simple callback */
+ ret = (* image_module->save_to_callback) (save_to_file_callback,
+ filehandle, pixbuf,
+ keys, values,
+ error);
+ } else {
+ /* can't save */
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
+ _("This build of gdk-pixbuf does not support saving the image format: %s"),
+ type);
+ ret = FALSE;
+ }
+
+ return ret;
+}
+
+#define TMP_FILE_BUF_SIZE 4096
+
+static gboolean
+save_to_callback_with_tmp_file (GdkPixbufModule *image_module,
+ GdkPixbuf *pixbuf,
+ GdkPixbufSaveFunc save_func,
+ gpointer user_data,
+ gchar **keys,
+ gchar **values,
+ GError **error)
+{
+ int fd;
+ FILE *f = NULL;
+ gboolean retval = FALSE;
+ gchar *buf = NULL;
+ gsize n;
+ gchar *filename = NULL;
+
+ buf = g_try_malloc (TMP_FILE_BUF_SIZE);
+ if (buf == NULL) {
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+ _("Insufficient memory to save image to callback"));
+ goto end;
+ }
+
+ fd = g_file_open_tmp ("gdkpixbuf-save-tmp.XXXXXX", &filename, error);
+ if (fd == -1)
+ goto end;
+ f = fdopen (fd, "wb+");
+ if (f == NULL) {
+ gint save_errno = errno;
+ g_set_error_literal (error,
+ G_FILE_ERROR,
+ g_file_error_from_errno (save_errno),
+ _("Failed to open temporary file"));
+ goto end;
+ }
+
+ retval = (image_module->save) (f, pixbuf, keys, values, error);
+ if (!retval)
+ goto end;
+
+ rewind (f);
+ for (;;) {
+ n = fread (buf, 1, TMP_FILE_BUF_SIZE, f);
+ if (n > 0) {
+ if (!save_func (buf, n, error, user_data))
+ goto end;
+ }
+ if (n != TMP_FILE_BUF_SIZE)
+ break;
+ }
+ if (ferror (f)) {
+ gint save_errno = errno;
+ g_set_error_literal (error,
+ G_FILE_ERROR,
+ g_file_error_from_errno (save_errno),
+ _("Failed to read from temporary file"));
+ goto end;
+ }
+ retval = TRUE;
+
+ end:
+ /* cleanup and return retval */
+ if (f)
+ fclose (f);
+ if (filename) {
+ g_unlink (filename);
+ g_free (filename);
+ }
+ g_free (buf);
+
+ return retval;
+}
+
+static gboolean
+gdk_pixbuf_real_save_to_callback (GdkPixbuf *pixbuf,
+ GdkPixbufSaveFunc save_func,
+ gpointer user_data,
+ const char *type,
+ gchar **keys,
+ gchar **values,
+ GError **error)
+{
+ gboolean ret;
+ GdkPixbufModule *image_module = NULL;
+
+ image_module = _gdk_pixbuf_get_named_module (type, error);
+
+ if (image_module == NULL)
+ return FALSE;
+
+ if (!_gdk_pixbuf_load_module (image_module, error))
+ return FALSE;
+
+ if (image_module->save_to_callback) {
+ /* save normally */
+ ret = (* image_module->save_to_callback) (save_func, user_data,
+ pixbuf, keys, values,
+ error);
+ } else if (image_module->save) {
+ /* use a temporary file */
+ ret = save_to_callback_with_tmp_file (image_module, pixbuf,
+ save_func, user_data,
+ keys, values,
+ error);
+ } else {
+ /* can't save */
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
+ _("This build of gdk-pixbuf does not support saving the image format: %s"),
+ type);
+ ret = FALSE;
+ }
+
+ return ret;
+}
+
+
+/**
+ * gdk_pixbuf_save:
+ * @pixbuf: a `GdkPixbuf`.
+ * @filename: (type filename): name of file to save.
+ * @type: name of file format.
+ * @error: (nullable): return location for error
+ * @...: list of key-value save options, followed by `NULL`
+ *
+ * Saves pixbuf to a file in format @type. By default, "jpeg", "png", "ico"
+ * and "bmp" are possible file formats to save in, but more formats may be
+ * installed. The list of all writable formats can be determined in the
+ * following way:
+ *
+ * ```c
+ * void add_if_writable (GdkPixbufFormat *data, GSList **list)
+ * {
+ * if (gdk_pixbuf_format_is_writable (data))
+ * *list = g_slist_prepend (*list, data);
+ * }
+ *
+ * GSList *formats = gdk_pixbuf_get_formats ();
+ * GSList *writable_formats = NULL;
+ * g_slist_foreach (formats, add_if_writable, &writable_formats);
+ * g_slist_free (formats);
+ * ```
+ *
+ * If `error` is set, `FALSE` will be returned. Possible errors include
+ * those in the `GDK_PIXBUF_ERROR` domain and those in the `G_FILE_ERROR`
+ * domain.
+ *
+ * The variable argument list should be `NULL`-terminated; if not empty,
+ * it should contain pairs of strings that modify the save
+ * parameters. For example:
+ *
+ * ```c
+ * gdk_pixbuf_save (pixbuf, handle, "jpeg", &error, "quality", "100", NULL);
+ * ```
+ *
+ * Currently only few parameters exist.
+ *
+ * JPEG images can be saved with a "quality" parameter; its value should be
+ * in the range `[0, 100]`. JPEG and PNG density can be set by setting the
+ * "x-dpi" and "y-dpi" parameters to the appropriate values in dots per inch.
+ *
+ * Text chunks can be attached to PNG images by specifying parameters of
+ * the form "tEXt::key", where key is an ASCII string of length 1-79.
+ * The values are UTF-8 encoded strings. The PNG compression level can
+ * be specified using the "compression" parameter; it's value is in an
+ * integer in the range of `[0, 9]`.
+ *
+ * ICC color profiles can also be embedded into PNG, JPEG and TIFF images.
+ * The "icc-profile" value should be the complete ICC profile encoded
+ * into base64.
+ *
+ * ```c
+ * char *contents;
+ * gsize length;
+ *
+ * // icm_path is set elsewhere
+ * g_file_get_contents (icm_path, &contents, &length, NULL);
+ *
+ * char *contents_encode = g_base64_encode ((const guchar *) contents, length);
+ *
+ * gdk_pixbuf_save (pixbuf, handle, "png", &error, "icc-profile", contents_encode, NULL);
+ * ```
+ *
+ * TIFF images recognize:
+ *
+ * 1. a "bits-per-sample" option (integer) which can be either 1 for saving
+ * bi-level CCITTFAX4 images, or 8 for saving 8-bits per sample
+ * 2. a "compression" option (integer) which can be 1 for no compression,
+ * 2 for Huffman, 5 for LZW, 7 for JPEG and 8 for DEFLATE (see the libtiff
+ * documentation and tiff.h for all supported codec values)
+ * 3. an "icc-profile" option (zero-terminated string) containing a base64
+ * encoded ICC color profile.
+ *
+ * ICO images can be saved in depth 16, 24, or 32, by using the "depth"
+ * parameter. When the ICO saver is given "x_hot" and "y_hot" parameters,
+ * it produces a CUR instead of an ICO.
+ *
+ * Return value: `TRUE` on success, and `FALSE` otherwise
+ **/
+gboolean
+gdk_pixbuf_save (GdkPixbuf *pixbuf,
+ const char *filename,
+ const char *type,
+ GError **error,
+ ...)
+{
+ gchar **keys = NULL;
+ gchar **values = NULL;
+ va_list args;
+ gboolean result;
+
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ va_start (args, error);
+
+ collect_save_options (args, &keys, &values);
+
+ va_end (args);
+
+ result = gdk_pixbuf_savev (pixbuf, filename, type,
+ keys, values,
+ error);
+
+ g_strfreev (keys);
+ g_strfreev (values);
+
+ return result;
+}
+
+/**
+ * gdk_pixbuf_savev:
+ * @pixbuf: a `GdkPixbuf`.
+ * @filename: (type filename): name of file to save.
+ * @type: name of file format.
+ * @option_keys: (array zero-terminated=1) (element-type utf8) (nullable): name of options to set
+ * @option_values: (array zero-terminated=1) (element-type utf8) (nullable): values for named options
+ * @error: (allow-none): return location for error, or `NULL`
+ *
+ * Vector version of `gdk_pixbuf_save()`.
+ *
+ * Saves pixbuf to a file in `type`, which is currently "jpeg", "png", "tiff", "ico" or "bmp".
+ *
+ * If @error is set, `FALSE` will be returned.
+ *
+ * See [method@GdkPixbuf.Pixbuf.save] for more details.
+ *
+ * Return value: whether an error was set
+ **/
+
+gboolean
+gdk_pixbuf_savev (GdkPixbuf *pixbuf,
+ const char *filename,
+ const char *type,
+ char **option_keys,
+ char **option_values,
+ GError **error)
+{
+ FILE *f = NULL;
+ gboolean result;
+
+ g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), FALSE);
+ g_return_val_if_fail (gdk_pixbuf_get_width (pixbuf) >= 0, FALSE);
+ g_return_val_if_fail (gdk_pixbuf_get_height (pixbuf) >= 0, FALSE);
+ g_return_val_if_fail (gdk_pixbuf_get_n_channels (pixbuf) >= 0, FALSE);
+ g_return_val_if_fail (filename != NULL, FALSE);
+ g_return_val_if_fail (type != NULL, FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ f = g_fopen (filename, "wb");
+
+ if (f == NULL) {
+ gint save_errno = errno;
+ gchar *display_name = g_filename_display_name (filename);
+ g_set_error (error,
+ G_FILE_ERROR,
+ g_file_error_from_errno (save_errno),
+ _("Failed to open “%s” for writing: %s"),
+ display_name,
+ g_strerror (save_errno));
+ g_free (display_name);
+ return FALSE;
+ }
+
+
+ result = gdk_pixbuf_real_save (pixbuf, f, type,
+ option_keys, option_values,
+ error);
+
+
+ if (!result) {
+ g_return_val_if_fail (error == NULL || *error != NULL, FALSE);
+ fclose (f);
+ g_unlink (filename);
+ return FALSE;
+ }
+
+ if (fclose (f) < 0) {
+ gint save_errno = errno;
+ gchar *display_name = g_filename_display_name (filename);
+ g_set_error (error,
+ G_FILE_ERROR,
+ g_file_error_from_errno (save_errno),
+ _("Failed to close “%s” while writing image, all data may not have been saved: %s"),
+ display_name,
+ g_strerror (save_errno));
+ g_free (display_name);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#ifdef G_OS_WIN32
+
+/**
+ * gdk_pixbuf_savev_utf8:
+ * @pixbuf: a `GdkPixbuf`.
+ * @filename: name of file to save.
+ * @type: name of file format.
+ * @option_keys: (array zero-terminated=1) (element-type utf8) (nullable): name of options to set
+ * @option_values: (array zero-terminated=1) (element-type utf8) (nullable): values for named options
+ * @error: (allow-none): return location for error, or `NULL`
+ *
+ * Same as gdk_pixbuf_savev()
+ *
+ * Return value: whether an error was set
+ **/
+gboolean
+gdk_pixbuf_savev_utf8 (GdkPixbuf *pixbuf,
+ const char *filename,
+ const char *type,
+ char **option_keys,
+ char **option_values,
+ GError **error)
+{
+ return gdk_pixbuf_savev (pixbuf, filename, type, option_keys,
+ option_values, error);
+}
+
+#endif
+
+/**
+ * gdk_pixbuf_save_to_callback:
+ * @pixbuf: a `GdkPixbuf`.
+ * @save_func: (scope call): a function that is called to save each block of data that
+ * the save routine generates.
+ * @user_data: user data to pass to the save function.
+ * @type: name of file format.
+ * @error: (allow-none): return location for error, or `NULL`
+ * @...: list of key-value save options
+ *
+ * Saves pixbuf in format `type` by feeding the produced data to a
+ * callback.
+ *
+ * This function can be used when you want to store the image to something
+ * other than a file, such as an in-memory buffer or a socket.
+ *
+ * If @error is set, `FALSE` will be returned. Possible errors
+ * include those in the `GDK_PIXBUF_ERROR` domain and whatever the save
+ * function generates.
+ *
+ * See [method@GdkPixbuf.Pixbuf.save] for more details.
+ *
+ * Return value: whether an error was set
+ *
+ * Since: 2.4
+ **/
+gboolean
+gdk_pixbuf_save_to_callback (GdkPixbuf *pixbuf,
+ GdkPixbufSaveFunc save_func,
+ gpointer user_data,
+ const char *type,
+ GError **error,
+ ...)
+{
+ gchar **keys = NULL;
+ gchar **values = NULL;
+ va_list args;
+ gboolean result;
+
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ va_start (args, error);
+
+ collect_save_options (args, &keys, &values);
+
+ va_end (args);
+
+ result = gdk_pixbuf_save_to_callbackv (pixbuf, save_func, user_data,
+ type, keys, values,
+ error);
+
+ g_strfreev (keys);
+ g_strfreev (values);
+
+ return result;
+}
+
+/**
+ * gdk_pixbuf_save_to_callbackv:
+ * @pixbuf: a `GdkPixbuf`.
+ * @save_func: (scope call): a function that is called to save each block of data that
+ * the save routine generates.
+ * @user_data: (closure): user data to pass to the save function.
+ * @type: name of file format.
+ * @option_keys: (array zero-terminated=1) (element-type utf8) (nullable): name of options to set
+ * @option_values: (array zero-terminated=1) (element-type utf8) (nullable): values for named options
+ * @error: (allow-none): return location for error, or `NULL`
+ *
+ * Vector version of `gdk_pixbuf_save_to_callback()`.
+ *
+ * Saves pixbuf to a callback in format @type, which is currently "jpeg",
+ * "png", "tiff", "ico" or "bmp".
+ *
+ * If @error is set, `FALSE` will be returned.
+ *
+ * See [method@GdkPixbuf.Pixbuf.save_to_callback] for more details.
+ *
+ * Return value: whether an error was set
+ *
+ * Since: 2.4
+ **/
+gboolean
+gdk_pixbuf_save_to_callbackv (GdkPixbuf *pixbuf,
+ GdkPixbufSaveFunc save_func,
+ gpointer user_data,
+ const char *type,
+ char **option_keys,
+ char **option_values,
+ GError **error)
+{
+ gboolean result;
+
+ g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), FALSE);
+ g_return_val_if_fail (gdk_pixbuf_get_width (pixbuf) >= 0, FALSE);
+ g_return_val_if_fail (gdk_pixbuf_get_height (pixbuf) >= 0, FALSE);
+ g_return_val_if_fail (gdk_pixbuf_get_n_channels (pixbuf) >= 0, FALSE);
+ g_return_val_if_fail (save_func != NULL, FALSE);
+ g_return_val_if_fail (type != NULL, FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ result = gdk_pixbuf_real_save_to_callback (pixbuf,
+ save_func, user_data, type,
+ option_keys, option_values,
+ error);
+
+ if (!result) {
+ g_return_val_if_fail (error == NULL || *error != NULL, FALSE);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * gdk_pixbuf_save_to_buffer:
+ * @pixbuf: a `GdkPixbuf`.
+ * @buffer: (array length=buffer_size) (out) (element-type guint8): location to receive a pointer
+ * to the new buffer.
+ * @buffer_size: location to receive the size of the new buffer.
+ * @type: name of file format.
+ * @error: (allow-none): return location for error, or `NULL`
+ * @...: list of key-value save options
+ *
+ * Saves pixbuf to a new buffer in format `type`, which is currently "jpeg",
+ * "png", "tiff", "ico" or "bmp".
+ *
+ * This is a convenience function that uses `gdk_pixbuf_save_to_callback()`
+ * to do the real work.
+ *
+ * Note that the buffer is not `NUL`-terminated and may contain embedded `NUL`
+ * characters.
+ *
+ * If @error is set, `FALSE` will be returned and @buffer will be set to
+ * `NULL`. Possible errors include those in the `GDK_PIXBUF_ERROR`
+ * domain.
+ *
+ * See `gdk_pixbuf_save()` for more details.
+ *
+ * Return value: whether an error was set
+ *
+ * Since: 2.4
+ **/
+gboolean
+gdk_pixbuf_save_to_buffer (GdkPixbuf *pixbuf,
+ gchar **buffer,
+ gsize *buffer_size,
+ const char *type,
+ GError **error,
+ ...)
+{
+ gchar **keys = NULL;
+ gchar **values = NULL;
+ va_list args;
+ gboolean result;
+
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ va_start (args, error);
+
+ collect_save_options (args, &keys, &values);
+
+ va_end (args);
+
+ result = gdk_pixbuf_save_to_bufferv (pixbuf, buffer, buffer_size,
+ type, keys, values,
+ error);
+
+ g_strfreev (keys);
+ g_strfreev (values);
+
+ return result;
+}
+
+struct SaveToBufferData {
+ gchar *buffer;
+ gsize len, max;
+};
+
+static gboolean
+save_to_buffer_callback (const gchar *data,
+ gsize count,
+ GError **error,
+ gpointer user_data)
+{
+ struct SaveToBufferData *sdata = user_data;
+ gchar *new_buffer;
+ gsize new_max;
+
+ if (sdata->len + count > sdata->max) {
+ new_max = MAX (sdata->max*2, sdata->len + count);
+ new_buffer = g_try_realloc (sdata->buffer, new_max);
+ if (!new_buffer) {
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+ _("Insufficient memory to save image into a buffer"));
+ return FALSE;
+ }
+ sdata->buffer = new_buffer;
+ sdata->max = new_max;
+ }
+ memcpy (sdata->buffer + sdata->len, data, count);
+ sdata->len += count;
+ return TRUE;
+}
+
+/**
+ * gdk_pixbuf_save_to_bufferv:
+ * @pixbuf: a `GdkPixbuf`.
+ * @buffer: (array length=buffer_size) (out) (element-type guint8):
+ * location to receive a pointer to the new buffer.
+ * @buffer_size: location to receive the size of the new buffer.
+ * @type: name of file format.
+ * @option_keys: (array zero-terminated=1) (element-type utf8) (nullable): name of options to set
+ * @option_values: (array zero-terminated=1) (element-type utf8) (nullable): values for named options
+ * @error: (allow-none): return location for error, or `NULL`
+ *
+ * Vector version of `gdk_pixbuf_save_to_buffer()`.
+ *
+ * Saves pixbuf to a new buffer in format @type, which is currently "jpeg",
+ * "tiff", "png", "ico" or "bmp".
+ *
+ * See [method@GdkPixbuf.Pixbuf.save_to_buffer] for more details.
+ *
+ * Return value: whether an error was set
+ *
+ * Since: 2.4
+ **/
+gboolean
+gdk_pixbuf_save_to_bufferv (GdkPixbuf *pixbuf,
+ gchar **buffer,
+ gsize *buffer_size,
+ const char *type,
+ char **option_keys,
+ char **option_values,
+ GError **error)
+{
+ static const gint initial_max = 1024;
+ struct SaveToBufferData sdata;
+
+ *buffer = NULL;
+ *buffer_size = 0;
+
+ sdata.buffer = g_try_malloc (initial_max);
+ sdata.max = initial_max;
+ sdata.len = 0;
+ if (!sdata.buffer) {
+ g_set_error_literal (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+ _("Insufficient memory to save image into a buffer"));
+ return FALSE;
+ }
+
+ if (!gdk_pixbuf_save_to_callbackv (pixbuf,
+ save_to_buffer_callback, &sdata,
+ type, option_keys, option_values,
+ error)) {
+ g_free (sdata.buffer);
+ return FALSE;
+ }
+
+ *buffer = sdata.buffer;
+ *buffer_size = sdata.len;
+ return TRUE;
+}
+
+typedef struct {
+ GOutputStream *stream;
+ GCancellable *cancellable;
+} SaveToStreamData;
+
+static gboolean
+save_to_stream (const gchar *buffer,
+ gsize count,
+ GError **error,
+ gpointer data)
+{
+ SaveToStreamData *sdata = (SaveToStreamData *)data;
+ gsize remaining;
+ gssize written;
+ GError *my_error = NULL;
+
+ remaining = count;
+ written = 0;
+ while (remaining > 0) {
+ buffer += written;
+ remaining -= written;
+ written = g_output_stream_write (sdata->stream,
+ buffer, remaining,
+ sdata->cancellable,
+ &my_error);
+ if (written < 0) {
+ if (!my_error) {
+ g_set_error_literal (error,
+ G_IO_ERROR, 0,
+ _("Error writing to image stream"));
+ }
+ else {
+ g_propagate_error (error, my_error);
+ }
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ * gdk_pixbuf_save_to_streamv:
+ * @pixbuf: a `GdkPixbuf`
+ * @stream: a `GOutputStream` to save the pixbuf to
+ * @type: name of file format
+ * @option_keys: (array zero-terminated=1) (element-type utf8) (nullable): name of options to set
+ * @option_values: (array zero-terminated=1) (element-type utf8) (nullable): values for named options
+ * @cancellable: (nullable): optional `GCancellable` object, `NULL` to ignore
+ * @error: return location for error
+ *
+ * Saves `pixbuf` to an output stream.
+ *
+ * Supported file formats are currently "jpeg", "tiff", "png", "ico" or
+ * "bmp".
+ *
+ * See [method@GdkPixbuf.Pixbuf.save_to_stream] for more details.
+ *
+ * Returns: `TRUE` if the pixbuf was saved successfully, `FALSE` if an
+ * error was set.
+ *
+ * Since: 2.36
+ */
+gboolean
+gdk_pixbuf_save_to_streamv (GdkPixbuf *pixbuf,
+ GOutputStream *stream,
+ const char *type,
+ char **option_keys,
+ char **option_values,
+ GCancellable *cancellable,
+ GError **error)
+{
+ SaveToStreamData data;
+
+ data.stream = stream;
+ data.cancellable = cancellable;
+
+ return gdk_pixbuf_save_to_callbackv (pixbuf, save_to_stream,
+ &data, type,
+ option_keys, option_values,
+ error);
+}
+
+/**
+ * gdk_pixbuf_save_to_stream:
+ * @pixbuf: a `GdkPixbuf`
+ * @stream: a `GOutputStream` to save the pixbuf to
+ * @type: name of file format
+ * @cancellable: (allow-none): optional `GCancellable` object, `NULL` to ignore
+ * @error: (allow-none): return location for error, or `NULL`
+ * @...: list of key-value save options
+ *
+ * Saves `pixbuf` to an output stream.
+ *
+ * Supported file formats are currently "jpeg", "tiff", "png", "ico" or
+ * "bmp". See `gdk_pixbuf_save_to_buffer()` for more details.
+ *
+ * The `cancellable` can be used to abort the operation from another
+ * thread. If the operation was cancelled, the error `G_IO_ERROR_CANCELLED`
+ * will be returned. Other possible errors are in the `GDK_PIXBUF_ERROR`
+ * and `G_IO_ERROR` domains.
+ *
+ * The stream is not closed at the end of this call.
+ *
+ * Returns: `TRUE` if the pixbuf was saved successfully, `FALSE` if an
+ * error was set.
+ *
+ * Since: 2.14
+ */
+gboolean
+gdk_pixbuf_save_to_stream (GdkPixbuf *pixbuf,
+ GOutputStream *stream,
+ const char *type,
+ GCancellable *cancellable,
+ GError **error,
+ ...)
+{
+ gboolean res;
+ gchar **keys = NULL;
+ gchar **values = NULL;
+ va_list args;
+
+ va_start (args, error);
+ collect_save_options (args, &keys, &values);
+ va_end (args);
+
+ res = gdk_pixbuf_save_to_streamv (pixbuf, stream, type,
+ keys, values,
+ cancellable, error);
+
+ g_strfreev (keys);
+ g_strfreev (values);
+
+ return res;
+}
+
+typedef struct {
+ GOutputStream *stream;
+ gchar *type;
+ gchar **keys;
+ gchar **values;
+} SaveToStreamAsyncData;
+
+static void
+save_to_stream_async_data_free (SaveToStreamAsyncData *data)
+{
+ if (data->stream)
+ g_object_unref (data->stream);
+ g_strfreev (data->keys);
+ g_strfreev (data->values);
+ g_free (data->type);
+ g_slice_free (SaveToStreamAsyncData, data);
+}
+
+static void
+save_to_stream_thread (GTask *task,
+ GdkPixbuf *pixbuf,
+ SaveToStreamAsyncData *data,
+ GCancellable *cancellable)
+{
+ SaveToStreamData sync_data;
+ gboolean retval;
+ GError *error = NULL;
+
+ sync_data.stream = data->stream;
+ sync_data.cancellable = cancellable;
+
+ retval = gdk_pixbuf_save_to_callbackv (pixbuf, save_to_stream,
+ &sync_data, data->type,
+ data->keys, data->values,
+ &error);
+
+ if (retval == FALSE) {
+ g_task_return_error (task, error);
+ } else {
+ g_task_return_boolean (task, TRUE);
+ }
+}
+
+/**
+ * gdk_pixbuf_save_to_streamv_async:
+ * @pixbuf: a `GdkPixbuf`
+ * @stream: a `GOutputStream` to which to save the pixbuf
+ * @type: name of file format
+ * @option_keys: (array zero-terminated=1) (element-type utf8) (nullable): name of options to set
+ * @option_values: (array zero-terminated=1) (element-type utf8) (nullable): values for named options
+ * @cancellable: (allow-none): optional `GCancellable` object, `NULL` to ignore
+ * @callback: a `GAsyncReadyCallback` to call when the pixbuf is saved
+ * @user_data: the data to pass to the callback function
+ *
+ * Saves `pixbuf` to an output stream asynchronously.
+ *
+ * For more details see gdk_pixbuf_save_to_streamv(), which is the synchronous
+ * version of this function.
+ *
+ * When the operation is finished, `callback` will be called in the main thread.
+ *
+ * You can then call gdk_pixbuf_save_to_stream_finish() to get the result of
+ * the operation.
+ *
+ * Since: 2.36
+ **/
+void
+gdk_pixbuf_save_to_streamv_async (GdkPixbuf *pixbuf,
+ GOutputStream *stream,
+ const gchar *type,
+ gchar **option_keys,
+ gchar **option_values,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ SaveToStreamAsyncData *data;
+
+ g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
+ g_return_if_fail (gdk_pixbuf_get_width (pixbuf) >= 0);
+ g_return_if_fail (gdk_pixbuf_get_height (pixbuf) >= 0);
+ g_return_if_fail (gdk_pixbuf_get_n_channels (pixbuf) >= 0);
+ g_return_if_fail (G_IS_OUTPUT_STREAM (stream));
+ g_return_if_fail (type != NULL);
+ g_return_if_fail (callback != NULL);
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ data = g_slice_new (SaveToStreamAsyncData);
+ data->stream = g_object_ref (stream);
+ data->type = g_strdup (type);
+ data->keys = g_strdupv (option_keys);
+ data->values = g_strdupv (option_values);
+
+ task = g_task_new (pixbuf, cancellable, callback, user_data);
+ g_task_set_source_tag (task, gdk_pixbuf_save_to_streamv_async);
+ g_task_set_task_data (task, data, (GDestroyNotify) save_to_stream_async_data_free);
+ g_task_run_in_thread (task, (GTaskThreadFunc) save_to_stream_thread);
+ g_object_unref (task);
+}
+
+/**
+ * gdk_pixbuf_save_to_stream_async:
+ * @pixbuf: a `GdkPixbuf`
+ * @stream: a `GOutputStream` to which to save the pixbuf
+ * @type: name of file format
+ * @cancellable: (allow-none): optional `GCancellable` object, `NULL` to ignore
+ * @callback: a `GAsyncReadyCallback` to call when the pixbuf is saved
+ * @user_data: the data to pass to the callback function
+ * @...: list of key-value save options
+ *
+ * Saves `pixbuf` to an output stream asynchronously.
+ *
+ * For more details see gdk_pixbuf_save_to_stream(), which is the synchronous
+ * version of this function.
+ *
+ * When the operation is finished, `callback` will be called in the main thread.
+ *
+ * You can then call gdk_pixbuf_save_to_stream_finish() to get the result of
+ * the operation.
+ *
+ * Since: 2.24
+ **/
+void
+gdk_pixbuf_save_to_stream_async (GdkPixbuf *pixbuf,
+ GOutputStream *stream,
+ const gchar *type,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ ...)
+{
+ gchar **keys = NULL;
+ gchar **values = NULL;
+ va_list args;
+
+ g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
+ g_return_if_fail (gdk_pixbuf_get_width (pixbuf) >= 0);
+ g_return_if_fail (gdk_pixbuf_get_height (pixbuf) >= 0);
+ g_return_if_fail (gdk_pixbuf_get_n_channels (pixbuf) >= 0);
+ g_return_if_fail (G_IS_OUTPUT_STREAM (stream));
+ g_return_if_fail (type != NULL);
+ g_return_if_fail (callback != NULL);
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ va_start (args, user_data);
+ collect_save_options (args, &keys, &values);
+ va_end (args);
+
+ gdk_pixbuf_save_to_streamv_async (pixbuf, stream, type,
+ keys, values,
+ cancellable, callback, user_data);
+ g_strfreev (keys);
+ g_strfreev (values);
+}
+
+/**
+ * gdk_pixbuf_save_to_stream_finish:
+ * @async_result: a `GAsyncResult`
+ * @error: a `GError`, or `NULL`
+ *
+ * Finishes an asynchronous pixbuf save operation started with
+ * gdk_pixbuf_save_to_stream_async().
+ *
+ * Return value: `TRUE` if the pixbuf was saved successfully, `FALSE` if an error was set.
+ *
+ * Since: 2.24
+ **/
+gboolean
+gdk_pixbuf_save_to_stream_finish (GAsyncResult *async_result,
+ GError **error)
+{
+ GTask *task;
+
+ /* Can not use g_task_is_valid because our GTask has a
+ * source_object which is not available to us anymore.
+ */
+ g_return_val_if_fail (G_IS_TASK (async_result), FALSE);
+
+ task = G_TASK (async_result);
+
+ g_return_val_if_fail (!error || (error && !*error), FALSE);
+ g_warn_if_fail (g_task_get_source_tag (task) == gdk_pixbuf_save_to_stream_async ||
+ g_task_get_source_tag (task) == gdk_pixbuf_save_to_streamv_async);
+
+ return g_task_propagate_boolean (task, error);
+}
+
+/**
+ * gdk_pixbuf_format_get_name:
+ * @format: a `GdkPixbufFormat`
+ *
+ * Returns the name of the format.
+ *
+ * Return value: the name of the format.
+ *
+ * Since: 2.2
+ */
+gchar *
+gdk_pixbuf_format_get_name (GdkPixbufFormat *format)
+{
+ g_return_val_if_fail (format != NULL, NULL);
+
+ return g_strdup (format->name);
+}
+
+/**
+ * gdk_pixbuf_format_get_description:
+ * @format: a `GdkPixbufFormat`
+ *
+ * Returns a description of the format.
+ *
+ * Return value: a description of the format.
+ *
+ * Since: 2.2
+ */
+gchar *
+gdk_pixbuf_format_get_description (GdkPixbufFormat *format)
+{
+ gchar *domain;
+ const gchar *description;
+ g_return_val_if_fail (format != NULL, NULL);
+
+ if (format->domain != NULL)
+ domain = format->domain;
+ else
+ domain = GETTEXT_PACKAGE;
+ description = g_dgettext (domain, format->description);
+
+ return g_strdup (description);
+}
+
+/**
+ * gdk_pixbuf_format_get_mime_types:
+ * @format: a `GdkPixbufFormat`
+ *
+ * Returns the mime types supported by the format.
+ *
+ * Return value: (transfer full) (array zero-terminated=1): an array of mime types
+ *
+ * Since: 2.2
+ */
+gchar **
+gdk_pixbuf_format_get_mime_types (GdkPixbufFormat *format)
+{
+ g_return_val_if_fail (format != NULL, NULL);
+
+ return g_strdupv (format->mime_types);
+}
+
+/**
+ * gdk_pixbuf_format_get_extensions:
+ * @format: a `GdkPixbufFormat`
+ *
+ * Returns the filename extensions typically used for files in the
+ * given format.
+ *
+ * Return value: (transfer full) (array zero-terminated=1): an array of
+ * filename extensions
+ *
+ * Since: 2.2
+ */
+gchar **
+gdk_pixbuf_format_get_extensions (GdkPixbufFormat *format)
+{
+ g_return_val_if_fail (format != NULL, NULL);
+
+ return g_strdupv (format->extensions);
+}
+
+/**
+ * gdk_pixbuf_format_is_writable:
+ * @format: a `GdkPixbufFormat`
+ *
+ * Returns whether pixbufs can be saved in the given format.
+ *
+ * Return value: whether pixbufs can be saved in the given format.
+ *
+ * Since: 2.2
+ */
+gboolean
+gdk_pixbuf_format_is_writable (GdkPixbufFormat *format)
+{
+ g_return_val_if_fail (format != NULL, FALSE);
+
+ return (format->flags & GDK_PIXBUF_FORMAT_WRITABLE) != 0;
+}
+
+/**
+ * gdk_pixbuf_format_is_scalable:
+ * @format: a `GdkPixbufFormat`
+ *
+ * Returns whether this image format is scalable.
+ *
+ * If a file is in a scalable format, it is preferable to load it at
+ * the desired size, rather than loading it at the default size and
+ * scaling the resulting pixbuf to the desired size.
+ *
+ * Return value: whether this image format is scalable.
+ *
+ * Since: 2.6
+ */
+gboolean
+gdk_pixbuf_format_is_scalable (GdkPixbufFormat *format)
+{
+ g_return_val_if_fail (format != NULL, FALSE);
+
+ return (format->flags & GDK_PIXBUF_FORMAT_SCALABLE) != 0;
+}
+
+/**
+ * gdk_pixbuf_format_is_disabled:
+ * @format: a `GdkPixbufFormat`
+ *
+ * Returns whether this image format is disabled.
+ *
+ * See gdk_pixbuf_format_set_disabled().
+ *
+ * Return value: whether this image format is disabled.
+ *
+ * Since: 2.6
+ */
+gboolean
+gdk_pixbuf_format_is_disabled (GdkPixbufFormat *format)
+{
+ g_return_val_if_fail (format != NULL, FALSE);
+
+ return format->disabled;
+}
+
+/**
+ * gdk_pixbuf_format_set_disabled:
+ * @format: a `GdkPixbufFormat`
+ * @disabled: `TRUE` to disable the format @format
+ *
+ * Disables or enables an image format.
+ *
+ * If a format is disabled, GdkPixbuf won't use the image loader for
+ * this format to load images.
+ *
+ * Applications can use this to avoid using image loaders with an
+ * inappropriate license, see gdk_pixbuf_format_get_license().
+ *
+ * Since: 2.6
+ */
+void
+gdk_pixbuf_format_set_disabled (GdkPixbufFormat *format,
+ gboolean disabled)
+{
+ g_return_if_fail (format != NULL);
+
+ format->disabled = disabled != FALSE;
+}
+
+/**
+ * gdk_pixbuf_format_get_license:
+ * @format: a pixbuf format
+ *
+ * Returns information about the license of the image loader for the format.
+ *
+ * The returned string should be a shorthand for a well known license, e.g.
+ * "LGPL", "GPL", "QPL", "GPL/QPL", or "other" to indicate some other license.
+ *
+ * Returns: (transfer full): a string describing the license of the pixbuf format
+ *
+ * Since: 2.6
+ */
+gchar*
+gdk_pixbuf_format_get_license (GdkPixbufFormat *format)
+{
+ g_return_val_if_fail (format != NULL, NULL);
+
+ return g_strdup (format->license);
+}
+
+GdkPixbufFormat *
+_gdk_pixbuf_get_format (GdkPixbufModule *module)
+{
+ g_return_val_if_fail (module != NULL, NULL);
+
+ return module->info;
+}
+
+/**
+ * gdk_pixbuf_get_formats:
+ *
+ * Obtains the available information about the image formats supported
+ * by GdkPixbuf.
+ *
+ * Returns: (transfer container) (element-type GdkPixbufFormat): A list of
+ * support image formats.
+ *
+ * Since: 2.2
+ */
+GSList *
+gdk_pixbuf_get_formats (void)
+{
+ GSList *result = NULL;
+ GSList *modules;
+
+ for (modules = get_file_formats (); modules; modules = g_slist_next (modules)) {
+ GdkPixbufModule *module = (GdkPixbufModule *)modules->data;
+ GdkPixbufFormat *info = _gdk_pixbuf_get_format (module);
+ result = g_slist_prepend (result, info);
+ }
+
+ return result;
+}
+
+/**
+ * gdk_pixbuf_format_copy:
+ * @format: a pixbuf format
+ *
+ * Creates a copy of `format`.
+ *
+ * Return value: the newly allocated copy of a `GdkPixbufFormat`. Use
+ * gdk_pixbuf_format_free() to free the resources when done
+ *
+ * Since: 2.22
+ */
+GdkPixbufFormat *
+gdk_pixbuf_format_copy (const GdkPixbufFormat *format)
+{
+ if (G_LIKELY (format != NULL))
+ return g_slice_dup (GdkPixbufFormat, format);
+
+ return NULL;
+}
+
+/**
+ * gdk_pixbuf_format_free:
+ * @format: a pixbuf format
+ *
+ * Frees the resources allocated when copying a `GdkPixbufFormat`
+ * using gdk_pixbuf_format_copy()
+ *
+ * Since: 2.22
+ */
+void
+gdk_pixbuf_format_free (GdkPixbufFormat *format)
+{
+ if (G_LIKELY (format != NULL))
+ g_slice_free (GdkPixbufFormat, format);
+}
+
+/**
+ * gdk_pixbuf_format_is_save_option_supported:
+ * @format: a pixbuf format
+ * @option_key: the name of an option
+ *
+ * Returns `TRUE` if the save option specified by @option_key is supported when
+ * saving a pixbuf using the module implementing @format.
+ *
+ * See gdk_pixbuf_save() for more information about option keys.
+ *
+ * Returns: `TRUE` if the specified option is supported
+ *
+ * Since: 2.36
+ */
+gboolean
+gdk_pixbuf_format_is_save_option_supported (GdkPixbufFormat *format,
+ const gchar *option_key)
+{
+ GdkPixbufModule *module;
+
+ g_return_val_if_fail (format != NULL, FALSE);
+ g_return_val_if_fail (option_key != NULL, FALSE);
+
+ module = _gdk_pixbuf_get_named_module (format->name, NULL);
+ if (!module)
+ return FALSE;
+
+ if (!_gdk_pixbuf_load_module (module, NULL))
+ return FALSE;
+
+ if (!module->is_save_option_supported)
+ return FALSE;
+
+ return (* module->is_save_option_supported) (option_key);
+}
+
+G_DEFINE_BOXED_TYPE (GdkPixbufFormat, gdk_pixbuf_format,
+ gdk_pixbuf_format_copy,
+ gdk_pixbuf_format_free)
Index: create-2.42.9-dirname-patch/gdk-pixbuf-2.42.9-new/gdk-pixbuf/queryloaders.c
===================================================================
--- create-2.42.9-dirname-patch/gdk-pixbuf-2.42.9-new/gdk-pixbuf/queryloaders.c (nonexistent)
+++ create-2.42.9-dirname-patch/gdk-pixbuf-2.42.9-new/gdk-pixbuf/queryloaders.c (revision 5)
@@ -0,0 +1,494 @@
+/* -*- mode: C; c-file-style: "linux" -*- */
+/* GdkPixbuf library
+ * queryloaders.c:
+ *
+ * Copyright (C) 2002 The Free Software Foundation
+ *
+ * Author: Matthias Clasen <maclas@gmx.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <glib/gprintf.h>
+#include <gmodule.h>
+
+#include <errno.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "gdk-pixbuf/gdk-pixbuf.h"
+#include "gdk-pixbuf/gdk-pixbuf-private.h"
+
+#ifdef USE_LA_MODULES
+#define SOEXT ".la"
+#else
+#define SOEXT ("." G_MODULE_SUFFIX)
+#endif
+#define SOEXT_LEN (strlen (SOEXT))
+
+#ifdef G_OS_WIN32
+#include <windows.h>
+#endif
+
+#ifdef OS_DARWIN
+#include <mach-o/dyld.h>
+#endif
+
+static void
+print_escaped (GString *contents, const char *str)
+{
+ gchar *tmp = g_strescape (str, "");
+ g_string_append_printf (contents, "\"%s\" ", tmp);
+ g_free (tmp);
+}
+
+static int
+loader_sanity_check (const char *path, GdkPixbufFormat *info, GdkPixbufModule *vtable)
+{
+ const GdkPixbufModulePattern *pattern;
+ const char *error = "";
+
+ for (pattern = info->signature; pattern->prefix; pattern++)
+ {
+ int prefix_len = strlen (pattern->prefix);
+ if (prefix_len == 0)
+ {
+ error = "empty pattern";
+
+ goto error;
+ }
+ if (pattern->mask)
+ {
+ int mask_len = strlen (pattern->mask);
+ if (mask_len != prefix_len)
+ {
+ error = "mask length mismatch";
+
+ goto error;
+ }
+ if (strspn (pattern->mask, " !xzn*") < mask_len)
+ {
+ error = "bad char in mask";
+
+ goto error;
+ }
+ }
+ }
+
+ if (!vtable->load && !vtable->begin_load && !vtable->load_animation)
+ {
+ error = "no load method implemented";
+
+ goto error;
+ }
+
+ if (vtable->begin_load && (!vtable->stop_load || !vtable->load_increment))
+ {
+ error = "incremental loading support incomplete";
+
+ goto error;
+ }
+
+ if ((info->flags & GDK_PIXBUF_FORMAT_WRITABLE) && !(vtable->save || vtable->save_to_callback))
+ {
+ error = "loader claims to support saving but doesn't implement save";
+ goto error;
+ }
+
+ return 1;
+
+ error:
+ g_fprintf (stderr, "Loader sanity check failed for %s: %s\n",
+ path, error);
+
+ return 0;
+}
+
+#ifdef GDK_PIXBUF_RELOCATABLE
+
+/* Based on gdk_pixbuf_get_toplevel () */
+static gchar *
+get_toplevel (void)
+{
+ static gchar *toplevel = NULL;
+
+ if (toplevel == NULL) {
+#if defined (G_OS_WIN32)
+ toplevel = g_win32_get_package_installation_directory_of_module (NULL);
+#elif defined(OS_DARWIN)
+ char pathbuf[PATH_MAX + 1];
+ uint32_t bufsize = sizeof (pathbuf);
+ gchar *bin_dir;
+
+ _NSGetExecutablePath (pathbuf, &bufsize);
+ bin_dir = g_path_get_dirname (pathbuf);
+ toplevel = g_build_path (G_DIR_SEPARATOR_S, bin_dir, "..", NULL);
+ g_free (bin_dir);
+#elif defined (OS_LINUX) || defined (__MINGW32__)
+ gchar *exe_path, *bin_dir;
+
+ exe_path = g_file_read_link ("/proc/self/exe", NULL);
+ bin_dir = g_path_get_dirname (exe_path);
+ toplevel = g_build_path (G_DIR_SEPARATOR_S, bin_dir, "..", NULL);
+ g_free (exe_path);
+ g_free (bin_dir);
+#else
+#error "Relocations not supported for this platform"
+#endif
+ }
+ return toplevel;
+}
+
+/* Returns the relative path or NULL; transfer full */
+static gchar *
+get_relative_path (const gchar *parent, const gchar *descendant)
+{
+ GFile *parent_file, *descendant_file;
+ char *relative_path;
+
+ parent_file = g_file_new_for_path (parent);
+ descendant_file = g_file_new_for_path (descendant);
+ relative_path = g_file_get_relative_path (parent_file, descendant_file);
+ g_object_unref (parent_file);
+ g_object_unref (descendant_file);
+
+ return relative_path;
+}
+
+#endif /* GDK_PIXBUF_RELOCATABLE */
+
+static void
+write_loader_info (GString *contents, const char *path, GdkPixbufFormat *info)
+{
+ const GdkPixbufModulePattern *pattern;
+ char **mime;
+ char **ext;
+ gchar *module_path = NULL, *escaped_path;
+
+#ifdef GDK_PIXBUF_RELOCATABLE
+ module_path = get_relative_path (get_toplevel (), path);
+#endif
+
+ if (module_path == NULL) {
+ module_path = g_strdup (path);
+ }
+
+ escaped_path = g_strescape (module_path, "");
+ g_string_append_printf (contents, "\"%s\"\n", escaped_path);
+ g_free (module_path);
+ g_free (escaped_path);
+
+ g_string_append_printf (contents, "\"%s\" %u \"%s\" \"%s\" \"%s\"\n",
+ info->name,
+ info->flags,
+ info->domain ? info->domain : GETTEXT_PACKAGE,
+ info->description,
+ info->license ? info->license : "");
+ for (mime = info->mime_types; *mime; mime++) {
+ g_string_append_printf (contents, "\"%s\" ", *mime);
+ }
+ g_string_append (contents, "\"\"\n");
+ for (ext = info->extensions; *ext; ext++) {
+ g_string_append_printf (contents, "\"%s\" ", *ext);
+ }
+ g_string_append (contents, "\"\"\n");
+ for (pattern = info->signature; pattern->prefix; pattern++) {
+ print_escaped (contents, pattern->prefix);
+ print_escaped (contents, pattern->mask ? (const char *)pattern->mask : "");
+ g_string_append_printf (contents, "%d\n", pattern->relevance);
+ }
+ g_string_append_c (contents, '\n');
+}
+
+static void
+query_module (GString *contents, const char *dir, const char *file)
+{
+ char *path;
+ GModule *module;
+ void (*fill_info) (GdkPixbufFormat *info);
+ void (*fill_vtable) (GdkPixbufModule *module);
+ gpointer fill_info_ptr;
+ gpointer fill_vtable_ptr;
+
+ if (g_path_is_absolute (file))
+ path = g_strdup (file);
+ else
+ path = g_build_filename (dir, file, NULL);
+
+ module = g_module_open (path, 0);
+ if (module &&
+ g_module_symbol (module, "fill_info", &fill_info_ptr) &&
+ g_module_symbol (module, "fill_vtable", &fill_vtable_ptr)) {
+ GdkPixbufFormat *info;
+ GdkPixbufModule *vtable;
+
+#ifdef G_OS_WIN32
+ /* Replace backslashes in path with forward slashes, so that
+ * it reads in without problems.
+ */
+ {
+ char *p = path;
+ while (*p) {
+ if (*p == '\\')
+ *p = '/';
+ p++;
+ }
+ }
+#endif
+ info = g_new0 (GdkPixbufFormat, 1);
+ vtable = g_new0 (GdkPixbufModule, 1);
+
+ vtable->module = module;
+
+ fill_info = fill_info_ptr;
+ fill_vtable = fill_vtable_ptr;
+
+ (*fill_info) (info);
+ (*fill_vtable) (vtable);
+
+ if (loader_sanity_check (path, info, vtable))
+ write_loader_info (contents, path, info);
+
+ g_free (info);
+ g_free (vtable);
+ }
+ else {
+ if (module == NULL)
+ g_fprintf (stderr, "g_module_open() failed for %s: %s\n", path,
+ g_module_error());
+ else
+ g_fprintf (stderr, "Cannot load loader %s\n", path);
+ }
+ if (module)
+ g_module_close (module);
+ g_free (path);
+}
+
+#if defined(G_OS_WIN32) && defined(GDK_PIXBUF_RELOCATABLE)
+
+static char *
+get_libdir (void)
+{
+ static char *libdir = NULL;
+
+ if (libdir == NULL)
+ libdir = g_build_filename (get_toplevel (), "lib", NULL);
+
+ return libdir;
+}
+
+#undef GDK_PIXBUF_LIBDIR
+#define GDK_PIXBUF_LIBDIR get_libdir()
+
+#endif
+
+static gchar *
+gdk_pixbuf_get_module_file (void)
+{
+ gchar *result = g_strdup (g_getenv ("GDK_PIXBUF_MODULE_FILE"));
+
+ if (!result)
+ result = g_build_filename (GDK_PIXBUF_LIBDIR, "gdk-pixbuf-2.0", GDK_PIXBUF_BINARY_VERSION, "loaders.cache", NULL);
+
+ return result;
+}
+
+int main (int argc, char **argv)
+{
+ gint i;
+ const gchar *prgname;
+ GString *contents;
+ gchar *cache_file = NULL;
+ gint first_file = 1;
+ GFile *pixbuf_libdir_file;
+ gchar *pixbuf_libdir;
+
+#ifdef G_OS_WIN32
+ gchar *libdir;
+ GFile *pixbuf_prefix_file;
+ gchar *pixbuf_prefix;
+#endif
+
+ /* An intermediate GFile here will convert all the path separators
+ * to the right one used by the platform
+ */
+ pixbuf_libdir_file = g_file_new_for_path (PIXBUF_LIBDIR);
+ pixbuf_libdir = g_file_get_path (pixbuf_libdir_file);
+ g_object_unref (pixbuf_libdir_file);
+
+#ifdef G_OS_WIN32
+ pixbuf_prefix_file = g_file_new_for_path (GDK_PIXBUF_PREFIX);
+ pixbuf_prefix = g_file_get_path (pixbuf_prefix_file);
+ g_object_unref (pixbuf_prefix_file);
+
+ if (g_ascii_strncasecmp (pixbuf_libdir, pixbuf_prefix, strlen (pixbuf_prefix)) == 0 &&
+ G_IS_DIR_SEPARATOR (pixbuf_libdir[strlen (pixbuf_prefix)])) {
+ gchar *runtime_prefix;
+ gchar *slash;
+
+ /* pixbuf_prefix is a prefix of pixbuf_libdir, as it
+ * normally is. Replace that prefix in pixbuf_libdir
+ * with the installation directory on this machine.
+ * We assume this invokation of
+ * gdk-pixbuf-query-loaders is run from either a "bin"
+ * subdirectory of the installation directory, or in
+ * the installation directory itself.
+ */
+ wchar_t fn[1000];
+ GetModuleFileNameW (NULL, fn, G_N_ELEMENTS (fn));
+ runtime_prefix = g_utf16_to_utf8 (fn, -1, NULL, NULL, NULL);
+ slash = strrchr (runtime_prefix, '\\');
+ *slash = '\0';
+ slash = strrchr (runtime_prefix, '\\');
+ /* If running from some weird location, or from the
+ * build directory (either in the .libs folder where
+ * libtool places the real executable when using a
+ * wrapper, or directly from the gdk-pixbuf folder),
+ * use the compile-time libdir.
+ */
+ if (slash == NULL ||
+ g_ascii_strcasecmp (slash + 1, ".libs") == 0 ||
+ g_ascii_strcasecmp (slash + 1, "gdk-pixbuf") == 0) {
+ libdir = NULL;
+ }
+ else {
+ if (slash != NULL && g_ascii_strcasecmp (slash + 1, "bin") == 0) {
+ *slash = '\0';
+ }
+
+ libdir = g_build_filename (runtime_prefix,
+ pixbuf_libdir + strlen (pixbuf_prefix) + 1,
+ NULL);
+ }
+ }
+ else {
+ libdir = NULL;
+ }
+
+ g_free (pixbuf_prefix);
+
+ if (libdir != NULL) {
+ g_free (pixbuf_libdir);
+ pixbuf_libdir = libdir;
+ }
+#endif
+
+ /* This call is necessary to ensure we actually link against libgobject;
+ * otherwise it may be stripped if -Wl,--as-needed is in use.
+ *
+ * The reason we need to link against libgobject is because it now has
+ * a global constructor. If the dynamically loaded modules happen
+ * to dlclose() libgobject, then reopen it again, we're in for trouble.
+ *
+ * See: https://bugzilla.gnome.org/show_bug.cgi?id=686822
+ */
+ g_type_ensure (G_TYPE_OBJECT);
+
+ if (argc > 1 && strcmp (argv[1], "--update-cache") == 0) {
+ cache_file = gdk_pixbuf_get_module_file ();
+ first_file = 2;
+ }
+
+ contents = g_string_new ("");
+
+ prgname = g_get_prgname ();
+ g_string_append_printf (contents,
+ "# GdkPixbuf Image Loader Modules file\n"
+ "# Automatically generated file, do not edit\n"
+ "# Created by %s from gdk-pixbuf-%s\n"
+ "#\n",
+ (prgname ? prgname : "gdk-pixbuf-query-loaders"),
+ GDK_PIXBUF_VERSION);
+
+ if (argc == first_file) {
+#ifdef USE_GMODULE
+ char *moduledir;
+ GDir *dir;
+ GList *l, *modules;
+
+ moduledir = g_strdup (g_getenv ("GDK_PIXBUF_MODULEDIR"));
+#ifdef G_OS_WIN32
+ if (moduledir != NULL && *moduledir != '\0') {
+ gchar *path;
+
+ path = g_locale_to_utf8 (moduledir, -1, NULL, NULL, NULL);
+ g_free (moduledir);
+ moduledir = path;
+ }
+#endif
+ if (moduledir == NULL || *moduledir == '\0') {
+ g_free (moduledir);
+ moduledir = g_strdup (pixbuf_libdir);
+ }
+
+ g_string_append_printf (contents, "# LoaderDir = %s\n#\n", moduledir);
+
+ modules = NULL;
+ dir = g_dir_open (moduledir, 0, NULL);
+ if (dir) {
+ const char *dent;
+
+ while ((dent = g_dir_read_name (dir))) {
+ gint len = strlen (dent);
+ if (len > SOEXT_LEN &&
+ strcmp (dent + len - SOEXT_LEN, SOEXT) == 0) {
+ modules = g_list_prepend (modules,
+ g_strdup (dent));
+ }
+ }
+ g_dir_close (dir);
+ }
+ modules = g_list_sort (modules, (GCompareFunc)strcmp);
+ for (l = modules; l != NULL; l = l->next)
+ query_module (contents, moduledir, l->data);
+ g_list_free_full (modules, g_free);
+ g_free (moduledir);
+#else
+ g_string_append_printf (contents, "# dynamic loading of modules not supported\n");
+#endif
+ }
+ else {
+ char *cwd = g_get_current_dir ();
+
+ for (i = first_file; i < argc; i++) {
+ char *infilename = argv[i];
+#ifdef G_OS_WIN32
+ infilename = g_locale_to_utf8 (infilename,
+ -1, NULL, NULL, NULL);
+#endif
+ query_module (contents, cwd, infilename);
+ }
+ g_free (cwd);
+ }
+
+ if (cache_file) {
+ GError *err;
+
+ err = NULL;
+ if (!g_file_set_contents (cache_file, contents->str, -1, &err)) {
+ g_fprintf (stderr, "%s\n", err->message);
+ }
+ }
+ else
+ g_print ("%s\n", contents->str);
+
+ g_free (pixbuf_libdir);
+
+ return 0;
+}
Index: create-2.42.9-dirname-patch/gdk-pixbuf-2.42.9-new/gdk-pixbuf
===================================================================
--- create-2.42.9-dirname-patch/gdk-pixbuf-2.42.9-new/gdk-pixbuf (nonexistent)
+++ create-2.42.9-dirname-patch/gdk-pixbuf-2.42.9-new/gdk-pixbuf (revision 5)
Property changes on: create-2.42.9-dirname-patch/gdk-pixbuf-2.42.9-new/gdk-pixbuf
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: create-2.42.9-dirname-patch/gdk-pixbuf-2.42.9-new
===================================================================
--- create-2.42.9-dirname-patch/gdk-pixbuf-2.42.9-new (nonexistent)
+++ create-2.42.9-dirname-patch/gdk-pixbuf-2.42.9-new (revision 5)
Property changes on: create-2.42.9-dirname-patch/gdk-pixbuf-2.42.9-new
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: create-2.42.9-dirname-patch
===================================================================
--- create-2.42.9-dirname-patch (nonexistent)
+++ create-2.42.9-dirname-patch (revision 5)
Property changes on: create-2.42.9-dirname-patch
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: patches/README
===================================================================
--- patches/README (nonexistent)
+++ patches/README (revision 5)
@@ -0,0 +1,6 @@
+
+/* begin *
+
+ TODO: Leave some comment here.
+
+ * end */
Index: patches
===================================================================
--- patches (nonexistent)
+++ patches (revision 5)
Property changes on: patches
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: .
===================================================================
--- . (nonexistent)
+++ . (revision 5)
Property changes on: .
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~