| File: | _build/../cdk-pixbuf/io-ico.c |
| Warning: | line 765, column 9 Array access (via field 'LineBuf') results in a null pointer dereference |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* -*- mode: C; c-file-style: "linux" -*- */ | |||
| 2 | /* CdkPixbuf library - Windows Icon/Cursor image loader | |||
| 3 | * | |||
| 4 | * Copyright (C) 1999 The Free Software Foundation | |||
| 5 | * | |||
| 6 | * Authors: Arjan van de Ven <arjan@fenrus.demon.nl> | |||
| 7 | * Federico Mena-Quintero <federico@gimp.org> | |||
| 8 | * | |||
| 9 | * Based on io-bmp.c | |||
| 10 | * | |||
| 11 | * This library is free software; you can redistribute it and/or | |||
| 12 | * modify it under the terms of the GNU Lesser General Public | |||
| 13 | * License as published by the Free Software Foundation; either | |||
| 14 | * version 2 of the License, or (at your option) any later version. | |||
| 15 | * | |||
| 16 | * This library is distributed in the hope that it will be useful, | |||
| 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| 19 | * Lesser General Public License for more details. | |||
| 20 | * | |||
| 21 | * You should have received a copy of the GNU Lesser General Public | |||
| 22 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |||
| 23 | */ | |||
| 24 | ||||
| 25 | #undef DUMPBIH | |||
| 26 | #define DEBUG(s) | |||
| 27 | ||||
| 28 | #define INFOHEADER_SIZE40 40 | |||
| 29 | ||||
| 30 | /* | |||
| 31 | ||||
| 32 | Icons are just like BMP's, except for the header. | |||
| 33 | ||||
| 34 | Known bugs: | |||
| 35 | * bi-tonal files aren't tested | |||
| 36 | ||||
| 37 | */ | |||
| 38 | ||||
| 39 | #include "config.h" | |||
| 40 | #include <stdio.h> | |||
| 41 | #include <stdlib.h> | |||
| 42 | #ifdef HAVE_UNISTD_H1 | |||
| 43 | #include <unistd.h> | |||
| 44 | #endif | |||
| 45 | #include <string.h> | |||
| 46 | #include <errno(*__errno_location ()).h> | |||
| 47 | #include <glib/gi18n-lib.h> | |||
| 48 | #include "cdk-pixbuf-io.h" | |||
| 49 | ||||
| 50 | ||||
| 51 | ||||
| 52 | /* | |||
| 53 | ||||
| 54 | These structures are actually dummies. These are according to | |||
| 55 | the "Windows API reference guide volume II" as written by | |||
| 56 | Borland International, but GCC fiddles with the alignment of | |||
| 57 | the internal members. | |||
| 58 | ||||
| 59 | */ | |||
| 60 | ||||
| 61 | struct BitmapFileHeader { | |||
| 62 | gushort bfType; | |||
| 63 | guint bfSize; | |||
| 64 | guint reserverd; | |||
| 65 | guint bfOffbits; | |||
| 66 | }; | |||
| 67 | ||||
| 68 | struct BitmapInfoHeader { | |||
| 69 | guint biSize; | |||
| 70 | guint biWidth; | |||
| 71 | guint biHeight; | |||
| 72 | gushort biPlanes; | |||
| 73 | gushort biBitCount; | |||
| 74 | guint biCompression; | |||
| 75 | guint biSizeImage; | |||
| 76 | guint biXPelsPerMeter; | |||
| 77 | guint biYPelsPerMeter; | |||
| 78 | guint biClrUsed; | |||
| 79 | guint biClrImportant; | |||
| 80 | }; | |||
| 81 | ||||
| 82 | #ifdef DUMPBIH | |||
| 83 | /* | |||
| 84 | ||||
| 85 | DumpBIH printf's the values in a BitmapInfoHeader to the screen, for | |||
| 86 | debugging purposes. | |||
| 87 | ||||
| 88 | */ | |||
| 89 | static void DumpBIH(unsigned char *BIH) | |||
| 90 | { | |||
| 91 | printf("biSize = %i \n", | |||
| 92 | (int)(BIH[3] << 24) + (BIH[2] << 16) + (BIH[1] << 8) + (BIH[0])); | |||
| 93 | printf("biWidth = %i \n", | |||
| 94 | (int)(BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) + (BIH[4])); | |||
| 95 | printf("biHeight = %i \n", | |||
| 96 | (int)(BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) + | |||
| 97 | (BIH[8])); | |||
| 98 | printf("biPlanes = %i \n", (int)(BIH[13] << 8) + (BIH[12])); | |||
| 99 | printf("biBitCount = %i \n", (int)(BIH[15] << 8) + (BIH[14])); | |||
| 100 | printf("biCompress = %i \n", | |||
| 101 | (int)(BIH[19] << 24) + (BIH[18] << 16) + (BIH[17] << 8) + | |||
| 102 | (BIH[16])); | |||
| 103 | printf("biSizeImage = %i \n", | |||
| 104 | (int)(BIH[23] << 24) + (BIH[22] << 16) + (BIH[21] << 8) + | |||
| 105 | (BIH[20])); | |||
| 106 | printf("biXPels = %i \n", | |||
| 107 | (int)(BIH[27] << 24) + (BIH[26] << 16) + (BIH[25] << 8) + | |||
| 108 | (BIH[24])); | |||
| 109 | printf("biYPels = %i \n", | |||
| 110 | (int)(BIH[31] << 24) + (BIH[30] << 16) + (BIH[29] << 8) + | |||
| 111 | (BIH[28])); | |||
| 112 | printf("biClrUsed = %i \n", | |||
| 113 | (int)(BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) + | |||
| 114 | (BIH[32])); | |||
| 115 | printf("biClrImprtnt= %i \n", | |||
| 116 | (int)(BIH[39] << 24) + (BIH[38] << 16) + (BIH[37] << 8) + | |||
| 117 | (BIH[36])); | |||
| 118 | } | |||
| 119 | #endif | |||
| 120 | ||||
| 121 | /* Progressive loading */ | |||
| 122 | struct headerpair { | |||
| 123 | gint width; | |||
| 124 | gint height; | |||
| 125 | guint depth; | |||
| 126 | guint Negative; /* Negative = 1 -> top down BMP, | |||
| 127 | Negative = 0 -> bottom up BMP */ | |||
| 128 | }; | |||
| 129 | ||||
| 130 | /* Score the various parts of the icon */ | |||
| 131 | struct ico_direntry_data { | |||
| 132 | gint ImageScore; | |||
| 133 | gint width; | |||
| 134 | gint height; | |||
| 135 | guint DIBoffset; | |||
| 136 | gint x_hot; | |||
| 137 | gint y_hot; | |||
| 138 | }; | |||
| 139 | ||||
| 140 | struct ico_progressive_state { | |||
| 141 | CdkPixbufModuleSizeFunc size_func; | |||
| 142 | CdkPixbufModulePreparedFunc prepared_func; | |||
| 143 | CdkPixbufModuleUpdatedFunc updated_func; | |||
| 144 | gpointer user_data; | |||
| 145 | ||||
| 146 | gint HeaderSize; /* The size of the header-part (incl colormap) */ | |||
| 147 | guchar *HeaderBuf; /* The buffer for the header (incl colormap) */ | |||
| 148 | gint BytesInHeaderBuf; /* The size of the allocated HeaderBuf */ | |||
| 149 | gint HeaderDone; /* The nr of bytes actually in HeaderBuf */ | |||
| 150 | ||||
| 151 | gint LineWidth; /* The width of a line in bytes */ | |||
| 152 | guchar *LineBuf; /* Buffer for 1 line */ | |||
| 153 | gint LineDone; /* # of bytes in LineBuf */ | |||
| 154 | gint Lines; /* # of finished lines */ | |||
| 155 | ||||
| 156 | gint Type; /* | |||
| 157 | 32 = RGBA | |||
| 158 | 24 = RGB | |||
| 159 | 16 = 555 RGB | |||
| 160 | 8 = 8 bit colormapped | |||
| 161 | 4 = 4 bpp colormapped | |||
| 162 | 1 = 1 bit bitonal | |||
| 163 | */ | |||
| 164 | gboolean cursor; | |||
| 165 | gint x_hot; | |||
| 166 | gint y_hot; | |||
| 167 | ||||
| 168 | struct headerpair Header; /* Decoded (BE->CPU) header */ | |||
| 169 | GList *entries; | |||
| 170 | guint DIBoffset; | |||
| 171 | ||||
| 172 | CdkPixbuf *pixbuf; /* Our "target" */ | |||
| 173 | }; | |||
| 174 | ||||
| 175 | static gpointer | |||
| 176 | cdk_pixbuf__ico_image_begin_load(CdkPixbufModuleSizeFunc size_func, | |||
| 177 | CdkPixbufModulePreparedFunc prepared_func, | |||
| 178 | CdkPixbufModuleUpdatedFunc updated_func, | |||
| 179 | gpointer user_data, | |||
| 180 | GError **error); | |||
| 181 | static gboolean cdk_pixbuf__ico_image_stop_load(gpointer data, GError **error); | |||
| 182 | static gboolean cdk_pixbuf__ico_image_load_increment(gpointer data, | |||
| 183 | const guchar * buf, guint size, | |||
| 184 | GError **error); | |||
| 185 | ||||
| 186 | static void | |||
| 187 | context_free (struct ico_progressive_state *context) | |||
| 188 | { | |||
| 189 | g_free (context->LineBuf); | |||
| 190 | context->LineBuf = NULL((void*)0); | |||
| 191 | g_free (context->HeaderBuf); | |||
| 192 | g_list_free_full (context->entries, g_free); | |||
| 193 | if (context->pixbuf) | |||
| 194 | g_object_unref (context->pixbuf); | |||
| 195 | ||||
| 196 | g_free (context); | |||
| 197 | } | |||
| 198 | ||||
| 199 | static gint | |||
| 200 | compare_direntry_scores (gconstpointer a, | |||
| 201 | gconstpointer b) | |||
| 202 | { | |||
| 203 | const struct ico_direntry_data *ia = a; | |||
| 204 | const struct ico_direntry_data *ib = b; | |||
| 205 | ||||
| 206 | /* Backwards, so largest first */ | |||
| 207 | if (ib->ImageScore < ia->ImageScore) | |||
| 208 | return -1; | |||
| 209 | else if (ib->ImageScore > ia->ImageScore) | |||
| 210 | return 1; | |||
| 211 | return 0; | |||
| 212 | } | |||
| 213 | ||||
| 214 | static void DecodeHeader(guchar *Data, gint Bytes, | |||
| 215 | struct ico_progressive_state *State, | |||
| 216 | GError **error) | |||
| 217 | { | |||
| 218 | /* For ICO's we have to be very clever. There are multiple images possible | |||
| 219 | in an .ICO. As a simple heuristic, we select the image which is the largest | |||
| 220 | in pixels. | |||
| 221 | */ | |||
| 222 | struct ico_direntry_data *entry; | |||
| 223 | gint IconCount = 0; /* The number of icon-versions in the file */ | |||
| 224 | guchar *BIH; /* The DIB for the used icon */ | |||
| 225 | guchar *Ptr; | |||
| 226 | gint I; | |||
| 227 | guint16 imgtype; /* 1 = icon, 2 = cursor */ | |||
| 228 | GList *l; | |||
| 229 | gboolean got_broken_header = FALSE(0); | |||
| 230 | ||||
| 231 | /* Step 1: The ICO header */ | |||
| 232 | ||||
| 233 | /* First word should be 0 according to specs */ | |||
| 234 | if (((Data[1] << 8) + Data[0]) != 0) { | |||
| 235 | g_set_error (error, | |||
| 236 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 237 | CDK_PIXBUF_ERROR_CORRUPT_IMAGE, | |||
| 238 | _("Invalid header in icon (%s)")((char *) g_dgettext ("cdk-pixbuf", "Invalid header in icon (%s)" )), "first word"); | |||
| 239 | return; | |||
| 240 | ||||
| 241 | } | |||
| 242 | ||||
| 243 | imgtype = (Data[3] << 8) + Data[2]; | |||
| 244 | ||||
| 245 | State->cursor = (imgtype == 2) ? TRUE(!(0)) : FALSE(0); | |||
| 246 | ||||
| 247 | /* If it is not a cursor make sure it is actually an icon */ | |||
| 248 | if (!State->cursor && imgtype != 1) { | |||
| 249 | g_set_error (error, | |||
| 250 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 251 | CDK_PIXBUF_ERROR_CORRUPT_IMAGE, | |||
| 252 | _("Invalid header in icon (%s)")((char *) g_dgettext ("cdk-pixbuf", "Invalid header in icon (%s)" )), "image type"); | |||
| 253 | return; | |||
| 254 | } | |||
| 255 | ||||
| 256 | IconCount = (Data[5] << 8) + (Data[4]); | |||
| 257 | ||||
| 258 | State->HeaderSize = 6 + IconCount*16; | |||
| 259 | ||||
| 260 | DEBUG(g_print ("Image type: %d (%s)\nImage count: %d\n", imgtype, imgtype == 2 ? "cursor" : "icon", IconCount)); | |||
| 261 | ||||
| 262 | if (State->HeaderSize>State->BytesInHeaderBuf) { | |||
| 263 | guchar *tmp=g_try_realloc(State->HeaderBuf,State->HeaderSize); | |||
| 264 | if (!tmp) { | |||
| 265 | g_set_error_literal (error, | |||
| 266 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 267 | CDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, | |||
| 268 | _("Not enough memory to load icon")((char *) g_dgettext ("cdk-pixbuf", "Not enough memory to load icon" ))); | |||
| 269 | return; | |||
| 270 | } | |||
| 271 | State->HeaderBuf = tmp; | |||
| 272 | State->BytesInHeaderBuf = State->HeaderSize; | |||
| 273 | } | |||
| 274 | if (Bytes < State->HeaderSize) { | |||
| 275 | return; | |||
| 276 | } | |||
| 277 | ||||
| 278 | /* Now iterate through the ICONDIRENTRY structures, and sort them by | |||
| 279 | * which one we think is "best" (essentially the largest) */ | |||
| 280 | g_list_free_full (State->entries, g_free); | |||
| 281 | State->entries = 0; | |||
| 282 | Ptr = Data + 6; | |||
| 283 | for (I=0;I<IconCount;I++) { | |||
| 284 | int width; | |||
| 285 | int height; | |||
| 286 | int depth; | |||
| 287 | int x_hot; | |||
| 288 | int y_hot; | |||
| 289 | guint data_size G_GNUC_UNUSED__attribute__ ((__unused__)); | |||
| 290 | guint data_offset; | |||
| 291 | ||||
| 292 | width = Ptr[0]; | |||
| 293 | height = Ptr[1]; | |||
| 294 | depth = Ptr[2]; | |||
| 295 | x_hot = (Ptr[5] << 8) + Ptr[4]; | |||
| 296 | y_hot = (Ptr[7] << 8) + Ptr[6]; | |||
| 297 | data_size = ((guint) (Ptr[11]) << 24) + (Ptr[10] << 16) + (Ptr[9] << 8) + (Ptr[8]); | |||
| 298 | data_offset = ((guint) (Ptr[15]) << 24) + (Ptr[14] << 16) + (Ptr[13] << 8) + (Ptr[12]); | |||
| 299 | DEBUG(g_print ("Image %d: %d x %d\n\tDepth: %d\n", I, width, height, depth); | |||
| 300 | if (imgtype == 2) | |||
| 301 | g_print ("\tHotspot: %d x %d\n", x_hot, y_hot); | |||
| 302 | else | |||
| 303 | g_print ("\tColor planes: %d\n\tBits per pixel: %d\n", x_hot, y_hot); | |||
| 304 | g_print ("\tSize: %d\n\tOffset: %d\n", data_size, data_offset);) | |||
| 305 | ||||
| 306 | if (depth == 0) | |||
| 307 | depth = 32; | |||
| 308 | else if (depth <= 2) | |||
| 309 | depth = 1; | |||
| 310 | else if (depth <= 16) | |||
| 311 | depth = 4; | |||
| 312 | else if (depth <= 256) | |||
| 313 | depth = 8; | |||
| 314 | ||||
| 315 | /* We check whether the HeaderSize (int) would overflow */ | |||
| 316 | if (data_offset > INT_MAX2147483647 - INFOHEADER_SIZE40) { | |||
| 317 | got_broken_header = TRUE(!(0)); | |||
| 318 | continue; | |||
| 319 | } | |||
| 320 | ||||
| 321 | entry = g_new0 (struct ico_direntry_data, 1)(struct ico_direntry_data *) (__extension__ ({ gsize __n = (gsize ) (1); gsize __s = sizeof (struct ico_direntry_data); gpointer __p; if (__s == 1) __p = g_malloc0 (__n); else if (__builtin_constant_p (__n) && (__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s); __p; })); | |||
| 322 | entry->width = width ? width : 256; | |||
| 323 | entry->height = height ? height : 256; | |||
| 324 | entry->ImageScore = entry->width * entry->height * depth; | |||
| 325 | entry->x_hot = x_hot; | |||
| 326 | entry->y_hot = y_hot; | |||
| 327 | entry->DIBoffset = data_offset; | |||
| 328 | State->entries = g_list_insert_sorted (State->entries, entry, compare_direntry_scores); | |||
| 329 | Ptr += 16; | |||
| 330 | } | |||
| 331 | ||||
| 332 | /* Now go through and find one we can parse */ | |||
| 333 | entry = NULL((void*)0); | |||
| 334 | for (l = State->entries; l != NULL((void*)0); l = g_list_next (l)((l) ? (((GList *)(l))->next) : ((void*)0))) { | |||
| 335 | entry = l->data; | |||
| 336 | ||||
| 337 | /* Avoid invoking undefined behavior in the State->HeaderSize calculation below */ | |||
| 338 | if (entry->DIBoffset > G_MAXINT2147483647 - INFOHEADER_SIZE40) { | |||
| 339 | g_set_error (error, | |||
| 340 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 341 | CDK_PIXBUF_ERROR_CORRUPT_IMAGE, | |||
| 342 | _("Invalid header in icon (%s)")((char *) g_dgettext ("cdk-pixbuf", "Invalid header in icon (%s)" )), "header size"); | |||
| 343 | return; | |||
| 344 | } | |||
| 345 | ||||
| 346 | /* We know how many bytes are in the "header" part. */ | |||
| 347 | State->HeaderSize = entry->DIBoffset + INFOHEADER_SIZE40; | |||
| 348 | ||||
| 349 | if (State->HeaderSize>State->BytesInHeaderBuf) { | |||
| 350 | guchar *tmp=g_try_realloc(State->HeaderBuf,State->HeaderSize); | |||
| 351 | if (!tmp) { | |||
| 352 | g_set_error_literal (error, | |||
| 353 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 354 | CDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, | |||
| 355 | _("Not enough memory to load icon")((char *) g_dgettext ("cdk-pixbuf", "Not enough memory to load icon" ))); | |||
| 356 | return; | |||
| 357 | } | |||
| 358 | State->HeaderBuf = tmp; | |||
| 359 | State->BytesInHeaderBuf = State->HeaderSize; | |||
| 360 | } | |||
| 361 | if (Bytes<State->HeaderSize) | |||
| 362 | return; | |||
| 363 | ||||
| 364 | BIH = Data+entry->DIBoffset; | |||
| 365 | ||||
| 366 | /* A compressed icon, try the next one */ | |||
| 367 | if ((BIH[16] != 0) || (BIH[17] != 0) || (BIH[18] != 0) | |||
| 368 | || (BIH[19] != 0)) { | |||
| 369 | DEBUG(g_print("Skipping icon with score %d, as it is compressed\n", entry->ImageScore)); | |||
| 370 | continue; | |||
| 371 | } | |||
| 372 | ||||
| 373 | DEBUG(g_print("Selecting icon with score %d\n", entry->ImageScore)); | |||
| 374 | ||||
| 375 | /* If we made it to here then we have selected a BIH structure | |||
| 376 | * in a format that we can parse */ | |||
| 377 | break; | |||
| 378 | } | |||
| 379 | ||||
| 380 | /* No valid icon found, because all are compressed? */ | |||
| 381 | if (l == NULL((void*)0)) { | |||
| 382 | g_set_error_literal (error, | |||
| 383 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 384 | CDK_PIXBUF_ERROR_CORRUPT_IMAGE, | |||
| 385 | got_broken_header ? | |||
| 386 | _("Invalid header in icon")((char *) g_dgettext ("cdk-pixbuf", "Invalid header in icon") ) : | |||
| 387 | _("Compressed icons are not supported")((char *) g_dgettext ("cdk-pixbuf", "Compressed icons are not supported" ))); | |||
| 388 | return; | |||
| 389 | } | |||
| 390 | ||||
| 391 | /* This is the one we're going with */ | |||
| 392 | State->DIBoffset = entry->DIBoffset; | |||
| 393 | State->x_hot = entry->x_hot; | |||
| 394 | State->y_hot = entry->y_hot; | |||
| 395 | ||||
| 396 | #ifdef DUMPBIH | |||
| 397 | DumpBIH(BIH); | |||
| 398 | #endif | |||
| 399 | /* Add the palette to the headersize */ | |||
| 400 | ||||
| 401 | State->Header.width = | |||
| 402 | (int)(BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) + (BIH[4]); | |||
| 403 | if (State->Header.width == 0) | |||
| 404 | State->Header.width = 256; | |||
| 405 | ||||
| 406 | State->Header.height = | |||
| 407 | (int)((BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) + (BIH[8]))/2; | |||
| 408 | /* /2 because the BIH height includes the transparency mask */ | |||
| 409 | if (State->Header.height == 0) | |||
| 410 | State->Header.height = 256; | |||
| 411 | ||||
| 412 | /* Negative heights mean top-down pixel-order */ | |||
| 413 | if (State->Header.height < 0) { | |||
| 414 | State->Header.height = -State->Header.height; | |||
| 415 | State->Header.Negative = 1; | |||
| 416 | } | |||
| 417 | if (State->Header.width < 0) { | |||
| 418 | State->Header.width = -State->Header.width; | |||
| 419 | } | |||
| 420 | ||||
| 421 | if (State->Header.width != entry->width || | |||
| 422 | State->Header.height != entry->height) { | |||
| 423 | g_set_error (error, | |||
| 424 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 425 | CDK_PIXBUF_ERROR_CORRUPT_IMAGE, | |||
| 426 | _("Invalid header in icon (%s)")((char *) g_dgettext ("cdk-pixbuf", "Invalid header in icon (%s)" )), "image size"); | |||
| 427 | return; | |||
| 428 | } | |||
| 429 | ||||
| 430 | State->Header.depth = (BIH[15] << 8) + (BIH[14]); | |||
| 431 | State->Type = State->Header.depth; | |||
| 432 | ||||
| 433 | /* Determine the palette size. If the header indicates 0, it | |||
| 434 | is actually the maximum for the bpp. You have to love the | |||
| 435 | guys who made the spec. */ | |||
| 436 | I = (int)(BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) + (BIH[32]); | |||
| 437 | I = I*4; | |||
| 438 | if ((I==0)&&(State->Type==1)) | |||
| 439 | I = 2*4; | |||
| 440 | if ((I==0)&&(State->Type==4)) | |||
| 441 | I = 16*4; | |||
| 442 | if ((I==0)&&(State->Type==8)) | |||
| 443 | I = 256*4; | |||
| 444 | ||||
| 445 | State->HeaderSize+=I; | |||
| 446 | ||||
| 447 | if (State->HeaderSize < 0) { | |||
| 448 | g_set_error (error, | |||
| 449 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 450 | CDK_PIXBUF_ERROR_CORRUPT_IMAGE, | |||
| 451 | _("Invalid header in icon (%s)")((char *) g_dgettext ("cdk-pixbuf", "Invalid header in icon (%s)" )), "palette size"); | |||
| 452 | return; | |||
| 453 | } | |||
| 454 | ||||
| 455 | if (State->HeaderSize>State->BytesInHeaderBuf) { | |||
| 456 | guchar *tmp=g_try_realloc(State->HeaderBuf,State->HeaderSize); | |||
| 457 | if (!tmp) { | |||
| 458 | g_set_error_literal (error, | |||
| 459 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 460 | CDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, | |||
| 461 | _("Not enough memory to load icon")((char *) g_dgettext ("cdk-pixbuf", "Not enough memory to load icon" ))); | |||
| 462 | return; | |||
| 463 | } | |||
| 464 | State->HeaderBuf = tmp; | |||
| 465 | State->BytesInHeaderBuf = State->HeaderSize; | |||
| 466 | } | |||
| 467 | if (Bytes < State->HeaderSize) { | |||
| 468 | return; | |||
| 469 | } | |||
| 470 | ||||
| 471 | if (State->Type == 32) | |||
| 472 | State->LineWidth = State->Header.width * 4; | |||
| 473 | else if (State->Type == 24) | |||
| 474 | State->LineWidth = State->Header.width * 3; | |||
| 475 | else if (State->Type == 16) | |||
| 476 | State->LineWidth = State->Header.width * 2; | |||
| 477 | else if (State->Type == 8) | |||
| 478 | State->LineWidth = State->Header.width * 1; | |||
| 479 | else if (State->Type == 4) | |||
| 480 | State->LineWidth = (State->Header.width+1)/2; | |||
| 481 | else if (State->Type == 1) { | |||
| 482 | State->LineWidth = State->Header.width / 8; | |||
| 483 | if ((State->Header.width & 7) != 0) | |||
| 484 | State->LineWidth++; | |||
| 485 | } else { | |||
| 486 | g_set_error_literal (error, | |||
| 487 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 488 | CDK_PIXBUF_ERROR_CORRUPT_IMAGE, | |||
| 489 | _("Unsupported icon type")((char *) g_dgettext ("cdk-pixbuf", "Unsupported icon type"))); | |||
| 490 | return; | |||
| 491 | } | |||
| 492 | ||||
| 493 | /* Pad to a 32 bit boundary */ | |||
| 494 | if (((State->LineWidth % 4) > 0)) | |||
| 495 | State->LineWidth = (State->LineWidth / 4) * 4 + 4; | |||
| 496 | ||||
| 497 | ||||
| 498 | if (State->LineBuf == NULL((void*)0)) { | |||
| 499 | State->LineBuf = g_try_malloc(State->LineWidth); | |||
| 500 | if (!State->LineBuf) { | |||
| 501 | g_set_error_literal (error, | |||
| 502 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 503 | CDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, | |||
| 504 | _("Not enough memory to load icon")((char *) g_dgettext ("cdk-pixbuf", "Not enough memory to load icon" ))); | |||
| 505 | return; | |||
| 506 | } | |||
| 507 | } | |||
| 508 | ||||
| 509 | g_assert(State->LineBuf != NULL)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_19 = 0; if (State->LineBuf != ((void*)0)) _g_boolean_var_19 = 1; _g_boolean_var_19; }), 1)) ; else g_assertion_message_expr ("CdkPixbuf", "../cdk-pixbuf/io-ico.c", 509, ((const char*) ( __func__)), "State->LineBuf != NULL"); } while (0); | |||
| 510 | ||||
| 511 | ||||
| 512 | if (State->pixbuf == NULL((void*)0)) { | |||
| 513 | { | |||
| 514 | gint width = State->Header.width; | |||
| 515 | gint height = State->Header.height; | |||
| 516 | ||||
| 517 | (*State->size_func) (&width, &height, State->user_data); | |||
| 518 | if (width == 0 || height == 0) { | |||
| 519 | State->LineWidth = 0; | |||
| 520 | return; | |||
| 521 | } | |||
| 522 | } | |||
| 523 | ||||
| 524 | State->pixbuf = | |||
| 525 | cdk_pixbuf_new(CDK_COLORSPACE_RGB, TRUE(!(0)), 8, | |||
| 526 | State->Header.width, | |||
| 527 | State->Header.height); | |||
| 528 | if (!State->pixbuf) { | |||
| 529 | g_set_error_literal (error, | |||
| 530 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 531 | CDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, | |||
| 532 | _("Not enough memory to load icon")((char *) g_dgettext ("cdk-pixbuf", "Not enough memory to load icon" ))); | |||
| 533 | return; | |||
| 534 | } | |||
| 535 | if (State->cursor) { | |||
| 536 | gchar hot[10]; | |||
| 537 | g_snprintf (hot, 10, "%d", State->x_hot); | |||
| 538 | cdk_pixbuf_set_option (State->pixbuf, "x_hot", hot); | |||
| 539 | g_snprintf (hot, 10, "%d", State->y_hot); | |||
| 540 | cdk_pixbuf_set_option (State->pixbuf, "y_hot", hot); | |||
| 541 | } | |||
| 542 | ||||
| 543 | /* Notify the client that we are ready to go */ | |||
| 544 | (*State->prepared_func) (State->pixbuf, | |||
| 545 | NULL((void*)0), | |||
| 546 | State->user_data); | |||
| 547 | } | |||
| 548 | ||||
| 549 | } | |||
| 550 | ||||
| 551 | /* | |||
| 552 | * func - called when we have pixmap created (but no image data) | |||
| 553 | * user_data - passed as arg 1 to func | |||
| 554 | * return context (opaque to user) | |||
| 555 | */ | |||
| 556 | ||||
| 557 | static gpointer | |||
| 558 | cdk_pixbuf__ico_image_begin_load(CdkPixbufModuleSizeFunc size_func, | |||
| 559 | CdkPixbufModulePreparedFunc prepared_func, | |||
| 560 | CdkPixbufModuleUpdatedFunc updated_func, | |||
| 561 | gpointer user_data, | |||
| 562 | GError **error) | |||
| 563 | { | |||
| 564 | struct ico_progressive_state *context; | |||
| 565 | ||||
| 566 | g_assert (size_func != NULL)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_20 = 0; if (size_func != ((void*)0)) _g_boolean_var_20 = 1; _g_boolean_var_20 ; }), 1)) ; else g_assertion_message_expr ("CdkPixbuf", "../cdk-pixbuf/io-ico.c" , 566, ((const char*) (__func__)), "size_func != NULL"); } while (0); | |||
| 567 | g_assert (prepared_func != NULL)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_21 = 0; if (prepared_func != ((void*)0)) _g_boolean_var_21 = 1; _g_boolean_var_21; }), 1)) ; else g_assertion_message_expr ( "CdkPixbuf", "../cdk-pixbuf/io-ico.c", 567, ((const char*) (__func__ )), "prepared_func != NULL"); } while (0); | |||
| 568 | g_assert (updated_func != NULL)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_22 = 0; if (updated_func != ((void*)0)) _g_boolean_var_22 = 1; _g_boolean_var_22 ; }), 1)) ; else g_assertion_message_expr ("CdkPixbuf", "../cdk-pixbuf/io-ico.c" , 568, ((const char*) (__func__)), "updated_func != NULL"); } while (0); | |||
| 569 | ||||
| 570 | context = g_new0(struct ico_progressive_state, 1)(struct ico_progressive_state *) (__extension__ ({ gsize __n = (gsize) (1); gsize __s = sizeof (struct ico_progressive_state ); gpointer __p; if (__s == 1) __p = g_malloc0 (__n); else if (__builtin_constant_p (__n) && (__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s); __p; })); | |||
| 571 | context->size_func = size_func; | |||
| 572 | context->prepared_func = prepared_func; | |||
| 573 | context->updated_func = updated_func; | |||
| 574 | context->user_data = user_data; | |||
| 575 | ||||
| 576 | context->HeaderSize = 54; | |||
| 577 | context->HeaderBuf = g_try_malloc(14 + INFOHEADER_SIZE40 + 4*256 + 512); | |||
| 578 | if (!context->HeaderBuf) { | |||
| 579 | g_free (context); | |||
| 580 | g_set_error_literal (error, | |||
| 581 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 582 | CDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, | |||
| 583 | _("Not enough memory to load ICO file")((char *) g_dgettext ("cdk-pixbuf", "Not enough memory to load ICO file" ))); | |||
| 584 | return NULL((void*)0); | |||
| 585 | } | |||
| 586 | /* 4*256 for the colormap */ | |||
| 587 | context->BytesInHeaderBuf = 14 + INFOHEADER_SIZE40 + 4*256 + 512 ; | |||
| 588 | context->HeaderDone = 0; | |||
| 589 | ||||
| 590 | context->LineWidth = 0; | |||
| 591 | context->LineBuf = NULL((void*)0); | |||
| 592 | context->LineDone = 0; | |||
| 593 | context->Lines = 0; | |||
| 594 | ||||
| 595 | context->Type = 0; | |||
| 596 | ||||
| 597 | memset(&context->Header, 0, sizeof(struct headerpair)); | |||
| 598 | ||||
| 599 | ||||
| 600 | context->pixbuf = NULL((void*)0); | |||
| 601 | ||||
| 602 | ||||
| 603 | return (gpointer) context; | |||
| 604 | } | |||
| 605 | ||||
| 606 | /* | |||
| 607 | * context - returned from image_begin_load | |||
| 608 | * | |||
| 609 | * free context, unref cdk_pixbuf | |||
| 610 | */ | |||
| 611 | static gboolean | |||
| 612 | cdk_pixbuf__ico_image_stop_load(gpointer data, | |||
| 613 | GError **error) | |||
| 614 | { | |||
| 615 | struct ico_progressive_state *context = | |||
| 616 | (struct ico_progressive_state *) data; | |||
| 617 | gboolean ret = TRUE(!(0)); | |||
| 618 | ||||
| 619 | /* FIXME this thing needs to report errors if | |||
| 620 | * we have unused image data | |||
| 621 | */ | |||
| 622 | ||||
| 623 | g_return_val_if_fail(context != NULL, TRUE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_23 = 0; if (context != ((void*)0)) _g_boolean_var_23 = 1; _g_boolean_var_23 ; }), 1))) { } else { g_return_if_fail_warning ("CdkPixbuf", ( (const char*) (__func__)), "context != NULL"); return ((!(0)) ); } } while (0); | |||
| 624 | ||||
| 625 | if (context->HeaderDone < context->HeaderSize) { | |||
| 626 | g_set_error_literal (error, | |||
| 627 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 628 | CDK_PIXBUF_ERROR_CORRUPT_IMAGE, | |||
| 629 | _("ICO image was truncated or incomplete.")((char *) g_dgettext ("cdk-pixbuf", "ICO image was truncated or incomplete." ))); | |||
| 630 | ret = FALSE(0); | |||
| 631 | } | |||
| 632 | ||||
| 633 | context_free (context); | |||
| 634 | return ret; | |||
| 635 | } | |||
| 636 | ||||
| 637 | static void | |||
| 638 | OneLine32 (struct ico_progressive_state *context) | |||
| 639 | { | |||
| 640 | gint X; | |||
| 641 | guchar *Pixels; | |||
| 642 | gsize rowstride = cdk_pixbuf_get_rowstride (context->pixbuf); | |||
| 643 | ||||
| 644 | X = 0; | |||
| 645 | if (context->Header.Negative == 0) | |||
| 646 | Pixels = (cdk_pixbuf_get_pixels (context->pixbuf) + | |||
| 647 | rowstride * (context->Header.height - context->Lines - 1)); | |||
| 648 | else | |||
| 649 | Pixels = (cdk_pixbuf_get_pixels (context->pixbuf) + | |||
| 650 | rowstride * context->Lines); | |||
| 651 | while (X < context->Header.width) { | |||
| 652 | /* BGRA */ | |||
| 653 | Pixels[X * 4 + 0] = context->LineBuf[X * 4 + 2]; | |||
| 654 | Pixels[X * 4 + 1] = context->LineBuf[X * 4 + 1]; | |||
| 655 | Pixels[X * 4 + 2] = context->LineBuf[X * 4 + 0]; | |||
| 656 | Pixels[X * 4 + 3] = context->LineBuf[X * 4 + 3]; | |||
| 657 | X++; | |||
| 658 | } | |||
| 659 | } | |||
| 660 | ||||
| 661 | static void OneLine24(struct ico_progressive_state *context) | |||
| 662 | { | |||
| 663 | gint X; | |||
| 664 | guchar *Pixels; | |||
| 665 | gsize rowstride = cdk_pixbuf_get_rowstride (context->pixbuf); | |||
| 666 | ||||
| 667 | X = 0; | |||
| 668 | if (context->Header.Negative == 0) | |||
| 669 | Pixels = (cdk_pixbuf_get_pixels (context->pixbuf) + | |||
| 670 | rowstride * (context->Header.height - context->Lines - 1)); | |||
| 671 | else | |||
| 672 | Pixels = (cdk_pixbuf_get_pixels (context->pixbuf) + | |||
| 673 | rowstride * context->Lines); | |||
| 674 | while (X < context->Header.width) { | |||
| 675 | Pixels[X * 4 + 0] = context->LineBuf[X * 3 + 2]; | |||
| 676 | Pixels[X * 4 + 1] = context->LineBuf[X * 3 + 1]; | |||
| 677 | Pixels[X * 4 + 2] = context->LineBuf[X * 3 + 0]; | |||
| 678 | Pixels[X * 4 + 3] = 0xff; | |||
| 679 | X++; | |||
| 680 | } | |||
| 681 | ||||
| 682 | } | |||
| 683 | ||||
| 684 | static void | |||
| 685 | OneLine16 (struct ico_progressive_state *context) | |||
| 686 | { | |||
| 687 | int i; | |||
| 688 | guchar *pixels; | |||
| 689 | guchar *src; | |||
| 690 | gsize rowstride = cdk_pixbuf_get_rowstride (context->pixbuf); | |||
| 691 | ||||
| 692 | if (context->Header.Negative == 0) | |||
| 693 | pixels = (cdk_pixbuf_get_pixels (context->pixbuf) + | |||
| 694 | rowstride * (context->Header.height - context->Lines - 1)); | |||
| 695 | else | |||
| 696 | pixels = (cdk_pixbuf_get_pixels (context->pixbuf) + | |||
| 697 | rowstride * context->Lines); | |||
| 698 | ||||
| 699 | src = context->LineBuf; | |||
| 700 | ||||
| 701 | for (i = 0; i < context->Header.width; i++) { | |||
| 702 | int v, r, g, b; | |||
| 703 | ||||
| 704 | v = (int) src[0] | ((int) src[1] << 8); | |||
| 705 | src += 2; | |||
| 706 | ||||
| 707 | /* Extract 5-bit RGB values */ | |||
| 708 | ||||
| 709 | r = (v >> 10) & 0x1f; | |||
| 710 | g = (v >> 5) & 0x1f; | |||
| 711 | b = v & 0x1f; | |||
| 712 | ||||
| 713 | /* Fill the rightmost bits to form 8-bit values */ | |||
| 714 | ||||
| 715 | *pixels++ = (r << 3) | (r >> 2); | |||
| 716 | *pixels++ = (g << 3) | (g >> 2); | |||
| 717 | *pixels++ = (b << 3) | (b >> 2); | |||
| 718 | *pixels++ = 0xff; | |||
| 719 | } | |||
| 720 | } | |||
| 721 | ||||
| 722 | ||||
| 723 | static void OneLine8(struct ico_progressive_state *context) | |||
| 724 | { | |||
| 725 | gint X; | |||
| 726 | guchar *Pixels; | |||
| 727 | gsize rowstride = cdk_pixbuf_get_rowstride (context->pixbuf); | |||
| 728 | ||||
| 729 | X = 0; | |||
| 730 | if (context->Header.Negative == 0) | |||
| 731 | Pixels = (cdk_pixbuf_get_pixels (context->pixbuf) + | |||
| 732 | rowstride * (context->Header.height - context->Lines - 1)); | |||
| 733 | else | |||
| 734 | Pixels = (cdk_pixbuf_get_pixels (context->pixbuf) + | |||
| 735 | rowstride * context->Lines); | |||
| 736 | while (X < context->Header.width) { | |||
| 737 | /* The joys of having a BGR byteorder */ | |||
| 738 | Pixels[X * 4 + 0] = | |||
| 739 | context->HeaderBuf[4 * context->LineBuf[X] + INFOHEADER_SIZE40 + 2 + context->DIBoffset]; | |||
| 740 | Pixels[X * 4 + 1] = | |||
| 741 | context->HeaderBuf[4 * context->LineBuf[X] + INFOHEADER_SIZE40 + 1 +context->DIBoffset]; | |||
| 742 | Pixels[X * 4 + 2] = | |||
| 743 | context->HeaderBuf[4 * context->LineBuf[X] + INFOHEADER_SIZE40 +context->DIBoffset]; | |||
| 744 | Pixels[X * 4 + 3] = 0xff; | |||
| 745 | X++; | |||
| 746 | } | |||
| 747 | } | |||
| 748 | static void OneLine4(struct ico_progressive_state *context) | |||
| 749 | { | |||
| 750 | gint X; | |||
| 751 | guchar *Pixels; | |||
| 752 | gsize rowstride = cdk_pixbuf_get_rowstride (context->pixbuf); | |||
| 753 | ||||
| 754 | X = 0; | |||
| 755 | if (context->Header.Negative == 0) | |||
| 756 | Pixels = (cdk_pixbuf_get_pixels (context->pixbuf) + | |||
| 757 | rowstride * (context->Header.height - context->Lines - 1)); | |||
| 758 | else | |||
| 759 | Pixels = (cdk_pixbuf_get_pixels (context->pixbuf) + | |||
| 760 | rowstride * context->Lines); | |||
| 761 | ||||
| 762 | while (X < context->Header.width) { | |||
| 763 | guchar Pix; | |||
| 764 | ||||
| 765 | Pix = context->LineBuf[X/2]; | |||
| ||||
| 766 | ||||
| 767 | Pixels[X * 4 + 0] = | |||
| 768 | context->HeaderBuf[4 * (Pix>>4) + INFOHEADER_SIZE40 + 2 + context->DIBoffset]; | |||
| 769 | Pixels[X * 4 + 1] = | |||
| 770 | context->HeaderBuf[4 * (Pix>>4) + INFOHEADER_SIZE40 + 1 +context->DIBoffset]; | |||
| 771 | Pixels[X * 4 + 2] = | |||
| 772 | context->HeaderBuf[4 * (Pix>>4) + INFOHEADER_SIZE40 + context->DIBoffset]; | |||
| 773 | Pixels[X * 4 + 3] = 0xff; | |||
| 774 | X++; | |||
| 775 | if (X<context->Header.width) { | |||
| 776 | /* Handle the other 4 bit pixel only when there is one */ | |||
| 777 | Pixels[X * 4 + 0] = | |||
| 778 | context->HeaderBuf[4 * (Pix&15) + INFOHEADER_SIZE40 + 2 + context->DIBoffset]; | |||
| 779 | Pixels[X * 4 + 1] = | |||
| 780 | context->HeaderBuf[4 * (Pix&15) + INFOHEADER_SIZE40 + 1 + context->DIBoffset]; | |||
| 781 | Pixels[X * 4 + 2] = | |||
| 782 | context->HeaderBuf[4 * (Pix&15) + INFOHEADER_SIZE40 + context->DIBoffset]; | |||
| 783 | Pixels[X * 4 + 3] = 0xff; | |||
| 784 | X++; | |||
| 785 | } | |||
| 786 | } | |||
| 787 | ||||
| 788 | } | |||
| 789 | ||||
| 790 | static void OneLine1(struct ico_progressive_state *context) | |||
| 791 | { | |||
| 792 | gint X; | |||
| 793 | guchar *Pixels; | |||
| 794 | gsize rowstride = cdk_pixbuf_get_rowstride (context->pixbuf); | |||
| 795 | ||||
| 796 | X = 0; | |||
| 797 | if (context->Header.Negative == 0) | |||
| 798 | Pixels = (cdk_pixbuf_get_pixels (context->pixbuf) + | |||
| 799 | rowstride * (context->Header.height - context->Lines - 1)); | |||
| 800 | else | |||
| 801 | Pixels = (cdk_pixbuf_get_pixels (context->pixbuf) + | |||
| 802 | rowstride * context->Lines); | |||
| 803 | while (X < context->Header.width) { | |||
| 804 | int Bit; | |||
| 805 | ||||
| 806 | Bit = (context->LineBuf[X / 8]) >> (7 - (X & 7)); | |||
| 807 | Bit = Bit & 1; | |||
| 808 | /* The joys of having a BGR byteorder */ | |||
| 809 | Pixels[X * 4 + 0] = Bit*255; | |||
| 810 | Pixels[X * 4 + 1] = Bit*255; | |||
| 811 | Pixels[X * 4 + 2] = Bit*255; | |||
| 812 | Pixels[X * 4 + 3] = 0xff; | |||
| 813 | X++; | |||
| 814 | } | |||
| 815 | } | |||
| 816 | ||||
| 817 | static void OneLineTransp(struct ico_progressive_state *context) | |||
| 818 | { | |||
| 819 | gint X; | |||
| 820 | guchar *Pixels; | |||
| 821 | gsize rowstride = cdk_pixbuf_get_rowstride (context->pixbuf); | |||
| 822 | ||||
| 823 | /* Ignore the XOR mask for XP style 32-bpp icons with alpha */ | |||
| 824 | if (context->Header.depth == 32) | |||
| 825 | return; | |||
| 826 | ||||
| 827 | X = 0; | |||
| 828 | if (context->Header.Negative == 0) | |||
| 829 | Pixels = (cdk_pixbuf_get_pixels (context->pixbuf) + | |||
| 830 | rowstride * (2*context->Header.height - context->Lines - 1)); | |||
| 831 | else | |||
| 832 | Pixels = (cdk_pixbuf_get_pixels (context->pixbuf) + | |||
| 833 | rowstride * (context->Lines-context->Header.height)); | |||
| 834 | while (X < context->Header.width) { | |||
| 835 | int Bit; | |||
| 836 | ||||
| 837 | Bit = (context->LineBuf[X / 8]) >> (7 - (X & 7)); | |||
| 838 | Bit = Bit & 1; | |||
| 839 | /* The joys of having a BGR byteorder */ | |||
| 840 | Pixels[X * 4 + 3] = 255-Bit*255; | |||
| 841 | #if 0 | |||
| 842 | if (Bit){ | |||
| 843 | Pixels[X*4+0] = 255; | |||
| 844 | Pixels[X*4+1] = 255; | |||
| 845 | } else { | |||
| 846 | Pixels[X*4+0] = 0; | |||
| 847 | Pixels[X*4+1] = 0; | |||
| 848 | } | |||
| 849 | #endif | |||
| 850 | X++; | |||
| 851 | } | |||
| 852 | } | |||
| 853 | ||||
| 854 | ||||
| 855 | static void OneLine(struct ico_progressive_state *context) | |||
| 856 | { | |||
| 857 | context->LineDone = 0; | |||
| 858 | ||||
| 859 | if (context->Lines >= context->Header.height*2) { | |||
| 860 | return; | |||
| 861 | } | |||
| 862 | ||||
| 863 | if (context->Lines <context->Header.height) { | |||
| 864 | if (context->Type == 32) | |||
| 865 | OneLine32 (context); | |||
| 866 | else if (context->Type == 24) | |||
| 867 | OneLine24(context); | |||
| 868 | else if (context->Type == 16) | |||
| 869 | OneLine16 (context); | |||
| 870 | else if (context->Type == 8) | |||
| 871 | OneLine8(context); | |||
| 872 | else if (context->Type == 4) | |||
| 873 | OneLine4(context); | |||
| 874 | else if (context->Type == 1) | |||
| 875 | OneLine1(context); | |||
| 876 | else | |||
| 877 | g_assert_not_reached ()do { g_assertion_message_expr ("CdkPixbuf", "../cdk-pixbuf/io-ico.c" , 877, ((const char*) (__func__)), ((void*)0)); } while (0); | |||
| 878 | } else | |||
| 879 | OneLineTransp(context); | |||
| 880 | ||||
| 881 | context->Lines++; | |||
| 882 | if (context->Lines>=context->Header.height) { | |||
| 883 | context->Type = 1; | |||
| 884 | context->LineWidth = context->Header.width / 8; | |||
| 885 | if ((context->Header.width & 7) != 0) | |||
| 886 | context->LineWidth++; | |||
| 887 | /* Pad to a 32 bit boundary */ | |||
| 888 | if (((context->LineWidth % 4) > 0)) | |||
| 889 | context->LineWidth = (context->LineWidth / 4) * 4 + 4; | |||
| 890 | } | |||
| 891 | ||||
| 892 | { | |||
| 893 | int y; | |||
| 894 | ||||
| 895 | y = context->Lines % context->Header.height; | |||
| 896 | if (context->Header.Negative == 0 && | |||
| 897 | context->Lines < context->Header.height) | |||
| 898 | y = context->Header.height - y; | |||
| 899 | (*context->updated_func) (context->pixbuf, | |||
| 900 | 0, | |||
| 901 | y, | |||
| 902 | context->Header.width, | |||
| 903 | 1, | |||
| 904 | context->user_data); | |||
| 905 | ||||
| 906 | } | |||
| 907 | } | |||
| 908 | ||||
| 909 | /* | |||
| 910 | * context - from image_begin_load | |||
| 911 | * buf - new image data | |||
| 912 | * size - length of new image data | |||
| 913 | * | |||
| 914 | * append image data onto inrecrementally built output image | |||
| 915 | */ | |||
| 916 | static gboolean | |||
| 917 | cdk_pixbuf__ico_image_load_increment(gpointer data, | |||
| 918 | const guchar * buf, | |||
| 919 | guint size, | |||
| 920 | GError **error) | |||
| 921 | { | |||
| 922 | struct ico_progressive_state *context = | |||
| 923 | (struct ico_progressive_state *) data; | |||
| 924 | ||||
| 925 | gint BytesToCopy; | |||
| 926 | ||||
| 927 | while (size
| |||
| ||||
| 928 | g_assert(context->LineDone >= 0)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_24 = 0; if (context->LineDone >= 0) _g_boolean_var_24 = 1 ; _g_boolean_var_24; }), 1)) ; else g_assertion_message_expr ( "CdkPixbuf", "../cdk-pixbuf/io-ico.c", 928, ((const char*) (__func__ )), "context->LineDone >= 0"); } while (0); | |||
| 929 | if (context->HeaderDone < context->HeaderSize) { /* We still | |||
| 930 | have headerbytes to do */ | |||
| 931 | BytesToCopy = | |||
| 932 | context->HeaderSize - context->HeaderDone; | |||
| 933 | if (BytesToCopy > size) | |||
| 934 | BytesToCopy = size; | |||
| 935 | ||||
| 936 | memmove(context->HeaderBuf + context->HeaderDone, | |||
| 937 | buf, BytesToCopy); | |||
| 938 | ||||
| 939 | size -= BytesToCopy; | |||
| 940 | buf += BytesToCopy; | |||
| 941 | context->HeaderDone += BytesToCopy; | |||
| 942 | } | |||
| 943 | else { | |||
| 944 | BytesToCopy = | |||
| 945 | context->LineWidth - context->LineDone; | |||
| 946 | if (BytesToCopy > size) | |||
| 947 | BytesToCopy = size; | |||
| 948 | ||||
| 949 | if (BytesToCopy > 0) { | |||
| 950 | /* Should be non-NULL once the header is decoded, as below. */ | |||
| 951 | g_assert (context->LineBuf != NULL)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_25 = 0; if (context->LineBuf != ((void*)0)) _g_boolean_var_25 = 1; _g_boolean_var_25; }), 1)) ; else g_assertion_message_expr ("CdkPixbuf", "../cdk-pixbuf/io-ico.c", 951, ((const char*) ( __func__)), "context->LineBuf != NULL"); } while (0); | |||
| 952 | ||||
| 953 | memmove(context->LineBuf + | |||
| 954 | context->LineDone, buf, | |||
| 955 | BytesToCopy); | |||
| 956 | ||||
| 957 | size -= BytesToCopy; | |||
| 958 | buf += BytesToCopy; | |||
| 959 | context->LineDone += BytesToCopy; | |||
| 960 | } | |||
| 961 | if ((context->LineDone >= context->LineWidth) && (context->LineWidth > 0)) { | |||
| 962 | /* By this point, DecodeHeader() will have been called, and should have returned successfully | |||
| 963 | * or set a #GError, as its only return-FALSE-without-setting-a-GError paths are when | |||
| 964 | * (context->HeaderDone < context->HeaderSize) or (context->LineWidth == 0). | |||
| 965 | * If it’s returned a #GError, we will have bailed already; otherwise, pixbuf will be set. */ | |||
| 966 | g_assert (context->pixbuf != NULL)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_26 = 0; if (context->pixbuf != ((void*)0)) _g_boolean_var_26 = 1; _g_boolean_var_26; }), 1)) ; else g_assertion_message_expr ("CdkPixbuf", "../cdk-pixbuf/io-ico.c", 966, ((const char*) ( __func__)), "context->pixbuf != NULL"); } while (0); | |||
| 967 | OneLine(context); | |||
| 968 | } | |||
| 969 | ||||
| 970 | ||||
| 971 | } | |||
| 972 | ||||
| 973 | if (context->HeaderDone >= 6 && context->pixbuf == NULL((void*)0)) { | |||
| 974 | GError *decode_err = NULL((void*)0); | |||
| 975 | DecodeHeader(context->HeaderBuf, | |||
| 976 | context->HeaderDone, context, &decode_err); | |||
| 977 | if (context->LineBuf != NULL((void*)0) && context->LineWidth == 0) | |||
| 978 | return TRUE(!(0)); | |||
| 979 | ||||
| 980 | if (decode_err) { | |||
| 981 | g_propagate_error (error, decode_err); | |||
| 982 | return FALSE(0); | |||
| 983 | } | |||
| 984 | } | |||
| 985 | } | |||
| 986 | ||||
| 987 | return TRUE(!(0)); | |||
| 988 | } | |||
| 989 | ||||
| 990 | /* saving ICOs */ | |||
| 991 | ||||
| 992 | static gint | |||
| 993 | write8 (FILE *f, | |||
| 994 | guint8 *data, | |||
| 995 | gint count) | |||
| 996 | { | |||
| 997 | gint bytes; | |||
| 998 | gint written; | |||
| 999 | ||||
| 1000 | written = 0; | |||
| 1001 | while (count > 0) | |||
| 1002 | { | |||
| 1003 | bytes = fwrite ((char*) data, sizeof (char), count, f); | |||
| 1004 | if (bytes <= 0) | |||
| 1005 | break; | |||
| 1006 | count -= bytes; | |||
| 1007 | data += bytes; | |||
| 1008 | written += bytes; | |||
| 1009 | } | |||
| 1010 | ||||
| 1011 | return written; | |||
| 1012 | } | |||
| 1013 | ||||
| 1014 | static gint | |||
| 1015 | write16 (FILE *f, | |||
| 1016 | guint16 *data, | |||
| 1017 | gint count) | |||
| 1018 | { | |||
| 1019 | gint i; | |||
| 1020 | ||||
| 1021 | for (i = 0; i < count; i++) | |||
| 1022 | data[i] = GUINT16_TO_LE (data[i])((guint16) (data[i])); | |||
| 1023 | ||||
| 1024 | return write8 (f, (guint8*) data, count * 2); | |||
| 1025 | } | |||
| 1026 | ||||
| 1027 | static gint | |||
| 1028 | write32 (FILE *f, | |||
| 1029 | guint32 *data, | |||
| 1030 | gint count) | |||
| 1031 | { | |||
| 1032 | gint i; | |||
| 1033 | ||||
| 1034 | for (i = 0; i < count; i++) | |||
| 1035 | data[i] = GUINT32_TO_LE (data[i])((guint32) (data[i])); | |||
| 1036 | ||||
| 1037 | return write8 (f, (guint8*) data, count * 4); | |||
| 1038 | } | |||
| 1039 | ||||
| 1040 | typedef struct _IconEntry IconEntry; | |||
| 1041 | struct _IconEntry { | |||
| 1042 | gint width; | |||
| 1043 | gint height; | |||
| 1044 | gint depth; | |||
| 1045 | gint hot_x; | |||
| 1046 | gint hot_y; | |||
| 1047 | ||||
| 1048 | guint8 n_colors; | |||
| 1049 | guint32 *colors; | |||
| 1050 | guint xor_rowstride; | |||
| 1051 | guint8 *xor; | |||
| 1052 | guint and_rowstride; | |||
| 1053 | guint8 *and; | |||
| 1054 | }; | |||
| 1055 | ||||
| 1056 | static gboolean | |||
| 1057 | fill_entry (IconEntry *icon, | |||
| 1058 | CdkPixbuf *pixbuf, | |||
| 1059 | gint hot_x, | |||
| 1060 | gint hot_y, | |||
| 1061 | GError **error) | |||
| 1062 | { | |||
| 1063 | guchar *p, *pixels, *and, *xor; | |||
| 1064 | gint n_channels, v, x, y; | |||
| 1065 | ||||
| 1066 | if (icon->width > 256 || icon->height > 256) { | |||
| 1067 | g_set_error_literal (error, | |||
| 1068 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 1069 | CDK_PIXBUF_ERROR_BAD_OPTION, | |||
| 1070 | _("Image too large to be saved as ICO")((char *) g_dgettext ("cdk-pixbuf", "Image too large to be saved as ICO" ))); | |||
| 1071 | return FALSE(0); | |||
| 1072 | } | |||
| 1073 | ||||
| 1074 | if (hot_x > -1 && hot_y > -1) { | |||
| 1075 | icon->hot_x = hot_x; | |||
| 1076 | icon->hot_y = hot_y; | |||
| 1077 | if (icon->hot_x >= icon->width || icon->hot_y >= icon->height) { | |||
| 1078 | g_set_error_literal (error, | |||
| 1079 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 1080 | CDK_PIXBUF_ERROR_BAD_OPTION, | |||
| 1081 | _("Cursor hotspot outside image")((char *) g_dgettext ("cdk-pixbuf", "Cursor hotspot outside image" ))); | |||
| 1082 | return FALSE(0); | |||
| 1083 | } | |||
| 1084 | } | |||
| 1085 | else { | |||
| 1086 | icon->hot_x = -1; | |||
| 1087 | icon->hot_y = -1; | |||
| 1088 | } | |||
| 1089 | ||||
| 1090 | switch (icon->depth) { | |||
| 1091 | case 32: | |||
| 1092 | icon->xor_rowstride = icon->width * 4; | |||
| 1093 | break; | |||
| 1094 | case 24: | |||
| 1095 | icon->xor_rowstride = icon->width * 3; | |||
| 1096 | break; | |||
| 1097 | case 16: | |||
| 1098 | icon->xor_rowstride = icon->width * 2; | |||
| 1099 | break; | |||
| 1100 | default: | |||
| 1101 | g_set_error (error, | |||
| 1102 | CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (), | |||
| 1103 | CDK_PIXBUF_ERROR_BAD_OPTION, | |||
| 1104 | _("Unsupported depth for ICO file: %d")((char *) g_dgettext ("cdk-pixbuf", "Unsupported depth for ICO file: %d" )), icon->depth); | |||
| 1105 | return FALSE(0); | |||
| 1106 | } | |||
| 1107 | ||||
| 1108 | if ((icon->xor_rowstride % 4) != 0) | |||
| 1109 | icon->xor_rowstride = 4 * ((icon->xor_rowstride / 4) + 1); | |||
| 1110 | icon->xor = g_new0 (guchar, icon->xor_rowstride * icon->height)(guchar *) (__extension__ ({ gsize __n = (gsize) (icon->xor_rowstride * icon->height); gsize __s = sizeof (guchar); gpointer __p ; if (__s == 1) __p = g_malloc0 (__n); else if (__builtin_constant_p (__n) && (__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s); __p; })); | |||
| 1111 | ||||
| 1112 | icon->and_rowstride = (icon->width + 7) / 8; | |||
| 1113 | if ((icon->and_rowstride % 4) != 0) | |||
| 1114 | icon->and_rowstride = 4 * ((icon->and_rowstride / 4) + 1); | |||
| 1115 | icon->and = g_new0 (guchar, icon->and_rowstride * icon->height)(guchar *) (__extension__ ({ gsize __n = (gsize) (icon->and_rowstride * icon->height); gsize __s = sizeof (guchar); gpointer __p ; if (__s == 1) __p = g_malloc0 (__n); else if (__builtin_constant_p (__n) && (__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s); __p; })); | |||
| 1116 | ||||
| 1117 | pixels = cdk_pixbuf_get_pixels (pixbuf); | |||
| 1118 | n_channels = cdk_pixbuf_get_n_channels (pixbuf); | |||
| 1119 | for (y = 0; y < icon->height; y++) { | |||
| 1120 | p = pixels + (gsize) cdk_pixbuf_get_rowstride (pixbuf) * (icon->height - 1 - y); | |||
| 1121 | and = icon->and + icon->and_rowstride * y; | |||
| 1122 | xor = icon->xor + icon->xor_rowstride * y; | |||
| 1123 | for (x = 0; x < icon->width; x++) { | |||
| 1124 | switch (icon->depth) { | |||
| 1125 | case 32: | |||
| 1126 | xor[0] = p[2]; | |||
| 1127 | xor[1] = p[1]; | |||
| 1128 | xor[2] = p[0]; | |||
| 1129 | xor[3] = 0xff; | |||
| 1130 | if (n_channels == 4) { | |||
| 1131 | xor[3] = p[3]; | |||
| 1132 | if (p[3] < 0x80) | |||
| 1133 | *and |= 1 << (7 - x % 8); | |||
| 1134 | } | |||
| 1135 | xor += 4; | |||
| 1136 | break; | |||
| 1137 | case 24: | |||
| 1138 | xor[0] = p[2]; | |||
| 1139 | xor[1] = p[1]; | |||
| 1140 | xor[2] = p[0]; | |||
| 1141 | if (n_channels == 4 && p[3] < 0x80) | |||
| 1142 | *and |= 1 << (7 - x % 8); | |||
| 1143 | xor += 3; | |||
| 1144 | break; | |||
| 1145 | case 16: | |||
| 1146 | v = ((p[0] >> 3) << 10) | ((p[1] >> 3) << 5) | (p[2] >> 3); | |||
| 1147 | xor[0] = v & 0xff; | |||
| 1148 | xor[1] = v >> 8; | |||
| 1149 | if (n_channels == 4 && p[3] < 0x80) | |||
| 1150 | *and |= 1 << (7 - x % 8); | |||
| 1151 | xor += 2; | |||
| 1152 | break; | |||
| 1153 | } | |||
| 1154 | ||||
| 1155 | p += n_channels; | |||
| 1156 | if (x % 8 == 7) | |||
| 1157 | and++; | |||
| 1158 | } | |||
| 1159 | } | |||
| 1160 | ||||
| 1161 | return TRUE(!(0)); | |||
| 1162 | } | |||
| 1163 | ||||
| 1164 | static void | |||
| 1165 | free_entry (IconEntry *icon) | |||
| 1166 | { | |||
| 1167 | g_free (icon->colors); | |||
| 1168 | g_free (icon->and); | |||
| 1169 | g_free (icon->xor); | |||
| 1170 | g_free (icon); | |||
| 1171 | } | |||
| 1172 | ||||
| 1173 | static void | |||
| 1174 | write_icon (FILE *f, GSList *entries) | |||
| 1175 | { | |||
| 1176 | IconEntry *icon; | |||
| 1177 | GSList *entry; | |||
| 1178 | guint8 bytes[4]; | |||
| 1179 | guint16 words[4]; | |||
| 1180 | guint32 dwords[6]; | |||
| 1181 | gint type; | |||
| 1182 | gint n_entries; | |||
| 1183 | gint offset; | |||
| 1184 | gint size; | |||
| 1185 | ||||
| 1186 | if (((IconEntry *)entries->data)->hot_x > -1) | |||
| 1187 | type = 2; | |||
| 1188 | else | |||
| 1189 | type = 1; | |||
| 1190 | n_entries = g_slist_length (entries); | |||
| 1191 | ||||
| 1192 | /* header */ | |||
| 1193 | words[0] = 0; | |||
| 1194 | words[1] = type; | |||
| 1195 | words[2] = n_entries; | |||
| 1196 | write16 (f, words, 3); | |||
| 1197 | ||||
| 1198 | offset = 6 + 16 * n_entries; | |||
| 1199 | ||||
| 1200 | for (entry = entries; entry; entry = entry->next) { | |||
| 1201 | icon = (IconEntry *)entry->data; | |||
| 1202 | size = INFOHEADER_SIZE40 + icon->height * (icon->and_rowstride + icon->xor_rowstride); | |||
| 1203 | ||||
| 1204 | /* directory entry */ | |||
| 1205 | if (icon->width == 256) | |||
| 1206 | bytes[0] = 0; | |||
| 1207 | else | |||
| 1208 | bytes[0] = icon->width; | |||
| 1209 | if (icon->height == 256) | |||
| 1210 | bytes[1] = 0; | |||
| 1211 | else | |||
| 1212 | bytes[1] = icon->height; | |||
| 1213 | bytes[2] = icon->n_colors; | |||
| 1214 | bytes[3] = 0; | |||
| 1215 | write8 (f, bytes, 4); | |||
| 1216 | if (type == 1) { | |||
| 1217 | words[0] = 1; | |||
| 1218 | words[1] = icon->depth; | |||
| 1219 | } | |||
| 1220 | else { | |||
| 1221 | words[0] = icon->hot_x; | |||
| 1222 | words[1] = icon->hot_y; | |||
| 1223 | } | |||
| 1224 | write16 (f, words, 2); | |||
| 1225 | dwords[0] = size; | |||
| 1226 | dwords[1] = offset; | |||
| 1227 | write32 (f, dwords, 2); | |||
| 1228 | ||||
| 1229 | offset += size; | |||
| 1230 | } | |||
| 1231 | ||||
| 1232 | for (entry = entries; entry; entry = entry->next) { | |||
| 1233 | icon = (IconEntry *)entry->data; | |||
| 1234 | ||||
| 1235 | /* bitmap header */ | |||
| 1236 | dwords[0] = INFOHEADER_SIZE40; | |||
| 1237 | dwords[1] = icon->width; | |||
| 1238 | dwords[2] = icon->height * 2; | |||
| 1239 | write32 (f, dwords, 3); | |||
| 1240 | words[0] = 1; | |||
| 1241 | words[1] = icon->depth; | |||
| 1242 | write16 (f, words, 2); | |||
| 1243 | dwords[0] = 0; | |||
| 1244 | dwords[1] = 0; | |||
| 1245 | dwords[2] = 0; | |||
| 1246 | dwords[3] = 0; | |||
| 1247 | dwords[4] = 0; | |||
| 1248 | dwords[5] = 0; | |||
| 1249 | write32 (f, dwords, 6); | |||
| 1250 | ||||
| 1251 | /* image data */ | |||
| 1252 | write8 (f, icon->xor, icon->xor_rowstride * icon->height); | |||
| 1253 | write8 (f, icon->and, icon->and_rowstride * icon->height); | |||
| 1254 | } | |||
| 1255 | } | |||
| 1256 | ||||
| 1257 | /* Locale-independent signed integer string parser, base 10. | |||
| 1258 | * @minimum and @maximum are valid inclusively. */ | |||
| 1259 | static gboolean | |||
| 1260 | ascii_strtoll (const gchar *str, | |||
| 1261 | gint64 minimum, | |||
| 1262 | gint64 maximum, | |||
| 1263 | gint64 *out, | |||
| 1264 | GError **error) | |||
| 1265 | { | |||
| 1266 | gint64 retval; | |||
| 1267 | const gchar *end_ptr; | |||
| 1268 | ||||
| 1269 | errno(*__errno_location ()) = 0; | |||
| 1270 | retval = g_ascii_strtoll (str, (gchar **) &end_ptr, 10); | |||
| 1271 | ||||
| 1272 | if (errno(*__errno_location ()) != 0) { | |||
| 1273 | g_set_error_literal (error, | |||
| 1274 | G_IO_ERRORg_io_error_quark(), G_IO_ERROR_INVALID_ARGUMENT, | |||
| 1275 | g_strerror (errno(*__errno_location ()))); | |||
| 1276 | return FALSE(0); | |||
| 1277 | } else if (end_ptr == str || *end_ptr != '\0') { | |||
| 1278 | g_set_error (error, G_IO_ERRORg_io_error_quark(), G_IO_ERROR_INVALID_ARGUMENT, | |||
| 1279 | "Argument is not an integer: %s", str); | |||
| 1280 | return FALSE(0); | |||
| 1281 | } else if ((maximum < G_MAXINT64(0x7fffffffffffffffL) && retval > maximum) || | |||
| 1282 | (minimum > G_MININT64((gint64) (-(0x7fffffffffffffffL) - (1L))) && retval < minimum)) { | |||
| 1283 | g_set_error (error, G_IO_ERRORg_io_error_quark(), G_IO_ERROR_INVALID_ARGUMENT, | |||
| 1284 | "Argument should be in range [%" G_GINT64_FORMAT"li" | |||
| 1285 | ", %" G_GINT64_FORMAT"li" "]: %s", | |||
| 1286 | minimum, maximum, str); | |||
| 1287 | return FALSE(0); | |||
| 1288 | } | |||
| 1289 | ||||
| 1290 | g_assert (retval >= minimum && retval <= maximum)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_27 = 0; if (retval >= minimum && retval <= maximum ) _g_boolean_var_27 = 1; _g_boolean_var_27; }), 1)) ; else g_assertion_message_expr ("CdkPixbuf", "../cdk-pixbuf/io-ico.c", 1290, ((const char*) (__func__)), "retval >= minimum && retval <= maximum" ); } while (0); | |||
| 1291 | ||||
| 1292 | if (out != NULL((void*)0)) | |||
| 1293 | *out = retval; | |||
| 1294 | ||||
| 1295 | return TRUE(!(0)); | |||
| 1296 | } | |||
| 1297 | ||||
| 1298 | static gboolean | |||
| 1299 | cdk_pixbuf__ico_image_save (FILE *f, | |||
| 1300 | CdkPixbuf *pixbuf, | |||
| 1301 | gchar **keys, | |||
| 1302 | gchar **values, | |||
| 1303 | GError **error) | |||
| 1304 | { | |||
| 1305 | gint hot_x, hot_y; | |||
| 1306 | IconEntry *icon; | |||
| 1307 | GSList *entries = NULL((void*)0); | |||
| 1308 | ||||
| 1309 | /* support only single-image ICOs for now */ | |||
| 1310 | icon = g_new0 (IconEntry, 1)(IconEntry *) (__extension__ ({ gsize __n = (gsize) (1); gsize __s = sizeof (IconEntry); gpointer __p; if (__s == 1) __p = g_malloc0 (__n); else if (__builtin_constant_p (__n) && (__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s); __p ; })); | |||
| 1311 | icon->width = cdk_pixbuf_get_width (pixbuf); | |||
| 1312 | icon->height = cdk_pixbuf_get_height (pixbuf); | |||
| 1313 | icon->depth = cdk_pixbuf_get_has_alpha (pixbuf) ? 32 : 24; | |||
| 1314 | hot_x = -1; | |||
| 1315 | hot_y = -1; | |||
| 1316 | ||||
| 1317 | /* parse options */ | |||
| 1318 | if (keys && *keys) { | |||
| 1319 | gchar **kiter; | |||
| 1320 | gchar **viter; | |||
| 1321 | ||||
| 1322 | for (kiter = keys, viter = values; *kiter && *viter; kiter++, viter++) { | |||
| 1323 | gint64 out; | |||
| 1324 | if (strcmp (*kiter, "depth") == 0) { | |||
| 1325 | if (!ascii_strtoll (*viter, 1, 32, | |||
| 1326 | &out, error)) { | |||
| 1327 | free_entry (icon); | |||
| 1328 | return FALSE(0); | |||
| 1329 | } | |||
| 1330 | icon->depth = out; | |||
| 1331 | } | |||
| 1332 | else if (strcmp (*kiter, "x_hot") == 0) { | |||
| 1333 | if (!ascii_strtoll (*viter, G_MININT(-2147483647 -1), G_MAXINT2147483647, | |||
| 1334 | &out, error)) { | |||
| 1335 | free_entry (icon); | |||
| 1336 | return FALSE(0); | |||
| 1337 | } | |||
| 1338 | hot_x = out; | |||
| 1339 | } | |||
| 1340 | else if (strcmp (*kiter, "y_hot") == 0) { | |||
| 1341 | if (!ascii_strtoll (*viter, G_MININT(-2147483647 -1), G_MAXINT2147483647, | |||
| 1342 | &out, error)) { | |||
| 1343 | free_entry (icon); | |||
| 1344 | return FALSE(0); | |||
| 1345 | } | |||
| 1346 | hot_y = out; | |||
| 1347 | } | |||
| 1348 | ||||
| 1349 | } | |||
| 1350 | } | |||
| 1351 | ||||
| 1352 | if (!fill_entry (icon, pixbuf, hot_x, hot_y, error)) { | |||
| 1353 | free_entry (icon); | |||
| 1354 | return FALSE(0); | |||
| 1355 | } | |||
| 1356 | ||||
| 1357 | entries = g_slist_append (entries, icon); | |||
| 1358 | write_icon (f, entries); | |||
| 1359 | ||||
| 1360 | g_slist_foreach (entries, (GFunc)free_entry, NULL((void*)0)); | |||
| 1361 | g_slist_free (entries); | |||
| 1362 | ||||
| 1363 | return TRUE(!(0)); | |||
| 1364 | } | |||
| 1365 | ||||
| 1366 | static gboolean | |||
| 1367 | cdk_pixbuf__ico_is_save_option_supported (const gchar *option_key) | |||
| 1368 | { | |||
| 1369 | if (g_strcmp0 (option_key, "depth") == 0 || | |||
| 1370 | g_strcmp0 (option_key, "x_hot") == 0 || | |||
| 1371 | g_strcmp0 (option_key, "y_hot") == 0) | |||
| 1372 | return TRUE(!(0)); | |||
| 1373 | ||||
| 1374 | return FALSE(0); | |||
| 1375 | } | |||
| 1376 | ||||
| 1377 | #ifndef INCLUDE_ico | |||
| 1378 | #define MODULE_ENTRY(function)__attribute__((visibility("default"))) void function G_MODULE_EXPORT__attribute__((visibility("default"))) void function | |||
| 1379 | #else | |||
| 1380 | #define MODULE_ENTRY(function)__attribute__((visibility("default"))) void function void _cdk_pixbuf__ico_ ## function | |||
| 1381 | #endif | |||
| 1382 | ||||
| 1383 | MODULE_ENTRY (fill_vtable)__attribute__((visibility("default"))) void fill_vtable (CdkPixbufModule *module) | |||
| 1384 | { | |||
| 1385 | module->begin_load = cdk_pixbuf__ico_image_begin_load; | |||
| 1386 | module->stop_load = cdk_pixbuf__ico_image_stop_load; | |||
| 1387 | module->load_increment = cdk_pixbuf__ico_image_load_increment; | |||
| 1388 | module->save = cdk_pixbuf__ico_image_save; | |||
| 1389 | module->is_save_option_supported = cdk_pixbuf__ico_is_save_option_supported; | |||
| 1390 | } | |||
| 1391 | ||||
| 1392 | MODULE_ENTRY (fill_info)__attribute__((visibility("default"))) void fill_info (CdkPixbufFormat *info) | |||
| 1393 | { | |||
| 1394 | static const CdkPixbufModulePattern signature[] = { | |||
| 1395 | { " \x1 ", "zz znz", 100 }, | |||
| 1396 | { " \x2 ", "zz znz", 100 }, | |||
| 1397 | { NULL((void*)0), NULL((void*)0), 0 } | |||
| 1398 | }; | |||
| 1399 | static const gchar *mime_types[] = { | |||
| 1400 | "image/x-icon", | |||
| 1401 | "image/x-ico", | |||
| 1402 | "image/x-win-bitmap", | |||
| 1403 | "image/vnd.microsoft.icon", | |||
| 1404 | "application/ico", | |||
| 1405 | "image/ico", | |||
| 1406 | "image/icon", | |||
| 1407 | "text/ico", | |||
| 1408 | NULL((void*)0) | |||
| 1409 | }; | |||
| 1410 | static const gchar *extensions[] = { | |||
| 1411 | "ico", | |||
| 1412 | "cur", | |||
| 1413 | NULL((void*)0) | |||
| 1414 | }; | |||
| 1415 | ||||
| 1416 | info->name = "ico"; | |||
| 1417 | info->signature = (CdkPixbufModulePattern *) signature; | |||
| 1418 | info->description = NC_("image format", "Windows icon")("Windows icon"); | |||
| 1419 | info->mime_types = (gchar **) mime_types; | |||
| 1420 | info->extensions = (gchar **) extensions; | |||
| 1421 | info->flags = CDK_PIXBUF_FORMAT_WRITABLE | CDK_PIXBUF_FORMAT_THREADSAFE; | |||
| 1422 | info->license = "LGPL"; | |||
| 1423 | } | |||
| 1424 | ||||
| 1425 | ||||
| 1426 | ||||
| 1427 |