#include <string.h>
#include "gdk-pixbuf-private.h"
#include "gdk-pixbuf-io.h"
+#include <errno.h>
\f
/* Progressive loading */
struct headerpair {
- guint width;
- guint height;
+ gint width;
+ gint height;
guint depth;
guint Negative; /* Negative = 1 -> top down BMP,
Negative = 0 -> bottom up BMP */
const guchar * buf, guint size,
GError **error);
+static void
+context_free (struct ico_progressive_state *context)
+{
+ if (context->LineBuf != NULL)
+ g_free (context->LineBuf);
+ context->LineBuf = NULL;
+ if (context->HeaderBuf != NULL)
+ g_free (context->HeaderBuf);
+ if (context->pixbuf)
+ gdk_pixbuf_unref (context->pixbuf);
+ g_free (context);
+}
+
/* Shared library entry point --> Can go when generic_image_load
enters gdk-pixbuf-io */
static GdkPixbuf *
gdk_pixbuf__ico_image_load(FILE * f, GError **error)
{
- guchar *membuf;
+ guchar membuf [4096];
size_t length;
struct ico_progressive_state *State;
State = gdk_pixbuf__ico_image_begin_load(NULL, NULL, NULL, error);
if (State == NULL)
- return NULL;
+ return NULL;
- membuf = g_malloc(4096);
-
- g_assert(membuf != NULL);
-
- while (feof(f) == 0) {
+ while (!feof(f)) {
length = fread(membuf, 1, 4096, f);
+ if (ferror (f)) {
+ g_set_error (error,
+ G_FILE_ERROR,
+ g_file_error_from_errno (errno),
+ _("Failure reading ICO: %s"), g_strerror (errno));
+ context_free (State);
+ return NULL;
+ }
if (length > 0)
if (!gdk_pixbuf__ico_image_load_increment(State, membuf, length,
error)) {
- gdk_pixbuf__ico_image_stop_load (State, NULL);
+ context_free (State);
return NULL;
- }
+ }
}
- g_free(membuf);
if (State->pixbuf != NULL)
- gdk_pixbuf_ref(State->pixbuf);
+ gdk_pixbuf_ref (State->pixbuf);
+ else {
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("ICO file was missing some data (perhaps it was truncated somehow?)"));
+ context_free (State);
+ return NULL;
+ }
pb = State->pixbuf;
}
static void DecodeHeader(guchar *Data, gint Bytes,
- struct ico_progressive_state *State)
+ struct ico_progressive_state *State,
+ GError **error)
{
/* For ICO's we have to be very clever. There are multiple images possible
in an .ICO. For now, we select (in order of priority):
State->HeaderSize = 6 + IconCount*16;
if (State->HeaderSize>State->BytesInHeaderBuf) {
- State->HeaderBuf=g_realloc(State->HeaderBuf,State->HeaderSize);
+ State->HeaderBuf=g_try_realloc(State->HeaderBuf,State->HeaderSize);
+ if (!State->HeaderBuf) {
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+ _("Not enough memory to load icon"));
+ return;
+ }
State->BytesInHeaderBuf = State->HeaderSize;
}
if (Bytes < State->HeaderSize)
State->HeaderSize = State->DIBoffset + 40; /* 40 = sizeof(InfoHeader) */
if (State->HeaderSize>State->BytesInHeaderBuf) {
- State->HeaderBuf=g_realloc(State->HeaderBuf,State->HeaderSize);
+ State->HeaderBuf=g_try_realloc(State->HeaderBuf,State->HeaderSize);
+ if (!State->HeaderBuf) {
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+ _("Not enough memory to load icon"));
+ return;
+ }
State->BytesInHeaderBuf = State->HeaderSize;
}
if (Bytes<State->HeaderSize)
State->Header.width =
(int)(BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) + (BIH[4]);
+ if (State->Header.width == 0) {
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("Icon has zero width"));
+ return;
+ }
State->Header.height =
(int)(BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) + (BIH[8])/2;
/* /2 because the BIH height includes the transparency mask */
+ if (State->Header.height == 0) {
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("Icon has zero height"));
+ return;
+ }
State->Header.depth = (BIH[15] << 8) + (BIH[14]);;
State->Type = State->Header.depth;
State->HeaderSize+=I;
if (State->HeaderSize>State->BytesInHeaderBuf) {
- State->HeaderBuf=g_realloc(State->HeaderBuf,State->HeaderSize);
+ State->HeaderBuf=g_try_realloc(State->HeaderBuf,State->HeaderSize);
+ if (!State->HeaderBuf) {
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+ _("Not enough memory to load icon"));
+ return;
+ }
State->BytesInHeaderBuf = State->HeaderSize;
}
if (Bytes < State->HeaderSize)
if ((BIH[16] != 0) || (BIH[17] != 0) || (BIH[18] != 0)
|| (BIH[19] != 0)) {
- g_assert(0); /* Compressed icons aren't allowed */
+ /* FIXME: is this the correct message? */
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("Compressed icons are not supported"));
+ return;
}
/* Negative heights mean top-down pixel-order */
if (State->Header.width < 0) {
State->Header.width = -State->Header.width;
}
+ g_assert (State->Header.width > 0);
+ g_assert (State->Header.height > 0);
if (State->Type == 24)
State->LineWidth = State->Header.width * 3;
State->LineWidth = (State->LineWidth / 4) * 4 + 4;
- if (State->LineBuf == NULL)
- State->LineBuf = g_malloc(State->LineWidth);
+ if (State->LineBuf == NULL) {
+ State->LineBuf = g_try_malloc(State->LineWidth);
+ if (!State->LineBuf) {
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+ _("Not enough memory to load icon"));
+ }
+ return;
+ }
g_assert(State->LineBuf != NULL);
if (State->pixbuf == NULL) {
State->pixbuf =
gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
- (gint) State->Header.width,
- (gint) State->Header.height);
+ State->Header.width,
+ State->Header.height);
if (State->prepared_func != NULL)
/* Notify the client that we are ready to go */
context->user_data = user_data;
context->HeaderSize = 54;
- context->HeaderBuf = g_malloc(14 + 40 + 4*256 + 512);
+ context->HeaderBuf = g_try_malloc(14 + 40 + 4*256 + 512);
+ if (!context->HeaderBuf) {
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+ _("Not enough memory to load ICO file"));
+ return NULL;
+ }
/* 4*256 for the colormap */
context->BytesInHeaderBuf = 14 + 40 + 4*256 + 512 ;
context->HeaderDone = 0;
*/
g_return_val_if_fail(context != NULL, TRUE);
-
- if (context->LineBuf != NULL)
- g_free(context->LineBuf);
- context->LineBuf = NULL;
- if (context->HeaderBuf != NULL)
- g_free(context->HeaderBuf);
-
- if (context->pixbuf)
- gdk_pixbuf_unref(context->pixbuf);
-
- g_free(context);
-
+
+ context_free (context);
return TRUE;
}
size -= BytesToCopy;
buf += BytesToCopy;
context->HeaderDone += BytesToCopy;
-
- } else
- {
+ }
+ else {
BytesToCopy =
context->LineWidth - context->LineDone;
if (BytesToCopy > size)
}
- if (context->HeaderDone >= 6)
+ if (context->HeaderDone >= 6) {
+ GError *decode_err = NULL;
DecodeHeader(context->HeaderBuf,
- context->HeaderDone, context);
-
-
+ context->HeaderDone, context, &decode_err);
+ if (decode_err) {
+ g_propagate_error (error, decode_err);
+ return FALSE;
+ }
+ }
}
return TRUE;
0
};
+static unsigned char const valid_ico_test[] = {
+ 0, 0, 1, 0, 1, 0, 16, 16, 16, 0, 0, 0, 0, 0, 40, 1, 0, 0, 22, 0, 0,
+ 0, 40, 0, 0, 0, 16, 0, 0, 0, 32, 0, 0, 0, 1, 0, 4, 0, 0, 0, 0, 0,
+ 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 128, 0, 0, 128, 0, 0, 0, 128, 128, 0, 128, 0, 0, 0, 128,
+ 0, 128, 0, 128, 128, 0, 0, 192, 192, 192, 0, 128, 128, 128, 0, 0, 0,
+ 255, 0, 0, 255, 0, 0, 0, 255, 255, 0, 255, 0, 0, 0, 255, 0, 255, 0,
+ 255, 255, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 153, 153, 153, 9, 144, 0, 0, 0, 0, 153, 0, 0, 0, 0, 0, 0, 0, 153, 0,
+ 0, 153, 0, 0, 0, 9, 153, 144, 0, 153, 144, 0, 0, 153, 144, 153, 0,
+ 9, 144, 0, 9, 153, 0, 9, 144, 9, 153, 0, 153, 144, 0, 153, 153, 153,
+ 153, 153, 153, 153, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 240, 55, 0, 0, 240,
+ 39, 0, 0, 252, 123, 0, 0, 252, 113, 0, 0, 248, 48, 0, 0, 241, 24, 0,
+ 0, 227, 136, 0, 0, 129, 0, 0, 0, 1, 255, 0, 0, 255, 255, 0, 0, 255,
+ 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0
+};
+
+static unsigned char const ico_test_1[] = {
+ 0, 0, 1, 0, 1, 0, 16, 16, 16, 0, 0, 0, 0, 0, 40, 1, 0, 0, 22, 0,
+ 0, 0, 40, 0, 0, 0, 16, 0, 0, 0, 32, 0, 0, 0, 1, 0, 4, 0, 0, 222,
+ 0, 0, 128, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 128, 0, 0, 0, 128, 128, 0, 128, 0,
+ 0, 0, 128, 0, 128, 0, 128, 128, 0, 0, 192, 192, 192, 0, 128, 128,
+ 128, 0, 0, 0, 255, 0, 0, 255, 0, 0, 0, 255, 255, 0, 255, 0, 0, 0,
+ 255, 0 , 255, 0, 255, 255, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 153, 153, 153, 9, 144, 0, 0, 0, 0, 153, 0, 0,
+ 0, 0, 0, 0, 0, 153, 0, 0, 153, 0, 0, 0, 9, 153, 144, 0, 153, 144,
+ 0, 0, 153, 144, 153, 251, 9, 144, 0, 9, 153, 0, 9, 144, 9, 153 ,
+ 0, 153, 144, 0, 153, 153, 153, 153, 153, 153, 153, 144, 0, 0, 0,
+ 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0,
+ 255, 255, 0, 0, 240, 55, 0, 0, 240, 39, 0, 0, 252, 123, 0, 0, 252,
+ 113, 0, 0, 248, 48, 0, 0, 241, 24, 0, 0, 227, 136, 0, 0 , 129, 0,
+ 0, 0, 1, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0,
+ 0, 255, 255, 0, 0
+};
+
+static unsigned char const wbmp_test_1[] = {
+ 0, 0, 189, 179, 1, 0, 16, 180, 16, 0, 0, 230, 0, 0, 40, 1, 0, 0,
+ 22, 0, 0, 115, 40, 0, 0, 0, 16, 0, 0, 0, 32, 56, 0, 0, 1, 70, 4,
+ 92, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 128, 0, 0, 128, 0, 0, 135, 128,
+ 128, 0, 128, 0, 0, 0, 248, 0, 128, 0, 128, 128, 0, 154, 84, 192,
+ 176, 0, 128, 128, 128, 0, 0, 0, 255, 0, 0, 255, 151, 0, 0, 161,
+ 255, 0, 255, 0, 0, 0, 255, 0, 255, 0, 255, 255, 0, 0, 255, 250,
+ 255, 0, 0, 159, 0, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 216, 0, 0, 148,
+ 0, 0, 0, 24, 0, 187, 0, 229, 0, 0, 0, 0, 0, 67, 0, 90, 0, 65, 153,
+ 153, 9, 144, 205, 236, 0, 0, 153, 0, 0, 0, 0, 0, 0, 251, 249, 0,
+ 0, 194, 0, 97, 0, 9, 153, 144, 0, 153, 144, 0, 255, 153, 144, 153,
+ 150, 9, 144, 0, 9, 153, 141, 9, 198, 9, 153, 0, 153, 153, 208,
+ 153, 153, 233, 239, 153, 153, 153, 144, 0, 0, 71, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 61, 0, 0, 0, 0, 17, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 171, 235, 0, 0, 103, 255, 0, 60, 255, 255, 0,
+ 0, 240, 55, 0, 41, 240, 39, 220, 0, 252, 123, 0, 0, 58, 113, 0,
+ 178, 248, 48, 233, 0, 241, 183, 42, 0, 130, 136, 0, 0, 129, 88, 0,
+ 0, 1, 255, 0, 0, 175, 93, 26, 0, 255, 255, 0, 149, 255, 255, 0,
+ 198, 212, 255, 0, 0,
+};
+
+static unsigned char const wbmp_test_2[] = {
+ 0, 0, 1, 111, 172, 0, 16, 16, 227, 0, 162, 150, 0, 24, 40, 208, 0,
+ 0, 22, 0, 0, 0, 40, 9, 0, 0, 16, 0, 221, 55, 32, 0, 0, 49, 1, 0,
+ 4, 0, 0, 0, 171, 0, 128, 0, 0, 24, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 128, 0, 0, 128, 0, 0, 0, 128,
+ 128, 0, 128, 0, 0, 0, 128, 107, 128, 0, 128, 128, 0, 0, 192, 248,
+ 192, 234, 128, 128, 128, 209, 0, 28, 255, 0, 0, 255, 0, 0, 0, 255,
+ 255, 0, 255, 0, 0, 0, 102, 0, 255, 0, 130, 255, 0, 0, 255, 255,
+ 255, 202, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 232, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 81, 0, 153, 153, 153,
+ 99, 144, 0, 0, 0, 0, 153, 0, 0, 0, 0, 0, 0, 0, 153, 0, 0, 153,
+ 255, 0, 0, 10, 153, 144, 0, 153, 144, 0, 0, 153, 144, 153, 96, 9,
+ 144, 0, 9, 153, 0, 9, 144, 9, 153, 0, 153, 144, 0, 153, 254, 153,
+ 153, 153, 153, 153, 144, 0, 0, 0, 168, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 5, 0, 47, 17, 0, 0, 0, 0, 0, 0, 250, 93, 47, 0,
+ 133, 28, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 240,
+ 55, 211, 0, 240, 39, 0, 169, 252, 123, 0, 0, 252, 118, 0, 0, 248,
+ 48, 26, 0, 122, 24, 0, 0, 227, 108, 0, 0, 129, 0, 0, 133, 1, 255,
+ 0, 0, 142, 255, 0, 0, 255, 255, 88, 40, 120, 64, 0, 178, 168, 255,
+ 151, 147
+};
+
static unsigned char const valid_jpeg_test[] = {
JPEG_HEADER,
255, 224, 0, 16, 74, 70, 73, 70, 0, 1, 1, 1, 0, 72, 0, 72, 0, 0,