summaryrefslogtreecommitdiff
path: root/gdk-pixbuf/io-pnm.c
diff options
context:
space:
mode:
authorMatthias Clasen <matthiasc@src.gnome.org>2001-09-14 22:04:55 +0000
committerMatthias Clasen <matthiasc@src.gnome.org>2001-09-14 22:04:55 +0000
commit49b3e05a30bb7de83f3c1016d11ee7e482f439a5 (patch)
treeb3cafb1c7355ae8a6fbd4e6ca94ab2d6b2010f8a /gdk-pixbuf/io-pnm.c
parenta5f9754350e803af7838a3c98a34418077e52fbb (diff)
downloadgdk-pixbuf-49b3e05a30bb7de83f3c1016d11ee7e482f439a5.tar.gz
Robustness fixes and test images for the jpeg, tiff, pnm, gif, xpm and tga
loaders.
Diffstat (limited to 'gdk-pixbuf/io-pnm.c')
-rw-r--r--gdk-pixbuf/io-pnm.c148
1 files changed, 112 insertions, 36 deletions
diff --git a/gdk-pixbuf/io-pnm.c b/gdk-pixbuf/io-pnm.c
index 6bba2285c..eafe13093 100644
--- a/gdk-pixbuf/io-pnm.c
+++ b/gdk-pixbuf/io-pnm.c
@@ -23,7 +23,6 @@
*/
#include <config.h>
-#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -203,7 +202,7 @@ pnm_skip_whitespace (PnmIOBuffer *inbuf, GError **error)
return PNM_SUSPEND;
}
- } else if (!isspace (*inptr)) {
+ } else if (!g_ascii_isspace (*inptr)) {
inbuf->byte = inptr;
inbuf->nbytes = (guint) (inend - inptr);
return PNM_OK;
@@ -221,9 +220,10 @@ static gint
pnm_read_next_value (PnmIOBuffer *inbuf, guint *value, GError **error)
{
register guchar *inptr, *word, *p;
- guchar *inend, buf[128];
+ guchar *inend, buf[129];
gchar *endptr;
gint retval;
+ glong result;
g_return_val_if_fail (inbuf != NULL, PNM_FATAL_ERR);
g_return_val_if_fail (inbuf->byte != NULL, PNM_FATAL_ERR);
@@ -237,24 +237,25 @@ pnm_read_next_value (PnmIOBuffer *inbuf, guint *value, GError **error)
inptr = inbuf->byte;
/* copy this pnm 'word' into a temp buffer */
- for (p = inptr, word = buf; (p < inend) && !isspace (*p) && (p - inptr < 128); p++, word++)
+ for (p = inptr, word = buf; (p < inend) && !g_ascii_isspace (*p) && (*p != '#') && (p - inptr < 128); p++, word++)
*word = *p;
*word = '\0';
/* hmmm, there must be more data to this 'word' */
- if (!isspace (*p))
- return PNM_SUSPEND;
+ if (!g_ascii_isspace (*p) && (*p != '#') && (p - inptr < 128))
+ return PNM_SUSPEND;
/* get the value */
- *value = strtol (buf, &endptr, 10);
- if (*endptr != '\0') {
+ result = strtol (buf, &endptr, 10);
+ if (*endptr != '\0' || result < 0) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
_("PNM loader expected to find an integer, but didn't"));
return PNM_FATAL_ERR;
}
-
+ *value = result;
+
inbuf->byte = p;
inbuf->nbytes = (guint) (inend - p);
@@ -281,7 +282,7 @@ pnm_read_header (PnmLoaderContext *context)
if (*inbuf->byte != 'P') {
g_set_error (context->error,
GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ GDK_PIXBUF_ERROR_HEADER_CORRUPT,
_("PNM file has an incorrect initial byte"));
return PNM_FATAL_ERR;
}
@@ -311,7 +312,7 @@ pnm_read_header (PnmLoaderContext *context)
default:
g_set_error (context->error,
GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ GDK_PIXBUF_ERROR_HEADER_CORRUPT,
_("PNM file is not in a recognized PNM subformat"));
return PNM_FATAL_ERR;
}
@@ -336,7 +337,7 @@ pnm_read_header (PnmLoaderContext *context)
if (!width) {
g_set_error (context->error,
GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ GDK_PIXBUF_ERROR_HEADER_CORRUPT,
_("PNM file has an image width of 0"));
return PNM_FATAL_ERR;
}
@@ -357,7 +358,7 @@ pnm_read_header (PnmLoaderContext *context)
if (!height) {
g_set_error (context->error,
GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ GDK_PIXBUF_ERROR_HEADER_CORRUPT,
_("PNM file has an image height of 0"));
return PNM_FATAL_ERR;
}
@@ -380,8 +381,24 @@ pnm_read_header (PnmLoaderContext *context)
if (context->maxval == 0) {
g_set_error (context->error,
GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
- _("Maximum color value in PNM file is 0"));
+ GDK_PIXBUF_ERROR_HEADER_CORRUPT,
+ _("Maximum color value in PNM file is 0"));
+ return PNM_FATAL_ERR;
+ }
+
+ if (context->maxval > 65535) {
+ g_set_error (context->error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_HEADER_CORRUPT,
+ _("Maximum color value in PNM file is too large"));
+ return PNM_FATAL_ERR;
+ }
+
+ if (context->maxval > 255) {
+ g_set_error (context->error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_HEADER_CORRUPT,
+ _("Can't handle PNM files with maximum color values greater than 255"));
return PNM_FATAL_ERR;
}
}
@@ -677,7 +694,7 @@ gdk_pixbuf__pnm_image_load (FILE *f, GError **error)
inbuf = &context.inbuf;
- while (!feof (f)) {
+ while (TRUE) {
guint num_to_read;
/* keep buffer as full as possible */
@@ -689,11 +706,14 @@ gdk_pixbuf__pnm_image_load (FILE *f, GError **error)
nbytes = fread (inbuf->buffer + inbuf->nbytes, 1, num_to_read, f);
/* error checking */
- if (nbytes == 0 && ferror (f)) {
+ if (nbytes == 0) {
/* we ran out of data? */
if (context.pixbuf)
gdk_pixbuf_unref (context.pixbuf);
- g_warning ("io-pnm.c: Ran out of data.\n");
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("Premature end-of-file encountered"));
return NULL;
}
@@ -713,23 +733,47 @@ gdk_pixbuf__pnm_image_load (FILE *f, GError **error)
/* scan until we hit image data */
if (!context.did_prescan) {
- retval = pnm_skip_whitespace (inbuf,
- context.error);
- if (retval == PNM_FATAL_ERR)
- return NULL;
- else if (retval == PNM_SUSPEND)
- continue;
-
+ switch (context.type) {
+ case PNM_FORMAT_PBM_RAW:
+ case PNM_FORMAT_PGM_RAW:
+ case PNM_FORMAT_PPM_RAW:
+ if (inbuf->nbytes <= 0)
+ continue;
+ /* raw formats require exactly one whitespace */
+ if (!g_ascii_isspace(*(inbuf->byte)))
+ {
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("Raw PNM formats require exactly one whitespace before sample data"));
+ return NULL;
+ }
+ inbuf->nbytes--;
+ inbuf->byte++;
+ break;
+ default:
+ retval = pnm_skip_whitespace (inbuf,
+ context.error);
+ if (retval == PNM_FATAL_ERR)
+ return NULL;
+ else if (retval == PNM_SUSPEND)
+ continue;
+ break;
+ }
context.did_prescan = TRUE;
context.output_row = 0;
context.output_col = 0;
context.rowstride = context.width * 3;
- context.pixels = g_malloc (context.height * context.width * 3);
+ context.pixels = g_try_malloc (context.height * context.width * 3);
if (!context.pixels) {
/* Failed to allocate memory */
- g_warning ("Couldn't allocate pixel buf");
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+ _("Can't allocate memory for loading PNM image"));
+ return NULL;
}
}
@@ -773,7 +817,14 @@ gdk_pixbuf__pnm_image_begin_load (ModulePreparedNotifyFunc prepared_func,
{
PnmLoaderContext *context;
- context = g_new0 (PnmLoaderContext, 1);
+ context = g_try_malloc (sizeof (PnmLoaderContext));
+ if (!context) {
+ g_set_error(error, GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+ _("Insufficient memory to load PNM context struct"));
+ return NULL;
+ }
+ memset (context, 0, sizeof (PnmLoaderContext));
context->prepared_func = prepared_func;
context->updated_func = updated_func;
context->user_data = user_data;
@@ -811,6 +862,11 @@ gdk_pixbuf__pnm_image_stop_load (gpointer data,
if (context->pixbuf)
gdk_pixbuf_unref (context->pixbuf);
+#if 0
+ /* We should ignore trailing newlines and we can't
+ generally complain about trailing stuff at all, since
+ pnm allows to put multiple images in a file
+ */
if (context->inbuf.nbytes > 0) {
g_set_error (error,
GDK_PIXBUF_ERROR,
@@ -818,6 +874,7 @@ gdk_pixbuf__pnm_image_stop_load (gpointer data,
_("Unexpected end of PNM image data"));
retval = FALSE;
}
+#endif
g_free (context);
@@ -895,14 +952,33 @@ gdk_pixbuf__pnm_image_load_increment (gpointer data,
/* scan until we hit image data */
if (!context->did_prescan) {
- retval = pnm_skip_whitespace (inbuf,
- context->error);
-
- if (retval == PNM_FATAL_ERR)
- return FALSE;
- else if (retval == PNM_SUSPEND)
- continue;
-
+ switch (context->type) {
+ case PNM_FORMAT_PBM_RAW:
+ case PNM_FORMAT_PGM_RAW:
+ case PNM_FORMAT_PPM_RAW:
+ if (inbuf->nbytes <= 0)
+ continue;
+ /* raw formats require exactly one whitespace */
+ if (!g_ascii_isspace(*(inbuf->byte)))
+ {
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("Raw PNM formats require exactly one whitespace before sample data"));
+ return FALSE;
+ }
+ inbuf->nbytes--;
+ inbuf->byte++;
+ break;
+ default:
+ retval = pnm_skip_whitespace (inbuf,
+ context->error);
+ if (retval == PNM_FATAL_ERR)
+ return FALSE;
+ else if (retval == PNM_SUSPEND)
+ continue;
+ break;
+ }
context->did_prescan = TRUE;
context->output_row = 0;
context->output_col = 0;