Commit 63cec32f authored by Gerd Moellmann's avatar Gerd Moellmann

(gif_load): Avoid sign extension and thus out of bounds

color indices when accessing raster pixels.
(gif_image_p, png_image_p, jpeg_image_p, tiff_image_p): Allow only
one of :file or :data.
(enum pbm_keyword_index): Add PBM_DATA.
(pbm_format): Add :data.
(pbm_image_p): Allow either :file or :data.
(pbm_read_file): New function.
(pbm_scan_number): Rewritten to read from string.
(pbm_load): Support :data.
parent 3998eed0
No preview for this file type
...@@ -19,17 +19,6 @@ along with GNU Emacs; see the file COPYING. If not, write to ...@@ -19,17 +19,6 @@ along with GNU Emacs; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */ Boston, MA 02111-1307, USA. */
/* Ability to read images from memory instead of a file added by
William Perry <wmperry@gnu.org> */
/* Image support (XBM, XPM, PBM, JPEG, TIFF, GIF, PNG, GS). tooltips,
tool-bars, busy-cursor, file selection dialog added by Gerd
Moellmann <gerd@gnu.org>. */
/* Completely rewritten by Richard Stallman. */
/* Rewritten for X11 by Joseph Arceneaux */
#include <config.h> #include <config.h>
#include <signal.h> #include <signal.h>
#include <stdio.h> #include <stdio.h>
...@@ -57,6 +46,8 @@ Boston, MA 02111-1307, USA. */ ...@@ -57,6 +46,8 @@ Boston, MA 02111-1307, USA. */
#ifdef HAVE_X_WINDOWS #ifdef HAVE_X_WINDOWS
#include <ctype.h> #include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
/* On some systems, the character-composition stuff is broken in X11R5. */ /* On some systems, the character-composition stuff is broken in X11R5. */
...@@ -7599,7 +7590,7 @@ x_build_heuristic_mask (f, file, img, how) ...@@ -7599,7 +7590,7 @@ x_build_heuristic_mask (f, file, img, how)
static int pbm_image_p P_ ((Lisp_Object object)); static int pbm_image_p P_ ((Lisp_Object object));
static int pbm_load P_ ((struct frame *f, struct image *img)); static int pbm_load P_ ((struct frame *f, struct image *img));
static int pbm_scan_number P_ ((FILE *fp)); static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
/* The symbol `pbm' identifying images of this type. */ /* The symbol `pbm' identifying images of this type. */
...@@ -7611,6 +7602,7 @@ enum pbm_keyword_index ...@@ -7611,6 +7602,7 @@ enum pbm_keyword_index
{ {
PBM_TYPE, PBM_TYPE,
PBM_FILE, PBM_FILE,
PBM_DATA,
PBM_ASCENT, PBM_ASCENT,
PBM_MARGIN, PBM_MARGIN,
PBM_RELIEF, PBM_RELIEF,
...@@ -7625,7 +7617,8 @@ enum pbm_keyword_index ...@@ -7625,7 +7617,8 @@ enum pbm_keyword_index
static struct image_keyword pbm_format[PBM_LAST] = static struct image_keyword pbm_format[PBM_LAST] =
{ {
{":type", IMAGE_SYMBOL_VALUE, 1}, {":type", IMAGE_SYMBOL_VALUE, 1},
{":file", IMAGE_STRING_VALUE, 1}, {":file", IMAGE_STRING_VALUE, 0},
{":data", IMAGE_STRING_VALUE, 0},
{":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
{":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
{":relief", IMAGE_INTEGER_VALUE, 0}, {":relief", IMAGE_INTEGER_VALUE, 0},
...@@ -7659,36 +7652,39 @@ pbm_image_p (object) ...@@ -7659,36 +7652,39 @@ pbm_image_p (object)
|| (fmt[PBM_ASCENT].count || (fmt[PBM_ASCENT].count
&& XFASTINT (fmt[PBM_ASCENT].value) > 100)) && XFASTINT (fmt[PBM_ASCENT].value) > 100))
return 0; return 0;
return 1;
/* Must specify either :data or :file. */
return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
} }
/* Scan a decimal number from PBM input file FP and return it. Value /* Scan a decimal number from *S and return it. Advance *S while
is -1 at end of file or if an error occurs. */ reading the number. END is the end of the string. Value is -1 at
end of input. */
static int static int
pbm_scan_number (fp) pbm_scan_number (s, end)
FILE *fp; unsigned char **s, *end;
{ {
int c, val = -1; int c, val = -1;
while (!feof (fp)) while (*s < end)
{ {
/* Skip white-space. */ /* Skip white-space. */
while ((c = fgetc (fp)) != EOF && isspace (c)) while (*s < end && (c = *(*s)++, isspace (c)))
; ;
if (c == '#') if (c == '#')
{ {
/* Skip comment to end of line. */ /* Skip comment to end of line. */
while ((c = fgetc (fp)) != EOF && c != '\n') while (*s < end && (c = *(*s)++, c != '\n'))
; ;
} }
else if (isdigit (c)) else if (isdigit (c))
{ {
/* Read decimal number. */ /* Read decimal number. */
val = c - '0'; val = c - '0';
while ((c = fgetc (fp)) != EOF && isdigit (c)) while (*s < end && (c = *(*s)++, isdigit (c)))
val = 10 * val + c - '0'; val = 10 * val + c - '0';
break; break;
} }
...@@ -7700,6 +7696,42 @@ pbm_scan_number (fp) ...@@ -7700,6 +7696,42 @@ pbm_scan_number (fp)
} }
/* Read FILE into memory. Value is a pointer to a buffer allocated
with xmalloc holding FILE's contents. Value is null if an error
occured. *SIZE is set to the size of the file. */
static char *
pbm_read_file (file, size)
Lisp_Object file;
int *size;
{
FILE *fp = NULL;
char *buf = NULL;
struct stat st;
if (stat (XSTRING (file)->data, &st) == 0
&& (fp = fopen (XSTRING (file)->data, "r")) != NULL
&& (buf = (char *) xmalloc (st.st_size),
fread (buf, 1, st.st_size, fp) == st.st_size))
{
*size = st.st_size;
fclose (fp);
}
else
{
if (fp)
fclose (fp);
if (buf)
{
xfree (buf);
buf = NULL;
}
}
return buf;
}
/* Load PBM image IMG for use on frame F. */ /* Load PBM image IMG for use on frame F. */
static int static int
...@@ -7707,50 +7739,60 @@ pbm_load (f, img) ...@@ -7707,50 +7739,60 @@ pbm_load (f, img)
struct frame *f; struct frame *f;
struct image *img; struct image *img;
{ {
FILE *fp;
char magic[2];
int raw_p, x, y; int raw_p, x, y;
int width, height, max_color_idx = 0; int width, height, max_color_idx = 0;
XImage *ximg; XImage *ximg;
Lisp_Object file, specified_file; Lisp_Object file, specified_file;
enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type; enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
struct gcpro gcpro1; struct gcpro gcpro1;
unsigned char *contents = NULL;
unsigned char *end, *p;
int size;
specified_file = image_spec_value (img->spec, QCfile, NULL); specified_file = image_spec_value (img->spec, QCfile, NULL);
file = x_find_image_file (specified_file); file = Qnil;
GCPRO1 (file); GCPRO1 (file);
if (!STRINGP (file))
{
image_error ("Cannot find image file %s", specified_file, Qnil);
UNGCPRO;
return 0;
}
fp = fopen (XSTRING (file)->data, "r"); if (STRINGP (specified_file))
if (fp == NULL)
{ {
UNGCPRO; file = x_find_image_file (specified_file);
return 0; if (!STRINGP (file))
} {
image_error ("Cannot find image file `%s'", specified_file, Qnil);
UNGCPRO;
return 0;
}
/* Read first two characters. */ contents = pbm_read_file (file, &size);
if (fread (magic, sizeof *magic, 2, fp) != 2) if (contents == NULL)
{
image_error ("Error reading `%s'", file, Qnil);
UNGCPRO;
return 0;
}
p = contents;
end = contents + size;
}
else
{ {
fclose (fp); Lisp_Object data;
image_error ("Not a PBM image file: %s", file, Qnil); data = image_spec_value (img->spec, QCdata, NULL);
UNGCPRO; p = XSTRING (data)->data;
return 0; end = p + STRING_BYTES (XSTRING (data));
} }
if (*magic != 'P') /* Check magic number. */
if (end - p < 2 || *p++ != 'P')
{ {
fclose (fp); image_error ("Not a PBM image: %s", file, Qnil);
image_error ("Not a PBM image file: %s", file, Qnil); error:
xfree (contents);
UNGCPRO; UNGCPRO;
return 0; return 0;
} }
switch (magic[1]) switch (*p++)
{ {
case '1': case '1':
raw_p = 0, type = PBM_MONO; raw_p = 0, type = PBM_MONO;
...@@ -7777,40 +7819,33 @@ pbm_load (f, img) ...@@ -7777,40 +7819,33 @@ pbm_load (f, img)
break; break;
default: default:
fclose (fp); image_error ("Not a PBM image: %s", file, Qnil);
image_error ("Not a PBM image file: %s", file, Qnil); goto error;
UNGCPRO;
return 0;
} }
/* Read width, height, maximum color-component. Characters /* Read width, height, maximum color-component. Characters
starting with `#' up to the end of a line are ignored. */ starting with `#' up to the end of a line are ignored. */
width = pbm_scan_number (fp); width = pbm_scan_number (&p, end);
height = pbm_scan_number (fp); height = pbm_scan_number (&p, end);
if (type != PBM_MONO) if (type != PBM_MONO)
{ {
max_color_idx = pbm_scan_number (fp); max_color_idx = pbm_scan_number (&p, end);
if (raw_p && max_color_idx > 255) if (raw_p && max_color_idx > 255)
max_color_idx = 255; max_color_idx = 255;
} }
if (width < 0 || height < 0 if (width < 0
|| height < 0
|| (type != PBM_MONO && max_color_idx < 0)) || (type != PBM_MONO && max_color_idx < 0))
{ goto error;
fclose (fp);
UNGCPRO;
return 0;
}
BLOCK_INPUT; BLOCK_INPUT;
if (!x_create_x_image_and_pixmap (f, file, width, height, 0, if (!x_create_x_image_and_pixmap (f, file, width, height, 0,
&ximg, &img->pixmap)) &ximg, &img->pixmap))
{ {
fclose (fp);
UNBLOCK_INPUT; UNBLOCK_INPUT;
UNGCPRO; goto error;
return 0;
} }
/* Initialize the color hash table. */ /* Initialize the color hash table. */
...@@ -7826,12 +7861,12 @@ pbm_load (f, img) ...@@ -7826,12 +7861,12 @@ pbm_load (f, img)
if (raw_p) if (raw_p)
{ {
if ((x & 7) == 0) if ((x & 7) == 0)
c = fgetc (fp); c = *p++;
g = c & 0x80; g = c & 0x80;
c <<= 1; c <<= 1;
} }
else else
g = pbm_scan_number (fp); g = pbm_scan_number (&p, end);
XPutPixel (ximg, x, y, (g XPutPixel (ximg, x, y, (g
? FRAME_FOREGROUND_PIXEL (f) ? FRAME_FOREGROUND_PIXEL (f)
...@@ -7846,31 +7881,29 @@ pbm_load (f, img) ...@@ -7846,31 +7881,29 @@ pbm_load (f, img)
int r, g, b; int r, g, b;
if (type == PBM_GRAY) if (type == PBM_GRAY)
r = g = b = raw_p ? fgetc (fp) : pbm_scan_number (fp); r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
else if (raw_p) else if (raw_p)
{ {
r = fgetc (fp); r = *p++;
g = fgetc (fp); g = *p++;
b = fgetc (fp); b = *p++;
} }
else else
{ {
r = pbm_scan_number (fp); r = pbm_scan_number (&p, end);
g = pbm_scan_number (fp); g = pbm_scan_number (&p, end);
b = pbm_scan_number (fp); b = pbm_scan_number (&p, end);
} }
if (r < 0 || g < 0 || b < 0) if (r < 0 || g < 0 || b < 0)
{ {
fclose (fp);
xfree (ximg->data); xfree (ximg->data);
ximg->data = NULL; ximg->data = NULL;
XDestroyImage (ximg); XDestroyImage (ximg);
UNBLOCK_INPUT; UNBLOCK_INPUT;
image_error ("Invalid pixel value in file `%s'", image_error ("Invalid pixel value in file `%s'",
file, Qnil); file, Qnil);
UNGCPRO; goto error;
return 0;
} }
/* RGB values are now in the range 0..max_color_idx. /* RGB values are now in the range 0..max_color_idx.
...@@ -7882,8 +7915,6 @@ pbm_load (f, img) ...@@ -7882,8 +7915,6 @@ pbm_load (f, img)
} }
} }
fclose (fp);
/* Store in IMG->colors the colors allocated for the image, and /* Store in IMG->colors the colors allocated for the image, and
free the color table. */ free the color table. */
img->colors = colors_in_color_table (&img->ncolors); img->colors = colors_in_color_table (&img->ncolors);
...@@ -7898,6 +7929,7 @@ pbm_load (f, img) ...@@ -7898,6 +7929,7 @@ pbm_load (f, img)
img->height = height; img->height = height;
UNGCPRO; UNGCPRO;
xfree (contents);
return 1; return 1;
} }
...@@ -7976,10 +8008,8 @@ png_image_p (object) ...@@ -7976,10 +8008,8 @@ png_image_p (object)
&& XFASTINT (fmt[PNG_ASCENT].value) > 100)) && XFASTINT (fmt[PNG_ASCENT].value) > 100))
return 0; return 0;
/* Must specify either the :data or :file keyword. This should /* Must specify either the :data or :file keyword. */
probably be moved up into parse_image_spec, since it seems to be return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
a general requirement. */
return fmt[PNG_FILE].count || fmt[PNG_DATA].count;
} }
...@@ -8465,10 +8495,8 @@ jpeg_image_p (object) ...@@ -8465,10 +8495,8 @@ jpeg_image_p (object)
&& XFASTINT (fmt[JPEG_ASCENT].value) > 100)) && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
return 0; return 0;
/* Must specify either the :data or :file keyword. This should /* Must specify either the :data or :file keyword. */
probably be moved up into parse_image_spec, since it seems to be return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
a general requirement. */
return fmt[JPEG_FILE].count || fmt[JPEG_DATA].count;
} }
...@@ -8830,10 +8858,8 @@ tiff_image_p (object) ...@@ -8830,10 +8858,8 @@ tiff_image_p (object)
&& XFASTINT (fmt[TIFF_ASCENT].value) > 100)) && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
return 0; return 0;
/* Must specify either the :data or :file keyword. This should /* Must specify either the :data or :file keyword. */
probably be moved up into parse_image_spec, since it seems to be return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
a general requirement. */
return fmt[TIFF_FILE].count || fmt[TIFF_DATA].count;
} }
...@@ -9154,10 +9180,8 @@ gif_image_p (object) ...@@ -9154,10 +9180,8 @@ gif_image_p (object)
&& XFASTINT (fmt[GIF_ASCENT].value) > 100)) && XFASTINT (fmt[GIF_ASCENT].value) > 100))
return 0; return 0;
/* Must specify either the :data or :file keyword. This should /* Must specify either the :data or :file keyword. */
probably be moved up into parse_image_spec, since it seems to be return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
a general requirement. */
return fmt[GIF_FILE].count || fmt[GIF_DATA].count;
} }
/* Reading a GIF image from memory /* Reading a GIF image from memory
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment