diff options
Diffstat (limited to 'gdk-pixbuf/io-xpm.c')
-rw-r--r-- | gdk-pixbuf/io-xpm.c | 821 |
1 files changed, 0 insertions, 821 deletions
diff --git a/gdk-pixbuf/io-xpm.c b/gdk-pixbuf/io-xpm.c deleted file mode 100644 index b8a02d84cc..0000000000 --- a/gdk-pixbuf/io-xpm.c +++ /dev/null @@ -1,821 +0,0 @@ -/* -*- 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 - * - * Authors: Mark Crichton <crichton@gimp.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, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "config.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <glib.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> /* for unlink */ -#endif -#include <errno.h> -#include "gdk-pixbuf-private.h" -#include "gdk-pixbuf-io.h" -#include <glib/gstdio.h> - - -/* I have must have done something to deserve this. - * XPM is such a crappy format to handle. - * This code is an ugly hybred from gdkpixmap.c - * modified to respect transparent colors. - * It's still a mess, though. - */ - -enum buf_op { - op_header, - op_cmap, - op_body -}; - -typedef struct { - gchar *color_string; - guint16 red; - guint16 green; - guint16 blue; - gint transparent; -} XPMColor; - -struct file_handle { - FILE *infile; - gchar *buffer; - guint buffer_size; -}; - -struct mem_handle { - const gchar **data; - 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) -{ - char instr[1024]; - - while (!feof (infile)) { - if (fscanf (infile, "%1023s", instr) < 0) - return FALSE; - if (strcmp (instr, str) == 0) - return TRUE; - } - - return FALSE; -} - -static gint -xpm_seek_char (FILE *infile, gchar c) -{ - gint b, oldb; - - while ((b = getc (infile)) != EOF) { - if (c != b && b == '/') { - b = getc (infile); - if (b == EOF) - return FALSE; - - else if (b == '*') { /* we have a comment */ - b = -1; - do { - oldb = b; - b = getc (infile); - if (b == EOF) - return FALSE; - } while (!(oldb == '*' && b == '/')); - } - } else if (c == b) - return TRUE; - } - - return FALSE; -} - -static gint -xpm_read_string (FILE *infile, gchar **buffer, guint *buffer_size) -{ - gint c; - guint cnt = 0, bufsiz, ret = FALSE; - gchar *buf; - - buf = *buffer; - bufsiz = *buffer_size; - if (buf == NULL) { - bufsiz = 10 * sizeof (gchar); - buf = g_new (gchar, bufsiz); - } - - do { - c = getc (infile); - } while (c != EOF && c != '"'); - - if (c != '"') - goto out; - - while ((c = getc (infile)) != EOF) { - if (cnt == bufsiz) { - guint new_size = bufsiz * 2; - - if (new_size > bufsiz) - bufsiz = new_size; - else - goto out; - - buf = g_realloc (buf, bufsiz); - buf[bufsiz - 1] = '\0'; - } - - if (c != '"') - buf[cnt++] = c; - else { - buf[cnt] = 0; - ret = TRUE; - break; - } - } - - out: - buf[bufsiz - 1] = '\0'; /* ensure null termination for errors */ - *buffer = buf; - *buffer_size = bufsiz; - return ret; -} - -static gchar * -xpm_extract_color (const gchar *buffer) -{ - 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 (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, 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; - } - - } - if (current_key > 1) - return g_strdup (current_color); - else - return NULL; -} - -/* (almost) direct copy from gdkpixmap.c... loads an XPM from a file */ - -static const gchar * -file_buffer (enum buf_op op, gpointer handle) -{ - struct file_handle *h = handle; - - switch (op) { - case op_header: - if (xpm_seek_string (h->infile, "XPM") != TRUE) - break; - - if (xpm_seek_char (h->infile, '{') != TRUE) - break; - /* Fall through to the next xpm_seek_char. */ - - case op_cmap: - xpm_seek_char (h->infile, '"'); - fseek (h->infile, -1, SEEK_CUR); - /* Fall through to the xpm_read_string. */ - - case op_body: - if(!xpm_read_string (h->infile, &h->buffer, &h->buffer_size)) - return NULL; - return h->buffer; - - default: - g_assert_not_reached (); - } - - return NULL; -} - -/* This reads from memory */ -static const gchar * -mem_buffer (enum buf_op op, gpointer handle) -{ - struct mem_handle *h = handle; - switch (op) { - case op_header: - case op_cmap: - case op_body: - if (h->data[h->offset]) { - const gchar* retval; - - retval = h->data[h->offset]; - h->offset += 1; - return retval; - } - break; - - default: - g_assert_not_reached (); - break; - } - - return NULL; -} - -/* This function does all the work. */ -static GdkPixbuf * -pixbuf_create_from_xpm (const gchar * (*get_buf) (enum buf_op op, gpointer handle), gpointer handle, - GError **error) -{ - 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 *pixtmp; - GdkPixbuf *pixbuf; - - fallbackcolor = NULL; - - buffer = (*get_buf) (op_header, handle); - if (!buffer) { - g_set_error_literal (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_CORRUPT_IMAGE, - _("No XPM header found")); - return NULL; - } - 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_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_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); - return NULL; - } - - color = &colors[cnt]; - color->color_string = &name_buf[cnt * (cpp + 1)]; - strncpy (color->color_string, buffer, cpp); - color->color_string[cpp] = 0; - buffer += strlen (color->color_string); - color->transparent = FALSE; - - color_name = xpm_extract_color (buffer); - - 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; - } - - g_free (color_name); - g_hash_table_insert (color_hash, color->color_string, color); - - if (cnt == 0) - fallbackcolor = color; - } - - pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, is_trans, 8, w, h); - - 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); - return NULL; - } - - wbytes = w * cpp; - - 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, xcnt = 0; n < wbytes; n += cpp, xcnt++) { - strncpy (pixel_str, &buffer[n], cpp); - pixel_str[cpp] = 0; - - color = g_hash_table_lookup (color_hash, pixel_str); - - /* Bad XPM...punt */ - if (!color) - color = fallbackcolor; - - *pixtmp++ = color->red >> 8; - *pixtmp++ = color->green >> 8; - *pixtmp++ = color->blue >> 8; - - if (is_trans && color->transparent) - *pixtmp++ = 0; - else if (is_trans) - *pixtmp++ = 0xFF; - } - } - - g_hash_table_destroy (color_hash); - g_free (colors); - g_free (name_buf); - - 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 */ -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, error); - g_free (h.buffer); - - return pixbuf; -} - -/* Shared library entry point for memory loading */ -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, &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"; -} |