| File: | _build/../cdk-pixbuf/io-xpm.c |
| Warning: | line 782, column 8 Value of 'errno' was not checked and may be overwritten by function 'fclose' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ | |||
| 2 | /* CdkPixbuf library - XPM image loader | |||
| 3 | * | |||
| 4 | * Copyright (C) 1999 Mark Crichton | |||
| 5 | * Copyright (C) 1999 The Free Software Foundation | |||
| 6 | * | |||
| 7 | * Authors: Mark Crichton <crichton@gimp.org> | |||
| 8 | * Federico Mena-Quintero <federico@gimp.org> | |||
| 9 | * | |||
| 10 | * This library is free software; you can redistribute it and/or | |||
| 11 | * modify it under the terms of the GNU Lesser General Public | |||
| 12 | * License as published by the Free Software Foundation; either | |||
| 13 | * version 2 of the License, or (at your option) any later version. | |||
| 14 | * | |||
| 15 | * This library is distributed in the hope that it will be useful, | |||
| 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| 18 | * Lesser General Public License for more details. | |||
| 19 | * | |||
| 20 | * You should have received a copy of the GNU Lesser General Public | |||
| 21 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |||
| 22 | */ | |||
| 23 | ||||
| 24 | #include "config.h" | |||
| 25 | #include <stdio.h> | |||
| 26 | #include <stdlib.h> | |||
| 27 | #include <string.h> | |||
| 28 | #include <glib.h> | |||
| 29 | #ifdef HAVE_UNISTD_H1 | |||
| 30 | #include <unistd.h> /* for unlink */ | |||
| 31 | #endif | |||
| 32 | #include <errno(*__errno_location ()).h> | |||
| 33 | #include <glib/gstdio.h> | |||
| 34 | #include <glib/gi18n-lib.h> | |||
| 35 | #include "cdk-pixbuf-core.h" | |||
| 36 | #include "cdk-pixbuf-io.h" | |||
| 37 | ||||
| 38 | ||||
| 39 | ||||
| 40 | ||||
| 41 | /* I have must have done something to deserve this. | |||
| 42 | * XPM is such a crappy format to handle. | |||
| 43 | * This code is an ugly hybrid from cdkpixmap.c | |||
| 44 | * modified to respect transparent colors. | |||
| 45 | * It's still a mess, though. | |||
| 46 | */ | |||
| 47 | ||||
| 48 | enum buf_op { | |||
| 49 | op_header, | |||
| 50 | op_cmap, | |||
| 51 | op_body | |||
| 52 | }; | |||
| 53 | ||||
| 54 | typedef struct { | |||
| 55 | gchar *color_string; | |||
| 56 | guint16 red; | |||
| 57 | guint16 green; | |||
| 58 | guint16 blue; | |||
| 59 | gint transparent; | |||
| 60 | } XPMColor; | |||
| 61 | ||||
| 62 | struct file_handle { | |||
| 63 | FILE *infile; | |||
| 64 | gchar *buffer; | |||
| 65 | guint buffer_size; | |||
| 66 | }; | |||
| 67 | ||||
| 68 | struct mem_handle { | |||
| 69 | const gchar **data; | |||
| 70 | int offset; | |||
| 71 | }; | |||
| 72 | ||||
| 73 | /* The following 2 routines (parse_color, find_color) come from Tk, via the Win32 | |||
| 74 | * port of CDK. The licensing terms on these (longer than the functions) is: | |||
| 75 | * | |||
| 76 | * This software is copyrighted by the Regents of the University of | |||
| 77 | * California, Sun Microsystems, Inc., and other parties. The following | |||
| 78 | * terms apply to all files associated with the software unless explicitly | |||
| 79 | * disclaimed in individual files. | |||
| 80 | * | |||
| 81 | * The authors hereby grant permission to use, copy, modify, distribute, | |||
| 82 | * and license this software and its documentation for any purpose, provided | |||
| 83 | * that existing copyright notices are retained in all copies and that this | |||
| 84 | * notice is included verbatim in any distributions. No written agreement, | |||
| 85 | * license, or royalty fee is required for any of the authorized uses. | |||
| 86 | * Modifications to this software may be copyrighted by their authors | |||
| 87 | * and need not follow the licensing terms described here, provided that | |||
| 88 | * the new terms are clearly indicated on the first page of each file where | |||
| 89 | * they apply. | |||
| 90 | * | |||
| 91 | * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY | |||
| 92 | * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES | |||
| 93 | * ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY | |||
| 94 | * DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE | |||
| 95 | * POSSIBILITY OF SUCH DAMAGE. | |||
| 96 | * | |||
| 97 | * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, | |||
| 98 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, | |||
| 99 | * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE | |||
| 100 | * IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE | |||
| 101 | * NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR | |||
| 102 | * MODIFICATIONS. | |||
| 103 | * | |||
| 104 | * GOVERNMENT USE: If you are acquiring this software on behalf of the | |||
| 105 | * U.S. government, the Government shall have only "Restricted Rights" | |||
| 106 | * in the software and related documentation as defined in the Federal | |||
| 107 | * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you | |||
| 108 | * are acquiring the software on behalf of the Department of Defense, the | |||
| 109 | * software shall be classified as "Commercial Computer Software" and the | |||
| 110 | * Government shall have only "Restricted Rights" as defined in Clause | |||
| 111 | * 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the | |||
| 112 | * authors grant the U.S. Government and others acting in its behalf | |||
| 113 | * permission to use and distribute the software in accordance with the | |||
| 114 | * terms specified in this license. | |||
| 115 | */ | |||
| 116 | ||||
| 117 | #include "xpm-color-table.h" | |||
| 118 | ||||
| 119 | /* | |||
| 120 | *---------------------------------------------------------------------- | |||
| 121 | * | |||
| 122 | * find_color -- | |||
| 123 | * | |||
| 124 | * This routine finds the color entry that corresponds to the | |||
| 125 | * specified color. | |||
| 126 | * | |||
| 127 | * Results: | |||
| 128 | * Returns non-zero on success. The RGB values of the XColor | |||
| 129 | * will be initialized to the proper values on success. | |||
| 130 | * | |||
| 131 | * Side effects: | |||
| 132 | * None. | |||
| 133 | * | |||
| 134 | *---------------------------------------------------------------------- | |||
| 135 | */ | |||
| 136 | ||||
| 137 | static int | |||
| 138 | compare_xcolor_entries (const void *a, const void *b) | |||
| 139 | { | |||
| 140 | return g_ascii_strcasecmp ((const char *) a, | |||
| 141 | color_names + ((const XPMColorEntry *)b)->name_offset); | |||
| 142 | } | |||
| 143 | ||||
| 144 | static gboolean | |||
| 145 | find_color(const char *name, | |||
| 146 | XPMColor *colorPtr) | |||
| 147 | { | |||
| 148 | XPMColorEntry *found; | |||
| 149 | ||||
| 150 | found = bsearch (name, xColors, G_N_ELEMENTS (xColors)(sizeof (xColors) / sizeof ((xColors)[0])), sizeof (XPMColorEntry), | |||
| 151 | compare_xcolor_entries); | |||
| 152 | if (found == NULL((void*)0)) | |||
| 153 | return FALSE(0); | |||
| 154 | ||||
| 155 | colorPtr->red = (found->red * 65535) / 255; | |||
| 156 | colorPtr->green = (found->green * 65535) / 255; | |||
| 157 | colorPtr->blue = (found->blue * 65535) / 255; | |||
| 158 | ||||
| 159 | return TRUE(!(0)); | |||
| 160 | } | |||
| 161 | ||||
| 162 | /* | |||
| 163 | *---------------------------------------------------------------------- | |||
| 164 | * | |||
| 165 | * parse_color -- | |||
| 166 | * | |||
| 167 | * Partial implementation of X color name parsing interface. | |||
| 168 | * | |||
| 169 | * Results: | |||
| 170 | * Returns TRUE on success. | |||
| 171 | * | |||
| 172 | * Side effects: | |||
| 173 | * None. | |||
| 174 | * | |||
| 175 | *---------------------------------------------------------------------- | |||
| 176 | */ | |||
| 177 | ||||
| 178 | static gboolean | |||
| 179 | parse_color (const char *spec, | |||
| 180 | XPMColor *colorPtr) | |||
| 181 | { | |||
| 182 | if (spec[0] == '#') { | |||
| 183 | int i, red, green, blue; | |||
| 184 | ||||
| 185 | if ((i = strlen (spec + 1)) % 3) { | |||
| 186 | return FALSE(0); | |||
| 187 | } | |||
| 188 | i /= 3; | |||
| 189 | ||||
| 190 | if (i == 4) { | |||
| 191 | if (sscanf (spec + 1, "%4x%4x%4x", &red, &green, &blue) != 3) | |||
| 192 | return FALSE(0); | |||
| 193 | colorPtr->red = red; | |||
| 194 | colorPtr->green = green; | |||
| 195 | colorPtr->blue = blue; | |||
| 196 | } else if (i == 1) { | |||
| 197 | if (sscanf (spec + 1, "%1x%1x%1x", &red, &green, &blue) != 3) | |||
| 198 | return FALSE(0); | |||
| 199 | colorPtr->red = (red * 65535) / 15; | |||
| 200 | colorPtr->green = (green * 65535) / 15; | |||
| 201 | colorPtr->blue = (blue * 65535) / 15; | |||
| 202 | } else if (i == 2) { | |||
| 203 | if (sscanf (spec + 1, "%2x%2x%2x", &red, &green, &blue) != 3) | |||
| 204 | return FALSE(0); | |||
| 205 | colorPtr->red = (red * 65535) / 255; | |||
| 206 | colorPtr->green = (green * 65535) / 255; | |||
| 207 | colorPtr->blue = (blue * 65535) / 255; | |||
| 208 | } else /* if (i == 3) */ { | |||
| 209 | if (sscanf (spec + 1, "%3x%3x%3x", &red, &green, &blue) != 3) | |||
| 210 | return FALSE(0); | |||
| 211 | colorPtr->red = (red * 65535) / 4095; | |||
| 212 | colorPtr->green = (green * 65535) / 4095; | |||
| 213 | colorPtr->blue = (blue * 65535) / 4095; | |||
| 214 | } | |||
| 215 | } else { | |||
| 216 | if (!find_color(spec, colorPtr)) | |||
| 217 | return FALSE(0); | |||
| 218 | } | |||
| 219 | return TRUE(!(0)); | |||
| 220 | } | |||
| 221 | ||||
| 222 | static gint | |||
| 223 | xpm_seek_string (FILE *infile, const gchar *str) | |||
| 224 | { | |||
| 225 | char instr[1024]; | |||
| 226 | ||||
| 227 | while (!feof (infile)) { | |||
| 228 | if (fscanf (infile, "%1023s", instr) < 0) | |||
| 229 | return FALSE(0); | |||
| 230 | if (strcmp (instr, str) == 0) | |||
| 231 | return TRUE(!(0)); | |||
| 232 | } | |||
| 233 | ||||
| 234 | return FALSE(0); | |||
| 235 | } | |||
| 236 | ||||
| 237 | static gint | |||
| 238 | xpm_seek_char (FILE *infile, gchar c) | |||
| 239 | { | |||
| 240 | gint b, oldb; | |||
| 241 | ||||
| 242 | while ((b = getc (infile)) != EOF(-1)) { | |||
| 243 | if (c != b && b == '/') { | |||
| 244 | b = getc (infile); | |||
| 245 | if (b == EOF(-1)) | |||
| 246 | return FALSE(0); | |||
| 247 | ||||
| 248 | else if (b == '*') { /* we have a comment */ | |||
| 249 | b = -1; | |||
| 250 | do { | |||
| 251 | oldb = b; | |||
| 252 | b = getc (infile); | |||
| 253 | if (b == EOF(-1)) | |||
| 254 | return FALSE(0); | |||
| 255 | } while (!(oldb == '*' && b == '/')); | |||
| 256 | } | |||
| 257 | } else if (c == b) | |||
| 258 | return TRUE(!(0)); | |||
| 259 | } | |||
| 260 | ||||
| 261 | return FALSE(0); | |||
| 262 | } | |||
| 263 | ||||
| 264 | static gint | |||
| 265 | xpm_read_string (FILE *infile, gchar **buffer, guint *buffer_size) | |||
| 266 | { | |||
| 267 | gint c; | |||
| 268 | guint cnt = 0, bufsiz, ret = FALSE(0); | |||
| 269 | gchar *buf; | |||
| 270 | ||||
| 271 | buf = *buffer; | |||
| 272 | bufsiz = *buffer_size; | |||
| 273 | if (buf == NULL((void*)0)) { | |||
| 274 | bufsiz = 10 * sizeof (gchar); | |||
| 275 | buf = g_new (gchar, bufsiz)(gchar *) (__extension__ ({ gsize __n = (gsize) (bufsiz); gsize __s = sizeof (gchar); gpointer __p; if (__s == 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n) && (__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s)) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s); __p; })); | |||
| 276 | } | |||
| 277 | ||||
| 278 | do { | |||
| 279 | c = getc (infile); | |||
| 280 | } while (c != EOF(-1) && c != '"'); | |||
| 281 | ||||
| 282 | if (c != '"') | |||
| 283 | goto out; | |||
| 284 | ||||
| 285 | while ((c = getc (infile)) != EOF(-1)) { | |||
| 286 | if (cnt == bufsiz) { | |||
| 287 | guint new_size = bufsiz * 2; | |||
| 288 | ||||
| 289 | if (new_size > bufsiz) | |||
| 290 | bufsiz = new_size; | |||
| 291 | else | |||
| 292 | goto out; | |||
| 293 | ||||
| 294 | buf = g_realloc (buf, bufsiz); | |||
| 295 | buf[bufsiz - 1] = '\0'; | |||
| 296 | } | |||
| 297 | ||||
| 298 | if (c != '"') | |||
| 299 | buf[cnt++] = c; | |||
| 300 | else { | |||
| 301 | buf[cnt] = 0; | |||
| 302 | ret = TRUE(!(0)); | |||
| 303 | break; | |||
| 304 | } | |||
| 305 | } | |||
| 306 | ||||
| 307 | out: | |||
| 308 | buf[bufsiz - 1] = '\0'; /* ensure null termination for errors */ | |||
| 309 | *buffer = buf; | |||
| 310 | *buffer_size = bufsiz; | |||
| 311 | return ret; | |||
| 312 | } | |||
| 313 | ||||
| 314 | static gchar * | |||
| 315 | xpm_extract_color (const gchar *buffer) | |||
| 316 | { | |||
| 317 | const gchar *p = &buffer[0]; | |||
| 318 | gint new_key = 0; | |||
| 319 | gint key = 0; | |||
| 320 | gint current_key = 1; | |||
| 321 | gint space = 128; | |||
| 322 | gchar word[129], color[129], current_color[129]; | |||
| 323 | gchar *r; | |||
| 324 | ||||
| 325 | word[0] = '\0'; | |||
| 326 | color[0] = '\0'; | |||
| 327 | current_color[0] = '\0'; | |||
| 328 | while (1) { | |||
| 329 | /* skip whitespace */ | |||
| 330 | for (; *p != '\0' && g_ascii_isspace (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0); p++) { | |||
| 331 | } | |||
| 332 | /* copy word */ | |||
| 333 | for (r = word; *p != '\0' && !g_ascii_isspace (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0) && r - word < sizeof (word) - 1; p++, r++) { | |||
| 334 | *r = *p; | |||
| 335 | } | |||
| 336 | *r = '\0'; | |||
| 337 | if (*word == '\0') { | |||
| 338 | if (color[0] == '\0') /* incomplete colormap entry */ | |||
| 339 | return NULL((void*)0); | |||
| 340 | else /* end of entry, still store the last color */ | |||
| 341 | new_key = 1; | |||
| 342 | } | |||
| 343 | else if (key > 0 && color[0] == '\0') /* next word must be a color name part */ | |||
| 344 | new_key = 0; | |||
| 345 | else { | |||
| 346 | if (strcmp (word, "c") == 0) | |||
| 347 | new_key = 5; | |||
| 348 | else if (strcmp (word, "g") == 0) | |||
| 349 | new_key = 4; | |||
| 350 | else if (strcmp (word, "g4") == 0) | |||
| 351 | new_key = 3; | |||
| 352 | else if (strcmp (word, "m") == 0) | |||
| 353 | new_key = 2; | |||
| 354 | else if (strcmp (word, "s") == 0) | |||
| 355 | new_key = 1; | |||
| 356 | else | |||
| 357 | new_key = 0; | |||
| 358 | } | |||
| 359 | if (new_key == 0) { /* word is a color name part */ | |||
| 360 | if (key == 0) /* key expected */ | |||
| 361 | return NULL((void*)0); | |||
| 362 | /* accumulate color name */ | |||
| 363 | if (color[0] != '\0') { | |||
| 364 | strncat (color, " ", space); | |||
| 365 | space -= MIN (space, 1)(((space) < (1)) ? (space) : (1)); | |||
| 366 | } | |||
| 367 | strncat (color, word, space); | |||
| 368 | space -= MIN (space, strlen (word))(((space) < (strlen (word))) ? (space) : (strlen (word))); | |||
| 369 | } | |||
| 370 | else { /* word is a key */ | |||
| 371 | if (key > current_key) { | |||
| 372 | current_key = key; | |||
| 373 | strcpy (current_color, color); | |||
| 374 | } | |||
| 375 | space = 128; | |||
| 376 | color[0] = '\0'; | |||
| 377 | key = new_key; | |||
| 378 | if (*p == '\0') break; | |||
| 379 | } | |||
| 380 | ||||
| 381 | } | |||
| 382 | if (current_key > 1) | |||
| 383 | return g_strdup (current_color)g_strdup_inline (current_color); | |||
| 384 | else | |||
| 385 | return NULL((void*)0); | |||
| 386 | } | |||
| 387 | ||||
| 388 | /* (almost) direct copy from cdkpixmap.c... loads an XPM from a file */ | |||
| 389 | ||||
| 390 | static const gchar * | |||
| 391 | file_buffer (enum buf_op op, gpointer handle) | |||
| 392 | { | |||
| 393 | struct file_handle *h = handle; | |||
| 394 | ||||
| 395 | switch (op) { | |||
| 396 | case op_header: | |||
| 397 | if (xpm_seek_string (h->infile, "XPM") != TRUE(!(0))) | |||
| 398 | break; | |||
| 399 | ||||
| 400 | if (xpm_seek_char (h->infile, '{') != TRUE(!(0))) | |||
| 401 | break; | |||
| 402 | /* Fall through to the next xpm_seek_char. */ | |||
| 403 | ||||
| 404 | case op_cmap: | |||
| 405 | xpm_seek_char (h->infile, '"'); | |||
| 406 | if (fseek (h->infile, -1, SEEK_CUR1) != 0) | |||
| 407 | return NULL((void*)0); | |||
| 408 | /* Fall through to the xpm_read_string. */ | |||
| 409 | ||||
| 410 | case op_body: | |||
| 411 | if(!xpm_read_string (h->infile, &h->buffer, &h->buffer_size)) | |||
| 412 | return NULL((void*)0); | |||
| 413 | return h->buffer; | |||
| 414 | ||||
| 415 | default: | |||
| 416 | g_assert_not_reached ()do { g_assertion_message_expr ("CdkPixbuf", "../cdk-pixbuf/io-xpm.c" , 416, ((const char*) (__func__)), ((void*)0)); } while (0); | |||
| 417 | } | |||
| 418 | ||||
| 419 | return NULL((void*)0); | |||
| 420 | } | |||
| 421 | ||||
| 422 | /* This reads from memory */ | |||
| 423 | static const gchar * | |||
| 424 | mem_buffer (enum buf_op op, gpointer handle) | |||
| 425 | { | |||
| 426 | struct mem_handle *h = handle; | |||
| 427 | switch (op) { | |||
| 428 | case op_header: | |||
| 429 | case op_cmap: | |||
| 430 | case op_body: | |||
| 431 | if (h->data[h->offset]) { | |||
| 432 | const gchar* retval; | |||
| 433 | ||||
| 434 | retval = h->data[h->offset]; | |||
| 435 | h->offset += 1; | |||
| 436 | return retval; | |||
| 437 | } | |||
| 438 | break; | |||
| 439 | ||||
| 440 | default: | |||
| 441 | g_assert_not_reached ()do { g_assertion_message_expr ("CdkPixbuf", "../cdk-pixbuf/io-xpm.c" , 441, ((const char*) (__func__)), ((void*)0)); } while (0); | |||
| 442 | break; | |||
| 443 | } | |||
| 444 | ||||
| 445 | return NULL((void*)0); | |||
| 446 | } | |||
| 447 | ||||
| 448 | /* This function does all the work. */ | |||
| 449 | static CdkPixbuf * | |||
| 450 | pixbuf_create_from_xpm (const gchar * (*get_buf) (enum buf_op op, gpointer handle), gpointer handle, | |||
| 451 | GError **error) | |||
| 452 | { | |||
| 453 | gint w, h, n_col, cpp, x_hot, y_hot, items; | |||
| 454 | gint cnt, xcnt, ycnt, wbytes, n; | |||
| 455 | gint is_trans = FALSE(0); | |||
| 456 | const gchar *buffer; | |||
| 457 | gchar *name_buf; | |||
| 458 | gchar pixel_str[32]; | |||
| 459 | GHashTable *color_hash; | |||
| 460 | XPMColor *colors, *color, *fallbackcolor; | |||
| 461 | guchar *pixtmp; | |||
| 462 | CdkPixbuf *pixbuf = NULL((void*)0); | |||
| 463 | gint rowstride; | |||
| 464 | ||||
| 465 | fallbackcolor = NULL((void*)0); | |||
| 466 | ||||
| 467 | buffer = (*get_buf) (op_header, handle); | |||
| 468 | if (!buffer) { | |||
| 469 | g_set_error_literal (error, | |||
| 470 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 471 | CDK_PIXBUF_ERROR_CORRUPT_IMAGE, | |||
| 472 | _("No XPM header found")((char *) g_dgettext ("cdk-pixbuf", "No XPM header found"))); | |||
| 473 | return NULL((void*)0); | |||
| 474 | } | |||
| 475 | items = sscanf (buffer, "%d %d %d %d %d %d", &w, &h, &n_col, &cpp, &x_hot, &y_hot); | |||
| 476 | ||||
| 477 | if (items != 4 && items != 6) { | |||
| 478 | g_set_error_literal (error, | |||
| 479 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 480 | CDK_PIXBUF_ERROR_CORRUPT_IMAGE, | |||
| 481 | _("Invalid XPM header")((char *) g_dgettext ("cdk-pixbuf", "Invalid XPM header"))); | |||
| 482 | return NULL((void*)0); | |||
| 483 | } | |||
| 484 | ||||
| 485 | if (w <= 0) { | |||
| 486 | g_set_error_literal (error, | |||
| 487 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 488 | CDK_PIXBUF_ERROR_CORRUPT_IMAGE, | |||
| 489 | _("XPM file has image width <= 0")((char *) g_dgettext ("cdk-pixbuf", "XPM file has image width <= 0" ))); | |||
| 490 | return NULL((void*)0); | |||
| 491 | ||||
| 492 | } | |||
| 493 | if (h <= 0) { | |||
| 494 | g_set_error_literal (error, | |||
| 495 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 496 | CDK_PIXBUF_ERROR_CORRUPT_IMAGE, | |||
| 497 | _("XPM file has image height <= 0")((char *) g_dgettext ("cdk-pixbuf", "XPM file has image height <= 0" ))); | |||
| 498 | return NULL((void*)0); | |||
| 499 | ||||
| 500 | } | |||
| 501 | /* Check from libXpm's ParsePixels() */ | |||
| 502 | if ((h > 0 && w >= UINT_MAX(2147483647 *2U +1U) / h) || | |||
| 503 | w * h >= UINT_MAX(2147483647 *2U +1U) / sizeof(unsigned int)) { | |||
| 504 | g_set_error_literal (error, | |||
| 505 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 506 | CDK_PIXBUF_ERROR_CORRUPT_IMAGE, | |||
| 507 | _("Invalid XPM header")((char *) g_dgettext ("cdk-pixbuf", "Invalid XPM header"))); | |||
| 508 | return NULL((void*)0); | |||
| 509 | } | |||
| 510 | if (cpp <= 0 || cpp >= 32 || w >= G_MAXINT2147483647 / cpp) { | |||
| 511 | g_set_error_literal (error, | |||
| 512 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 513 | CDK_PIXBUF_ERROR_CORRUPT_IMAGE, | |||
| 514 | _("XPM has invalid number of chars per pixel")((char *) g_dgettext ("cdk-pixbuf", "XPM has invalid number of chars per pixel" ))); | |||
| 515 | return NULL((void*)0); | |||
| 516 | } | |||
| 517 | if (n_col <= 0 || | |||
| 518 | n_col >= G_MAXINT2147483647 / (cpp + 1) || | |||
| 519 | n_col >= G_MAXINT2147483647 / sizeof (XPMColor)) { | |||
| 520 | g_set_error_literal (error, | |||
| 521 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 522 | CDK_PIXBUF_ERROR_CORRUPT_IMAGE, | |||
| 523 | _("XPM file has invalid number of colors")((char *) g_dgettext ("cdk-pixbuf", "XPM file has invalid number of colors" ))); | |||
| 524 | return NULL((void*)0); | |||
| 525 | } | |||
| 526 | ||||
| 527 | /* The hash is used for fast lookups of color from chars */ | |||
| 528 | color_hash = g_hash_table_new (g_str_hash, g_str_equal); | |||
| 529 | ||||
| 530 | name_buf = g_try_malloc (n_col * (cpp + 1)); | |||
| 531 | if (!name_buf) { | |||
| 532 | g_set_error_literal (error, | |||
| 533 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 534 | CDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, | |||
| 535 | _("Cannot allocate memory for loading XPM image")((char *) g_dgettext ("cdk-pixbuf", "Cannot allocate memory for loading XPM image" ))); | |||
| 536 | g_hash_table_destroy (color_hash); | |||
| 537 | return NULL((void*)0); | |||
| 538 | } | |||
| 539 | colors = (XPMColor *) g_try_malloc (sizeof (XPMColor) * n_col); | |||
| 540 | if (!colors) { | |||
| 541 | g_set_error_literal (error, | |||
| 542 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 543 | CDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, | |||
| 544 | _("Cannot allocate memory for loading XPM image")((char *) g_dgettext ("cdk-pixbuf", "Cannot allocate memory for loading XPM image" ))); | |||
| 545 | g_hash_table_destroy (color_hash); | |||
| 546 | g_free (name_buf); | |||
| 547 | return NULL((void*)0); | |||
| 548 | } | |||
| 549 | ||||
| 550 | for (cnt = 0; cnt < n_col; cnt++) { | |||
| 551 | gchar *color_name; | |||
| 552 | ||||
| 553 | buffer = (*get_buf) (op_cmap, handle); | |||
| 554 | if (!buffer) { | |||
| 555 | g_set_error_literal (error, | |||
| 556 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 557 | CDK_PIXBUF_ERROR_CORRUPT_IMAGE, | |||
| 558 | _("Cannot read XPM colormap")((char *) g_dgettext ("cdk-pixbuf", "Cannot read XPM colormap" ))); | |||
| 559 | goto out; | |||
| 560 | } | |||
| 561 | ||||
| 562 | color = &colors[cnt]; | |||
| 563 | color->color_string = &name_buf[cnt * (cpp + 1)]; | |||
| 564 | strncpy (color->color_string, buffer, cpp); | |||
| 565 | color->color_string[cpp] = 0; | |||
| 566 | buffer += strlen (color->color_string); | |||
| 567 | color->transparent = FALSE(0); | |||
| 568 | ||||
| 569 | color_name = xpm_extract_color (buffer); | |||
| 570 | ||||
| 571 | if ((color_name == NULL((void*)0)) || (g_ascii_strcasecmp (color_name, "None") == 0) | |||
| 572 | || (parse_color (color_name, color) == FALSE(0))) { | |||
| 573 | color->transparent = TRUE(!(0)); | |||
| 574 | color->red = 0; | |||
| 575 | color->green = 0; | |||
| 576 | color->blue = 0; | |||
| 577 | is_trans = TRUE(!(0)); | |||
| 578 | } | |||
| 579 | ||||
| 580 | g_free (color_name); | |||
| 581 | g_hash_table_insert (color_hash, color->color_string, color); | |||
| 582 | ||||
| 583 | if (cnt == 0) | |||
| 584 | fallbackcolor = color; | |||
| 585 | } | |||
| 586 | ||||
| 587 | pixbuf = cdk_pixbuf_new (CDK_COLORSPACE_RGB, is_trans, 8, w, h); | |||
| 588 | ||||
| 589 | if (!pixbuf) { | |||
| 590 | g_set_error_literal (error, | |||
| 591 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 592 | CDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, | |||
| 593 | _("Cannot allocate memory for loading XPM image")((char *) g_dgettext ("cdk-pixbuf", "Cannot allocate memory for loading XPM image" ))); | |||
| 594 | goto out; | |||
| 595 | } | |||
| 596 | ||||
| 597 | rowstride = cdk_pixbuf_get_rowstride (pixbuf); | |||
| 598 | ||||
| 599 | wbytes = w * cpp; | |||
| 600 | ||||
| 601 | for (ycnt = 0; ycnt < h; ycnt++) { | |||
| 602 | pixtmp = cdk_pixbuf_get_pixels (pixbuf) + ycnt * rowstride; | |||
| 603 | ||||
| 604 | buffer = (*get_buf) (op_body, handle); | |||
| 605 | if ((!buffer) || (strlen (buffer) < wbytes)) { | |||
| 606 | /* Advertised width doesn't match pixels */ | |||
| 607 | g_set_error_literal (error, | |||
| 608 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 609 | CDK_PIXBUF_ERROR_CORRUPT_IMAGE, | |||
| 610 | _("Dimensions do not match data")((char *) g_dgettext ("cdk-pixbuf", "Dimensions do not match data" ))); | |||
| 611 | goto out; | |||
| 612 | } | |||
| 613 | ||||
| 614 | for (n = 0, xcnt = 0; n < wbytes; n += cpp, xcnt++) { | |||
| 615 | strncpy (pixel_str, &buffer[n], cpp); | |||
| 616 | pixel_str[cpp] = 0; | |||
| 617 | ||||
| 618 | color = g_hash_table_lookup (color_hash, pixel_str); | |||
| 619 | ||||
| 620 | /* Bad XPM...punt */ | |||
| 621 | if (!color) | |||
| 622 | color = fallbackcolor; | |||
| 623 | ||||
| 624 | *pixtmp++ = color->red >> 8; | |||
| 625 | *pixtmp++ = color->green >> 8; | |||
| 626 | *pixtmp++ = color->blue >> 8; | |||
| 627 | ||||
| 628 | if (is_trans && color->transparent) | |||
| 629 | *pixtmp++ = 0; | |||
| 630 | else if (is_trans) | |||
| 631 | *pixtmp++ = 0xFF; | |||
| 632 | } | |||
| 633 | } | |||
| 634 | ||||
| 635 | g_hash_table_destroy (color_hash); | |||
| 636 | g_free (colors); | |||
| 637 | g_free (name_buf); | |||
| 638 | ||||
| 639 | if (items == 6) { | |||
| 640 | gchar hot[10]; | |||
| 641 | g_snprintf (hot, 10, "%d", x_hot); | |||
| 642 | cdk_pixbuf_set_option (pixbuf, "x_hot", hot); | |||
| 643 | g_snprintf (hot, 10, "%d", y_hot); | |||
| 644 | cdk_pixbuf_set_option (pixbuf, "y_hot", hot); | |||
| 645 | ||||
| 646 | } | |||
| 647 | ||||
| 648 | return pixbuf; | |||
| 649 | ||||
| 650 | out: | |||
| 651 | g_hash_table_destroy (color_hash); | |||
| 652 | g_free (colors); | |||
| 653 | g_free (name_buf); | |||
| 654 | ||||
| 655 | g_clear_object (&pixbuf)do { _Static_assert (sizeof *((&pixbuf)) == sizeof (gpointer ), "Expression evaluates to false"); __typeof__ (((&pixbuf ))) _pp = ((&pixbuf)); __typeof__ (*((&pixbuf))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr) ; } while (0); | |||
| 656 | return NULL((void*)0); | |||
| 657 | } | |||
| 658 | ||||
| 659 | /* Shared library entry point for file loading */ | |||
| 660 | static CdkPixbuf * | |||
| 661 | cdk_pixbuf__xpm_image_load (FILE *f, | |||
| 662 | GError **error) | |||
| 663 | { | |||
| 664 | CdkPixbuf *pixbuf; | |||
| 665 | struct file_handle h; | |||
| 666 | ||||
| 667 | memset (&h, 0, sizeof (h)); | |||
| 668 | h.infile = f; | |||
| 669 | pixbuf = pixbuf_create_from_xpm (file_buffer, &h, error); | |||
| 670 | g_free (h.buffer); | |||
| 671 | ||||
| 672 | return pixbuf; | |||
| 673 | } | |||
| 674 | ||||
| 675 | /* Shared library entry point for memory loading */ | |||
| 676 | static CdkPixbuf * | |||
| 677 | cdk_pixbuf__xpm_image_load_xpm_data (const gchar **data) | |||
| 678 | { | |||
| 679 | CdkPixbuf *pixbuf; | |||
| 680 | struct mem_handle h; | |||
| 681 | GError *error = NULL((void*)0); | |||
| 682 | ||||
| 683 | h.data = data; | |||
| 684 | h.offset = 0; | |||
| 685 | ||||
| 686 | pixbuf = pixbuf_create_from_xpm (mem_buffer, &h, &error); | |||
| 687 | ||||
| 688 | if (error) { | |||
| 689 | g_warning ("Inline XPM data is broken: %s", error->message); | |||
| 690 | g_error_free (error); | |||
| 691 | error = NULL((void*)0); | |||
| 692 | } | |||
| 693 | ||||
| 694 | return pixbuf; | |||
| 695 | } | |||
| 696 | ||||
| 697 | /* Progressive loader */ | |||
| 698 | typedef struct _XPMContext XPMContext; | |||
| 699 | struct _XPMContext | |||
| 700 | { | |||
| 701 | CdkPixbufModulePreparedFunc prepared_func; | |||
| 702 | CdkPixbufModuleUpdatedFunc updated_func; | |||
| 703 | gpointer user_data; | |||
| 704 | ||||
| 705 | gchar *tempname; | |||
| 706 | FILE *file; | |||
| 707 | gboolean all_okay; | |||
| 708 | }; | |||
| 709 | ||||
| 710 | /* | |||
| 711 | * FIXME xpm loading progressively is not properly implemented. | |||
| 712 | * Instead we will buffer to a file then load that file when done. | |||
| 713 | * This is very broken but it should be relatively simple to fix | |||
| 714 | * in the future. | |||
| 715 | */ | |||
| 716 | static gpointer | |||
| 717 | cdk_pixbuf__xpm_image_begin_load (CdkPixbufModuleSizeFunc size_func, | |||
| 718 | CdkPixbufModulePreparedFunc prepared_func, | |||
| 719 | CdkPixbufModuleUpdatedFunc updated_func, | |||
| 720 | gpointer user_data, | |||
| 721 | GError **error) | |||
| 722 | { | |||
| 723 | XPMContext *context; | |||
| 724 | gint fd; | |||
| 725 | ||||
| 726 | g_assert (size_func != NULL)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_15 = 0; if (size_func != ((void*)0)) _g_boolean_var_15 = 1; _g_boolean_var_15 ; }), 1)) ; else g_assertion_message_expr ("CdkPixbuf", "../cdk-pixbuf/io-xpm.c" , 726, ((const char*) (__func__)), "size_func != NULL"); } while (0); | |||
| 727 | g_assert (prepared_func != NULL)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_16 = 0; if (prepared_func != ((void*)0)) _g_boolean_var_16 = 1; _g_boolean_var_16; }), 1)) ; else g_assertion_message_expr ( "CdkPixbuf", "../cdk-pixbuf/io-xpm.c", 727, ((const char*) (__func__ )), "prepared_func != NULL"); } while (0); | |||
| 728 | g_assert (updated_func != NULL)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_17 = 0; if (updated_func != ((void*)0)) _g_boolean_var_17 = 1; _g_boolean_var_17 ; }), 1)) ; else g_assertion_message_expr ("CdkPixbuf", "../cdk-pixbuf/io-xpm.c" , 728, ((const char*) (__func__)), "updated_func != NULL"); } while (0); | |||
| 729 | ||||
| 730 | context = g_new (XPMContext, 1)(XPMContext *) (__extension__ ({ gsize __n = (gsize) (1); gsize __s = sizeof (XPMContext); gpointer __p; if (__s == 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n) && (__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s )) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s ); __p; })); | |||
| 731 | context->prepared_func = prepared_func; | |||
| 732 | context->updated_func = updated_func; | |||
| 733 | context->user_data = user_data; | |||
| 734 | context->all_okay = TRUE(!(0)); | |||
| 735 | fd = g_file_open_tmp ("cdkpixbuf-xpm-tmp.XXXXXX", &context->tempname, | |||
| 736 | NULL((void*)0)); | |||
| 737 | if (fd < 0) { | |||
| 738 | g_free (context); | |||
| 739 | return NULL((void*)0); | |||
| 740 | } | |||
| 741 | ||||
| 742 | context->file = fdopen (fd, "w+"); | |||
| 743 | if (context->file == NULL((void*)0)) { | |||
| 744 | g_free (context->tempname); | |||
| 745 | g_free (context); | |||
| 746 | return NULL((void*)0); | |||
| 747 | } | |||
| 748 | ||||
| 749 | return context; | |||
| 750 | } | |||
| 751 | ||||
| 752 | static gboolean | |||
| 753 | cdk_pixbuf__xpm_image_stop_load (gpointer data, | |||
| 754 | GError **error) | |||
| 755 | { | |||
| 756 | XPMContext *context = (XPMContext*) data; | |||
| 757 | CdkPixbuf *pixbuf; | |||
| 758 | gboolean retval = FALSE(0); | |||
| 759 | ||||
| 760 | g_return_val_if_fail (data != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_18 = 0; if (data != ((void*)0)) _g_boolean_var_18 = 1; _g_boolean_var_18 ; }), 1))) { } else { g_return_if_fail_warning ("CdkPixbuf", ( (const char*) (__func__)), "data != NULL"); return ((0)); } } while (0); | |||
| ||||
| 761 | ||||
| 762 | fflush (context->file); | |||
| 763 | rewind (context->file); | |||
| 764 | if (context->all_okay) { | |||
| 765 | pixbuf = cdk_pixbuf__xpm_image_load (context->file, error); | |||
| 766 | ||||
| 767 | if (pixbuf != NULL((void*)0)) { | |||
| 768 | (* context->prepared_func) (pixbuf, | |||
| 769 | NULL((void*)0), | |||
| 770 | context->user_data); | |||
| 771 | (* context->updated_func) (pixbuf, | |||
| 772 | 0, 0, | |||
| 773 | cdk_pixbuf_get_width (pixbuf), | |||
| 774 | cdk_pixbuf_get_height (pixbuf), | |||
| 775 | context->user_data); | |||
| 776 | g_object_unref (pixbuf); | |||
| 777 | ||||
| 778 | retval = TRUE(!(0)); | |||
| 779 | } | |||
| 780 | } | |||
| 781 | ||||
| 782 | fclose (context->file); | |||
| ||||
| 783 | g_unlink (context->tempname); | |||
| 784 | g_free (context->tempname); | |||
| 785 | g_free ((XPMContext *) context); | |||
| 786 | ||||
| 787 | return retval; | |||
| 788 | } | |||
| 789 | ||||
| 790 | static gboolean | |||
| 791 | cdk_pixbuf__xpm_image_load_increment (gpointer data, | |||
| 792 | const guchar *buf, | |||
| 793 | guint size, | |||
| 794 | GError **error) | |||
| 795 | { | |||
| 796 | XPMContext *context = (XPMContext *) data; | |||
| 797 | ||||
| 798 | g_return_val_if_fail (data != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_19 = 0; if (data != ((void*)0)) _g_boolean_var_19 = 1; _g_boolean_var_19 ; }), 1))) { } else { g_return_if_fail_warning ("CdkPixbuf", ( (const char*) (__func__)), "data != NULL"); return ((0)); } } while (0); | |||
| 799 | ||||
| 800 | if (fwrite (buf, sizeof (guchar), size, context->file) != size) { | |||
| 801 | gint save_errno = errno(*__errno_location ()); | |||
| 802 | context->all_okay = FALSE(0); | |||
| 803 | g_set_error_literal (error, | |||
| 804 | G_FILE_ERRORg_file_error_quark (), | |||
| 805 | g_file_error_from_errno (save_errno), | |||
| 806 | _("Failed to write to temporary file when loading XPM image")((char *) g_dgettext ("cdk-pixbuf", "Failed to write to temporary file when loading XPM image" ))); | |||
| 807 | return FALSE(0); | |||
| 808 | } | |||
| 809 | ||||
| 810 | return TRUE(!(0)); | |||
| 811 | } | |||
| 812 | ||||
| 813 | #ifndef INCLUDE_xpm | |||
| 814 | #define MODULE_ENTRY(function)__attribute__((visibility("default"))) void function G_MODULE_EXPORT__attribute__((visibility("default"))) void function | |||
| 815 | #else | |||
| 816 | #define MODULE_ENTRY(function)__attribute__((visibility("default"))) void function void _cdk_pixbuf__xpm_ ## function | |||
| 817 | #endif | |||
| 818 | ||||
| 819 | MODULE_ENTRY (fill_vtable)__attribute__((visibility("default"))) void fill_vtable (CdkPixbufModule *module) | |||
| 820 | { | |||
| 821 | module->load = cdk_pixbuf__xpm_image_load; | |||
| 822 | module->load_xpm_data = cdk_pixbuf__xpm_image_load_xpm_data; | |||
| 823 | module->begin_load = cdk_pixbuf__xpm_image_begin_load; | |||
| 824 | module->stop_load = cdk_pixbuf__xpm_image_stop_load; | |||
| 825 | module->load_increment = cdk_pixbuf__xpm_image_load_increment; | |||
| 826 | } | |||
| 827 | ||||
| 828 | MODULE_ENTRY (fill_info)__attribute__((visibility("default"))) void fill_info (CdkPixbufFormat *info) | |||
| 829 | { | |||
| 830 | static const CdkPixbufModulePattern signature[] = { | |||
| 831 | { "/* XPM */", NULL((void*)0), 100 }, | |||
| 832 | { NULL((void*)0), NULL((void*)0), 0 } | |||
| 833 | }; | |||
| 834 | static const gchar *mime_types[] = { | |||
| 835 | "image/x-xpixmap", | |||
| 836 | NULL((void*)0) | |||
| 837 | }; | |||
| 838 | static const gchar *extensions[] = { | |||
| 839 | "xpm", | |||
| 840 | NULL((void*)0) | |||
| 841 | }; | |||
| 842 | ||||
| 843 | info->name = "xpm"; | |||
| 844 | info->signature = (CdkPixbufModulePattern *) signature; | |||
| 845 | info->description = NC_("image format", "XPM")("XPM"); | |||
| 846 | info->mime_types = (gchar **) mime_types; | |||
| 847 | info->extensions = (gchar **) extensions; | |||
| 848 | info->flags = CDK_PIXBUF_FORMAT_THREADSAFE; | |||
| 849 | info->license = "LGPL"; | |||
| 850 | } |