summaryrefslogtreecommitdiff
path: root/gdk-pixbuf/gdk-pixbuf-data.c
diff options
context:
space:
mode:
authorOwen Taylor <otaylor@src.gnome.org>2001-06-26 16:19:01 +0000
committerOwen Taylor <otaylor@src.gnome.org>2001-06-26 16:19:01 +0000
commitbbd7adb1e857dcc718e0b62f05071847966b6a41 (patch)
tree7b2c86a23d311ba28630fdd16f7a526e940d331b /gdk-pixbuf/gdk-pixbuf-data.c
parent3450e8a239f543335add5fb5cc0b95979e79c30d (diff)
downloadgdk-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.c251
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;
+}
+