diff options
author | Owen Taylor <otaylor@src.gnome.org> | 2001-06-26 16:19:01 +0000 |
---|---|---|
committer | Owen Taylor <otaylor@src.gnome.org> | 2001-06-26 16:19:01 +0000 |
commit | bbd7adb1e857dcc718e0b62f05071847966b6a41 (patch) | |
tree | 7b2c86a23d311ba28630fdd16f7a526e940d331b /gdk-pixbuf/gdk-pixbuf-data.c | |
parent | 3450e8a239f543335add5fb5cc0b95979e79c30d (diff) | |
download | gdk-pixbuf-bbd7adb1e857dcc718e0b62f05071847966b6a41.tar.gz |
Revert inline-pixbuf changes until Tim comes back to fix missing files
Diffstat (limited to 'gdk-pixbuf/gdk-pixbuf-data.c')
-rw-r--r-- | gdk-pixbuf/gdk-pixbuf-data.c | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/gdk-pixbuf/gdk-pixbuf-data.c b/gdk-pixbuf/gdk-pixbuf-data.c index 15f5aa8b8..95903b527 100644 --- a/gdk-pixbuf/gdk-pixbuf-data.c +++ b/gdk-pixbuf/gdk-pixbuf-data.c @@ -78,3 +78,254 @@ gdk_pixbuf_new_from_data (const guchar *data, GdkColorspace colorspace, gboolean return pixbuf; } + +static guint32 +read_int (const guchar **p) +{ + guint32 num; + + /* Note most significant bytes are first in the byte stream */ + num = + (*p)[3] | + ((*p)[2] << 8) | + ((*p)[1] << 16) | + ((*p)[0] << 24); + + *p += 4; + + return num; +} + +static gboolean +read_bool (const guchar **p) +{ + gboolean val = **p != 0; + + ++(*p); + + return val; +} + +static GdkPixbuf* +read_raw_inline (const guchar *data, + gboolean copy_pixels, + int length, + GError **error) +{ + GdkPixbuf *pixbuf; + const guchar *p = data; + guint32 rowstride, width, height, colorspace, + n_channels, bits_per_sample; + gboolean has_alpha; + + 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; + } + + rowstride = read_int (&p); + width = read_int (&p); + height = read_int (&p); + + 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; + + /* 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) { + 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 corrupted 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) { + 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) { + 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) { + 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) { + 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; + gint row; + + 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; + p += rowstride; + } + } else { + pixbuf = gdk_pixbuf_new_from_data (p, + colorspace, + has_alpha, + bits_per_sample, + width, height, + rowstride, + NULL, NULL); + } + + return pixbuf; +} + +/** + * gdk_pixbuf_new_from_inline: + * @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. + * + * 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, or NULL If error is set. + **/ +GdkPixbuf* +gdk_pixbuf_new_from_inline (const guchar *inline_pixbuf, + gboolean copy_pixels, + int length, + GError **error) +{ + const guchar *p; + GdkPixbuf *pixbuf; + GdkPixbufInlineFormat format; + + if (length >= 0 && length < 8) { + /* 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; + } + + format = read_int (&p); + + switch (format) + { + case GDK_PIXBUF_INLINE_RAW: + 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; + } + + return pixbuf; +} + |