diff options
Diffstat (limited to 'gdk-pixbuf/gdk-pixbuf-data.c')
-rw-r--r-- | gdk-pixbuf/gdk-pixbuf-data.c | 130 |
1 files changed, 105 insertions, 25 deletions
diff --git a/gdk-pixbuf/gdk-pixbuf-data.c b/gdk-pixbuf/gdk-pixbuf-data.c index 94db20f376..a1b0232400 100644 --- a/gdk-pixbuf/gdk-pixbuf-data.c +++ b/gdk-pixbuf/gdk-pixbuf-data.c @@ -23,6 +23,7 @@ #include <config.h> #include "gdk-pixbuf.h" #include "gdk-pixbuf-private.h" +#include "gdk-pixbuf-i18n.h" #include <stdlib.h> #include <string.h> @@ -106,7 +107,10 @@ read_bool (const guchar **p) } static GdkPixbuf* -read_raw_inline (const guchar *data, gboolean copy_pixels, int length) +read_raw_inline (const guchar *data, + gboolean copy_pixels, + int length, + GError **error) { GdkPixbuf *pixbuf; const guchar *p = data; @@ -116,6 +120,11 @@ read_raw_inline (const guchar *data, gboolean copy_pixels, int length) if (length >= 0 && length < 12) { /* Not enough buffer to hold the width/height/rowstride */ + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Image data is partially missing")); + return NULL; } @@ -123,9 +132,14 @@ read_raw_inline (const guchar *data, gboolean copy_pixels, int length) width = read_int (&p); height = read_int (&p); - if (rowstride < width) + if (rowstride < width) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Image has an incorrect pixel rowstride, perhaps the data was corrupted somehow.")); return NULL; /* bad data from untrusted source. */ - + } + /* rowstride >= width, so we can trust width */ length -= 12; @@ -133,37 +147,71 @@ read_raw_inline (const guchar *data, gboolean copy_pixels, int length) /* There's some better way like G_MAXINT/height > rowstride * but I'm not sure it works, so stick to this for now. */ - if (((double)height) * ((double)rowstride) > (double)G_MAXINT) + if (((double)height) * ((double)rowstride) > (double)G_MAXINT) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Image size is impossibly large, perhaps the data was corrupted somehow")); + return NULL; /* overflow */ - + } + if (length >= 0 && length < (height * rowstride + 13)) { /* Not enough buffer to hold the remaining header * information plus the data. */ + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Image data is partially missing, probably it was ocorrupted somehow.")); return NULL; } - + /* Read the remaining 13 bytes of header information */ has_alpha = read_bool (&p) != FALSE; colorspace = read_int (&p); n_channels = read_int (&p); bits_per_sample = read_int (&p); - - if (colorspace != GDK_COLORSPACE_RGB) + + if (colorspace != GDK_COLORSPACE_RGB) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Image has an unknown colorspace code (%d), perhaps the image data was corrupted"), + colorspace); return NULL; + } - if (bits_per_sample != 8) + if (bits_per_sample != 8) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Image has an improper number of bits per sample (%d), perhaps the image data was corrupted"), + bits_per_sample); return NULL; - - if (has_alpha && n_channels != 4) + } + + if (has_alpha && n_channels != 4) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Image has an improper number of channels (%d), perhaps the image data was corrupted"), + n_channels); return NULL; - - if (!has_alpha && n_channels != 3) + } + + if (!has_alpha && n_channels != 3) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Image has an improper number of channels (%d), perhaps the image data was corrupted"), + n_channels); return NULL; - + } + if (copy_pixels) { guchar *pixels; gint dest_rowstride; @@ -172,10 +220,19 @@ read_raw_inline (const guchar *data, gboolean copy_pixels, int length) pixbuf = gdk_pixbuf_new (colorspace, has_alpha, bits_per_sample, width, height); - + + if (pixbuf == NULL) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Not enough memory to store a %d by %d image; try exiting some applications to free memory."), + width, height); + return NULL; + } + pixels = gdk_pixbuf_get_pixels (pixbuf); dest_rowstride = gdk_pixbuf_get_rowstride (pixbuf); - + for (row = 0; row < height; row++) { memcpy (pixels, p, rowstride); pixels += dest_rowstride; @@ -190,32 +247,42 @@ read_raw_inline (const guchar *data, gboolean copy_pixels, int length) rowstride, NULL, NULL); } - + return pixbuf; } /** * gdk_pixbuf_new_from_inline: - * @data: An inlined GdkPixbuf + * @inline_pixbuf: An inlined GdkPixbuf * @copy_pixels: whether to copy the pixels out of the inline data, or to use them in-place + * @length: length of the inline data + * @error: return location for error * * Create a #GdkPixbuf from a custom format invented to store pixbuf - * data in C program code. This library comes with a program called "make-inline-pixbuf" - * that can write out a variable definition containing an inlined pixbuf. - * This is useful if you want to ship a program with images, but - * don't want to depend on any external files. + * data in C program code. This library comes with a program called + * "make-inline-pixbuf" that can write out a variable definition + * containing an inlined pixbuf. This is useful if you want to ship a + * program with images, but don't want to depend on any external + * files. * * The inline data format contains the pixels in #GdkPixbuf's native * format. Since the inline pixbuf is read-only static data, you * don't need to copy it unless you intend to write to it. * + * If you create a pixbuf from const inline data compiled into your + * program, it's probably safe to ignore errors, since things will + * always succeed. For non-const inline data, you could get out of + * memory. For untrusted inline data located at runtime, you could + * have corrupt inline data in addition. + * * Return value: A newly-created #GdkPixbuf structure with a reference count of - * 1. + * 1, or NULL If error is set. **/ GdkPixbuf* gdk_pixbuf_new_from_inline (const guchar *inline_pixbuf, gboolean copy_pixels, - int length) + int length, + GError **error) { const guchar *p; GdkPixbuf *pixbuf; @@ -225,12 +292,20 @@ gdk_pixbuf_new_from_inline (const guchar *inline_pixbuf, /* not enough bytes to contain even the magic number * and format code. */ + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Image contained no data.")); return NULL; } p = inline_pixbuf; if (read_int (&p) != GDK_PIXBUF_INLINE_MAGIC_NUMBER) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Image isn't in the correct format (inline GdkPixbuf format)")); return NULL; } @@ -239,10 +314,15 @@ gdk_pixbuf_new_from_inline (const guchar *inline_pixbuf, switch (format) { case GDK_PIXBUF_INLINE_RAW: - pixbuf = read_raw_inline (p, copy_pixels, length - 8); + pixbuf = read_raw_inline (p, copy_pixels, length - 8, error); break; default: + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_UNKNOWN_TYPE, + _("This version of the software is unable to read images with type code %d"), + format); return NULL; } |