X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gdk-pixbuf%2Fio-xpm.c;h=b8a02d84cc4e02261bff97dd974376bbd89f04b5;hb=d722adb76abce67984f24a98433c245d86674b5c;hp=dcc4a8c30a264f16f0ea5af54ebf18f5fce9cfd9;hpb=d0f73034cf5e6c5b7f52ce7d31bd3b3d8cca0d4c;p=~andy%2Fgtk diff --git a/gdk-pixbuf/io-xpm.c b/gdk-pixbuf/io-xpm.c index dcc4a8c30..b8a02d84c 100644 --- a/gdk-pixbuf/io-xpm.c +++ b/gdk-pixbuf/io-xpm.c @@ -1,4 +1,5 @@ -/* GdkPixbuf library - JPEG image loader +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* GdkPixbuf library - XPM image loader * * Copyright (C) 1999 Mark Crichton * Copyright (C) 1999 The Free Software Foundation @@ -7,28 +8,33 @@ * Federico Mena-Quintero * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public + * 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 - * Library General Public License for more details. + * Lesser General Public License for more details. * - * You should have received a copy of the GNU Library General Public + * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ -#include +#include "config.h" #include +#include #include #include -#include -#include "gdk-pixbuf.h" - +#ifdef HAVE_UNISTD_H +#include /* for unlink */ +#endif +#include +#include "gdk-pixbuf-private.h" +#include "gdk-pixbuf-io.h" +#include /* I have must have done something to deserve this. @@ -46,9 +52,11 @@ enum buf_op { typedef struct { gchar *color_string; - GdkColor color; + guint16 red; + guint16 green; + guint16 blue; gint transparent; -} _XPMColor; +} XPMColor; struct file_handle { FILE *infile; @@ -61,20 +69,162 @@ struct mem_handle { int offset; }; +/* The following 2 routines (parse_color, find_color) come from Tk, via the Win32 + * port of GDK. The licensing terms on these (longer than the functions) is: + * + * This software is copyrighted by the Regents of the University of + * California, Sun Microsystems, Inc., and other parties. The following + * terms apply to all files associated with the software unless explicitly + * disclaimed in individual files. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + * + * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY + * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY + * DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE + * IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE + * NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR + * MODIFICATIONS. + * + * GOVERNMENT USE: If you are acquiring this software on behalf of the + * U.S. government, the Government shall have only "Restricted Rights" + * in the software and related documentation as defined in the Federal + * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you + * are acquiring the software on behalf of the Department of Defense, the + * software shall be classified as "Commercial Computer Software" and the + * Government shall have only "Restricted Rights" as defined in Clause + * 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the + * authors grant the U.S. Government and others acting in its behalf + * permission to use and distribute the software in accordance with the + * terms specified in this license. + */ + +#include "xpm-color-table.h" + +/* + *---------------------------------------------------------------------- + * + * find_color -- + * + * This routine finds the color entry that corresponds to the + * specified color. + * + * Results: + * Returns non-zero on success. The RGB values of the XColor + * will be initialized to the proper values on success. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +compare_xcolor_entries (const void *a, const void *b) +{ + return g_ascii_strcasecmp ((const char *) a, + color_names + ((const XPMColorEntry *)b)->name_offset); +} + +static gboolean +find_color(const char *name, + XPMColor *colorPtr) +{ + XPMColorEntry *found; + + found = bsearch (name, xColors, G_N_ELEMENTS (xColors), sizeof (XPMColorEntry), + compare_xcolor_entries); + if (found == NULL) + return FALSE; + + colorPtr->red = (found->red * 65535) / 255; + colorPtr->green = (found->green * 65535) / 255; + colorPtr->blue = (found->blue * 65535) / 255; + + return TRUE; +} + +/* + *---------------------------------------------------------------------- + * + * parse_color -- + * + * Partial implementation of X color name parsing interface. + * + * Results: + * Returns TRUE on success. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static gboolean +parse_color (const char *spec, + XPMColor *colorPtr) +{ + if (spec[0] == '#') { + char fmt[16]; + int i, red, green, blue; + + if ((i = strlen (spec + 1)) % 3) { + return FALSE; + } + i /= 3; + + g_snprintf (fmt, 16, "%%%dx%%%dx%%%dx", i, i, i); + + if (sscanf (spec + 1, fmt, &red, &green, &blue) != 3) { + return FALSE; + } + if (i == 4) { + colorPtr->red = red; + colorPtr->green = green; + colorPtr->blue = blue; + } else if (i == 1) { + colorPtr->red = (red * 65535) / 15; + colorPtr->green = (green * 65535) / 15; + colorPtr->blue = (blue * 65535) / 15; + } else if (i == 2) + { + colorPtr->red = (red * 65535) / 255; + colorPtr->green = (green * 65535) / 255; + colorPtr->blue = (blue * 65535) / 255; + } else /* if (i == 3) */ { + colorPtr->red = (red * 65535) / 4095; + colorPtr->green = (green * 65535) / 4095; + colorPtr->blue = (blue * 65535) / 4095; + } + } else { + if (!find_color(spec, colorPtr)) + return FALSE; + } + return TRUE; +} + static gint -xpm_seek_string (FILE *infile, const gchar *str, gint skip_comments) +xpm_seek_string (FILE *infile, const gchar *str) { char instr[1024]; while (!feof (infile)) { - fscanf (infile, "%1023s", instr); - if (skip_comments == TRUE && strcmp (instr, "/*") == 0) { - fscanf (infile, "%1023s", instr); - while (!feof (infile) && strcmp (instr, "*/") != 0) - fscanf (infile, "%1023s", instr); - fscanf (infile, "%1023s", instr); - } - + if (fscanf (infile, "%1023s", instr) < 0) + return FALSE; if (strcmp (instr, str) == 0) return TRUE; } @@ -159,96 +309,78 @@ xpm_read_string (FILE *infile, gchar **buffer, guint *buffer_size) return ret; } -static const gchar * -xpm_skip_whitespaces (const gchar *buffer) -{ - gint32 index = 0; - - while (buffer[index] != 0 && (buffer[index] == 0x20 || buffer[index] == 0x09)) - index++; - - return &buffer[index]; -} - -static const gchar * -xpm_skip_string (const gchar *buffer) -{ - gint32 index = 0; - - while (buffer[index] != 0 && buffer[index] != 0x20 && buffer[index] != 0x09) - index++; - - return &buffer[index]; -} - -/* Xlib crashed once at a color name lengths around 125 */ -#define MAX_COLOR_LEN 120 - static gchar * xpm_extract_color (const gchar *buffer) { - gint counter, numnames; - const gchar *ptr = NULL; - gchar ch, temp[128]; - gchar color[MAX_COLOR_LEN], *retcol; - gint space; - - counter = 0; - while (ptr == NULL) { - if ((buffer[counter] == 'c') || (buffer[counter] == 'g')) { - ch = buffer[counter + 1]; - if (ch == 0x20 || ch == 0x09) - ptr = &buffer[counter + 1]; - } else if (buffer[counter] == 0) - return NULL; - - counter++; - } - ptr = xpm_skip_whitespaces (ptr); - - if (ptr[0] == 0) - return NULL; - else if (ptr[0] == '#') { - counter = 1; - while (ptr[counter] != 0 && - ((ptr[counter] >= '0' && ptr[counter] <= '9') || - (ptr[counter] >= 'a' && ptr[counter] <= 'f') || - (ptr[counter] >= 'A' && ptr[counter] <= 'F'))) - counter++; - retcol = g_new (gchar, counter + 1); - strncpy (retcol, ptr, counter); - - retcol[counter] = 0; - - return retcol; - } - color[0] = 0; - numnames = 0; - - space = MAX_COLOR_LEN - 1; - while (space > 0) { - sscanf (ptr, "%127s", temp); - - if (((gint) ptr[0] == 0) || - (strcmp ("s", temp) == 0) || (strcmp ("m", temp) == 0) || - (strcmp ("g", temp) == 0) || (strcmp ("g4", temp) == 0)) - break; + const gchar *p = &buffer[0]; + gint new_key = 0; + gint key = 0; + gint current_key = 1; + gint space = 128; + gchar word[129], color[129], current_color[129]; + gchar *r; + + word[0] = '\0'; + color[0] = '\0'; + current_color[0] = '\0'; + while (1) { + /* skip whitespace */ + for (; *p != '\0' && g_ascii_isspace (*p); p++) { + } + /* copy word */ + for (r = word; *p != '\0' && !g_ascii_isspace (*p) && r - word < sizeof (word) - 1; p++, r++) { + *r = *p; + } + *r = '\0'; + if (*word == '\0') { + if (color[0] == '\0') /* incomplete colormap entry */ + return NULL; + else /* end of entry, still store the last color */ + new_key = 1; + } + else if (key > 0 && color[0] == '\0') /* next word must be a color name part */ + new_key = 0; else { - if (numnames > 0) { - space -= 1; - strcat (color, " "); + if (strcmp (word, "c") == 0) + new_key = 5; + else if (strcmp (word, "g") == 0) + new_key = 4; + else if (strcmp (word, "g4") == 0) + new_key = 3; + else if (strcmp (word, "m") == 0) + new_key = 2; + else if (strcmp (word, "s") == 0) + new_key = 1; + else + new_key = 0; + } + if (new_key == 0) { /* word is a color name part */ + if (key == 0) /* key expected */ + return NULL; + /* accumulate color name */ + if (color[0] != '\0') { + strncat (color, " ", space); + space -= MIN (space, 1); } - - strncat (color, temp, space); - space -= MIN (space, strlen (temp)); - ptr = xpm_skip_string (ptr); - ptr = xpm_skip_whitespaces (ptr); - numnames++; + strncat (color, word, space); + space -= MIN (space, strlen (word)); + } + else { /* word is a key */ + if (key > current_key) { + current_key = key; + strcpy (current_color, color); + } + space = 128; + color[0] = '\0'; + key = new_key; + if (*p == '\0') break; } + } - - retcol = g_strdup (color); - return retcol; + if (current_key > 1) + return g_strdup (current_color); + else + return NULL; } /* (almost) direct copy from gdkpixmap.c... loads an XPM from a file */ @@ -260,7 +392,7 @@ file_buffer (enum buf_op op, gpointer handle) switch (op) { case op_header: - if (xpm_seek_string (h->infile, "XPM", FALSE) != TRUE) + if (xpm_seek_string (h->infile, "XPM") != TRUE) break; if (xpm_seek_char (h->infile, '{') != TRUE) @@ -273,7 +405,8 @@ file_buffer (enum buf_op op, gpointer handle) /* Fall through to the xpm_read_string. */ case op_body: - xpm_read_string (h->infile, &h->buffer, &h->buffer_size); + if(!xpm_read_string (h->infile, &h->buffer, &h->buffer_size)) + return NULL; return h->buffer; default: @@ -309,52 +442,107 @@ mem_buffer (enum buf_op op, gpointer handle) return NULL; } -/* Destroy notification function for the libart pixbuf */ -static void -free_buffer (gpointer user_data, gpointer data) -{ - free (data); -} - /* This function does all the work. */ static GdkPixbuf * -pixbuf_create_from_xpm (const gchar * (*get_buf) (enum buf_op op, gpointer handle), gpointer handle) +pixbuf_create_from_xpm (const gchar * (*get_buf) (enum buf_op op, gpointer handle), gpointer handle, + GError **error) { - gint w, h, n_col, cpp; - gint cnt, xcnt, ycnt, wbytes, n, ns; + gint w, h, n_col, cpp, x_hot, y_hot, items; + gint cnt, xcnt, ycnt, wbytes, n; gint is_trans = FALSE; const gchar *buffer; gchar *name_buf; gchar pixel_str[32]; GHashTable *color_hash; - _XPMColor *colors, *color, *fallbackcolor; - guchar *pixels, *pixtmp; + XPMColor *colors, *color, *fallbackcolor; + guchar *pixtmp; + GdkPixbuf *pixbuf; fallbackcolor = NULL; buffer = (*get_buf) (op_header, handle); if (!buffer) { - g_warning ("No XPM header found"); + g_set_error_literal (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("No XPM header found")); return NULL; } - sscanf (buffer, "%d %d %d %d", &w, &h, &n_col, &cpp); - if (cpp >= 32) { - g_warning ("XPM has more than 31 chars per pixel."); + items = sscanf (buffer, "%d %d %d %d %d %d", &w, &h, &n_col, &cpp, &x_hot, &y_hot); + + if (items != 4 && items != 6) { + g_set_error_literal (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Invalid XPM header")); + return NULL; + } + + if (w <= 0) { + g_set_error_literal (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("XPM file has image width <= 0")); + return NULL; + + } + if (h <= 0) { + g_set_error_literal (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("XPM file has image height <= 0")); + return NULL; + + } + if (cpp <= 0 || cpp >= 32) { + g_set_error_literal (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("XPM has invalid number of chars per pixel")); + return NULL; + } + if (n_col <= 0 || + n_col >= G_MAXINT / (cpp + 1) || + n_col >= G_MAXINT / sizeof (XPMColor)) { + g_set_error_literal (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("XPM file has invalid number of colors")); return NULL; } /* The hash is used for fast lookups of color from chars */ color_hash = g_hash_table_new (g_str_hash, g_str_equal); - name_buf = g_new (gchar, n_col * (cpp + 1)); - colors = g_new (_XPMColor, n_col); + name_buf = g_try_malloc (n_col * (cpp + 1)); + if (!name_buf) { + g_set_error_literal (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Cannot allocate memory for loading XPM image")); + g_hash_table_destroy (color_hash); + return NULL; + } + colors = (XPMColor *) g_try_malloc (sizeof (XPMColor) * n_col); + if (!colors) { + g_set_error_literal (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Cannot allocate memory for loading XPM image")); + g_hash_table_destroy (color_hash); + g_free (name_buf); + return NULL; + } for (cnt = 0; cnt < n_col; cnt++) { gchar *color_name; buffer = (*get_buf) (op_cmap, handle); if (!buffer) { - g_warning ("Can't load XPM colormap"); + g_set_error_literal (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Cannot read XPM colormap")); g_hash_table_destroy (color_hash); g_free (name_buf); g_free (colors); @@ -370,9 +558,12 @@ pixbuf_create_from_xpm (const gchar * (*get_buf) (enum buf_op op, gpointer handl color_name = xpm_extract_color (buffer); - if ((color_name == NULL) || (g_strcasecmp (color_name, "None") == 0) - || (gdk_color_parse (color_name, &color->color) == FALSE)) { + if ((color_name == NULL) || (g_ascii_strcasecmp (color_name, "None") == 0) + || (parse_color (color_name, color) == FALSE)) { color->transparent = TRUE; + color->red = 0; + color->green = 0; + color->blue = 0; is_trans = TRUE; } @@ -383,12 +574,13 @@ pixbuf_create_from_xpm (const gchar * (*get_buf) (enum buf_op op, gpointer handl fallbackcolor = color; } - if (is_trans) - pixels = malloc (w * h * 4); - else - pixels = malloc (w * h * 3); + pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, is_trans, 8, w, h); - if (!pixels) { + if (!pixbuf) { + g_set_error_literal (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Cannot allocate memory for loading XPM image")); g_hash_table_destroy (color_hash); g_free (colors); g_free (name_buf); @@ -396,17 +588,17 @@ pixbuf_create_from_xpm (const gchar * (*get_buf) (enum buf_op op, gpointer handl } wbytes = w * cpp; - pixtmp = pixels; for (ycnt = 0; ycnt < h; ycnt++) { + pixtmp = pixbuf->pixels + ycnt * pixbuf->rowstride; + buffer = (*get_buf) (op_body, handle); if ((!buffer) || (strlen (buffer) < wbytes)) continue; - for (n = 0, cnt = 0, xcnt = 0; n < wbytes; n += cpp, xcnt++) { + for (n = 0, xcnt = 0; n < wbytes; n += cpp, xcnt++) { strncpy (pixel_str, &buffer[n], cpp); pixel_str[cpp] = 0; - ns = 0; color = g_hash_table_lookup (color_hash, pixel_str); @@ -414,9 +606,9 @@ pixbuf_create_from_xpm (const gchar * (*get_buf) (enum buf_op op, gpointer handl if (!color) color = fallbackcolor; - *pixtmp++ = color->color.red >> 8; - *pixtmp++ = color->color.green >> 8; - *pixtmp++ = color->color.blue >> 8; + *pixtmp++ = color->red >> 8; + *pixtmp++ = color->green >> 8; + *pixtmp++ = color->blue >> 8; if (is_trans && color->transparent) *pixtmp++ = 0; @@ -429,37 +621,201 @@ pixbuf_create_from_xpm (const gchar * (*get_buf) (enum buf_op op, gpointer handl g_free (colors); g_free (name_buf); - return gdk_pixbuf_new_from_data (pixels, ART_PIX_RGB, is_trans, - w, h, is_trans ? (w * 4) : (w * 3), - free_buffer, NULL); + if (items == 6) { + gchar hot[10]; + g_snprintf (hot, 10, "%d", x_hot); + gdk_pixbuf_set_option (pixbuf, "x_hot", hot); + g_snprintf (hot, 10, "%d", y_hot); + gdk_pixbuf_set_option (pixbuf, "y_hot", hot); + + } + + return pixbuf; } /* Shared library entry point for file loading */ -GdkPixbuf * -image_load (FILE *f) +static GdkPixbuf * +gdk_pixbuf__xpm_image_load (FILE *f, + GError **error) { GdkPixbuf *pixbuf; struct file_handle h; memset (&h, 0, sizeof (h)); h.infile = f; - pixbuf = pixbuf_create_from_xpm (file_buffer, &h); + pixbuf = pixbuf_create_from_xpm (file_buffer, &h, error); g_free (h.buffer); return pixbuf; } /* Shared library entry point for memory loading */ -GdkPixbuf * -image_load_xpm_data (const gchar **data) +static GdkPixbuf * +gdk_pixbuf__xpm_image_load_xpm_data (const gchar **data) { GdkPixbuf *pixbuf; struct mem_handle h; - + GError *error = NULL; + h.data = data; h.offset = 0; - pixbuf = pixbuf_create_from_xpm (mem_buffer, &h); + pixbuf = pixbuf_create_from_xpm (mem_buffer, &h, &error); + + if (error) { + g_warning ("Inline XPM data is broken: %s", error->message); + g_error_free (error); + error = NULL; + } return pixbuf; } + +/* Progressive loader */ +typedef struct _XPMContext XPMContext; +struct _XPMContext +{ + GdkPixbufModulePreparedFunc prepare_func; + GdkPixbufModuleUpdatedFunc update_func; + gpointer user_data; + + gchar *tempname; + FILE *file; + gboolean all_okay; +}; + +/* + * FIXME xpm loading progressively is not properly implemented. + * Instead we will buffer to a file then load that file when done. + * This is very broken but it should be relayively simple to fix + * in the future. + */ +static gpointer +gdk_pixbuf__xpm_image_begin_load (GdkPixbufModuleSizeFunc size_func, + GdkPixbufModulePreparedFunc prepare_func, + GdkPixbufModuleUpdatedFunc update_func, + gpointer user_data, + GError **error) +{ + XPMContext *context; + gint fd; + + context = g_new (XPMContext, 1); + context->prepare_func = prepare_func; + context->update_func = update_func; + context->user_data = user_data; + context->all_okay = TRUE; + fd = g_file_open_tmp ("gdkpixbuf-xpm-tmp.XXXXXX", &context->tempname, + NULL); + if (fd < 0) { + g_free (context); + return NULL; + } + + context->file = fdopen (fd, "w+"); + if (context->file == NULL) { + g_free (context->tempname); + g_free (context); + return NULL; + } + + return context; +} + +static gboolean +gdk_pixbuf__xpm_image_stop_load (gpointer data, + GError **error) +{ + XPMContext *context = (XPMContext*) data; + GdkPixbuf *pixbuf; + gboolean retval = FALSE; + + g_return_val_if_fail (data != NULL, FALSE); + + fflush (context->file); + rewind (context->file); + if (context->all_okay) { + pixbuf = gdk_pixbuf__xpm_image_load (context->file, error); + + if (pixbuf != NULL) { + if (context->prepare_func) + (* context->prepare_func) (pixbuf, + NULL, + context->user_data); + if (context->update_func) + (* context->update_func) (pixbuf, 0, 0, pixbuf->width, pixbuf->height, context->user_data); + g_object_unref (pixbuf); + + retval = TRUE; + } + } + + fclose (context->file); + g_unlink (context->tempname); + g_free (context->tempname); + g_free ((XPMContext *) context); + + return retval; +} + +static gboolean +gdk_pixbuf__xpm_image_load_increment (gpointer data, + const guchar *buf, + guint size, + GError **error) +{ + XPMContext *context = (XPMContext *) data; + + g_return_val_if_fail (data != NULL, FALSE); + + if (fwrite (buf, sizeof (guchar), size, context->file) != size) { + gint save_errno = errno; + context->all_okay = FALSE; + g_set_error_literal (error, + G_FILE_ERROR, + g_file_error_from_errno (save_errno), + _("Failed to write to temporary file when loading XPM image")); + return FALSE; + } + + return TRUE; +} + +#ifndef INCLUDE_xpm +#define MODULE_ENTRY(function) G_MODULE_EXPORT void function +#else +#define MODULE_ENTRY(function) void _gdk_pixbuf__xpm_ ## function +#endif + +MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module) +{ + module->load = gdk_pixbuf__xpm_image_load; + module->load_xpm_data = gdk_pixbuf__xpm_image_load_xpm_data; + module->begin_load = gdk_pixbuf__xpm_image_begin_load; + module->stop_load = gdk_pixbuf__xpm_image_stop_load; + module->load_increment = gdk_pixbuf__xpm_image_load_increment; +} + +MODULE_ENTRY (fill_info) (GdkPixbufFormat *info) +{ + static GdkPixbufModulePattern signature[] = { + { "/* XPM */", NULL, 100 }, + { NULL, NULL, 0 } + }; + static gchar * mime_types[] = { + "image/x-xpixmap", + NULL + }; + static gchar * extensions[] = { + "xpm", + NULL + }; + + info->name = "xpm"; + info->signature = signature; + info->description = N_("The XPM image format"); + info->mime_types = mime_types; + info->extensions = extensions; + info->flags = GDK_PIXBUF_FORMAT_THREADSAFE; + info->license = "LGPL"; +}