mirror of https://github.com/GNOME/gimp.git
applied modified patch from Nils Philippsen that adds more sanity checks
2007-08-30 Raphael Quinet <raphael@gimp.org> * plug-ins/common/pcx.c: applied modified patch from Nils Philippsen that adds more sanity checks when loading and saving images. Fixes the reopened bug #471189. svn path=/trunk/; revision=23409
This commit is contained in:
parent
3736ea8284
commit
e21b1dce84
|
@ -1,3 +1,9 @@
|
|||
2007-08-30 Raphaël Quinet <raphael@gimp.org>
|
||||
|
||||
* plug-ins/common/pcx.c: applied modified patch from Nils
|
||||
Philippsen that adds more sanity checks when loading and saving
|
||||
images. Fixes the reopened bug #471189.
|
||||
|
||||
2007-08-30 Michael Natterer <mitch@gimp.org>
|
||||
|
||||
First version of global menubar support for OSX. Work in progress.
|
||||
|
|
|
@ -51,22 +51,22 @@ static void load_1 (FILE *fp,
|
|||
gint width,
|
||||
gint height,
|
||||
guchar *buffer,
|
||||
gint16 bytes);
|
||||
guint16 bytes);
|
||||
static void load_4 (FILE *fp,
|
||||
gint width,
|
||||
gint height,
|
||||
guchar *buffer,
|
||||
gint16 bytes);
|
||||
guint16 bytes);
|
||||
static void load_8 (FILE *fp,
|
||||
gint width,
|
||||
gint height,
|
||||
guchar *buffer,
|
||||
gint16 bytes);
|
||||
guint16 bytes);
|
||||
static void load_24 (FILE *fp,
|
||||
gint width,
|
||||
gint height,
|
||||
guchar *buffer,
|
||||
gint16 bytes);
|
||||
guint16 bytes);
|
||||
static void readline (FILE *fp,
|
||||
guchar *buffer,
|
||||
gint bytes);
|
||||
|
@ -259,31 +259,84 @@ guchar mono[6]= { 0, 0, 0, 255, 255, 255 };
|
|||
|
||||
static struct
|
||||
{
|
||||
guint8 manufacturer;
|
||||
guint8 version;
|
||||
guint8 compression;
|
||||
guint8 bpp;
|
||||
gint16 x1, y1;
|
||||
gint16 x2, y2;
|
||||
gint16 hdpi;
|
||||
gint16 vdpi;
|
||||
guint8 colormap[48];
|
||||
guint8 reserved;
|
||||
guint8 planes;
|
||||
gint16 bytesperline;
|
||||
gint16 color;
|
||||
guint8 filler[58];
|
||||
guint8 manufacturer;
|
||||
guint8 version;
|
||||
guint8 compression;
|
||||
guint8 bpp;
|
||||
guint16 x1, y1;
|
||||
guint16 x2, y2;
|
||||
guint16 hdpi;
|
||||
guint16 vdpi;
|
||||
guint8 colormap[48];
|
||||
guint8 reserved;
|
||||
guint8 planes;
|
||||
guint16 bytesperline;
|
||||
guint16 color;
|
||||
guint8 filler[58];
|
||||
} pcx_header;
|
||||
|
||||
static struct {
|
||||
size_t size;
|
||||
gpointer address;
|
||||
} pcx_header_buf_xlate[] = {
|
||||
{ 1, &pcx_header.manufacturer },
|
||||
{ 1, &pcx_header.version },
|
||||
{ 1, &pcx_header.compression },
|
||||
{ 1, &pcx_header.bpp },
|
||||
{ 2, &pcx_header.x1 },
|
||||
{ 2, &pcx_header.y1 },
|
||||
{ 2, &pcx_header.x2 },
|
||||
{ 2, &pcx_header.y2 },
|
||||
{ 2, &pcx_header.hdpi },
|
||||
{ 2, &pcx_header.vdpi },
|
||||
{ 48, &pcx_header.colormap },
|
||||
{ 1, &pcx_header.reserved },
|
||||
{ 1, &pcx_header.planes },
|
||||
{ 2, &pcx_header.bytesperline },
|
||||
{ 2, &pcx_header.color },
|
||||
{ 58, &pcx_header.filler },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
pcx_header_from_buffer (const gpointer buf)
|
||||
{
|
||||
gint i;
|
||||
gint buf_offset = 0;
|
||||
|
||||
for (i = 0; pcx_header_buf_xlate[i].size != 0; i++)
|
||||
{
|
||||
g_memmove (pcx_header_buf_xlate[i].address, buf + buf_offset,
|
||||
pcx_header_buf_xlate[i].size);
|
||||
buf_offset += pcx_header_buf_xlate[i].size;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pcx_header_to_buffer (const gpointer buf)
|
||||
{
|
||||
gint i;
|
||||
gint buf_offset = 0;
|
||||
|
||||
for (i = 0; pcx_header_buf_xlate[i].size != 0; i++)
|
||||
{
|
||||
g_memmove (buf + buf_offset, pcx_header_buf_xlate[i].address,
|
||||
pcx_header_buf_xlate[i].size);
|
||||
buf_offset += pcx_header_buf_xlate[i].size;
|
||||
}
|
||||
}
|
||||
|
||||
static gint32
|
||||
load_image (const gchar *filename)
|
||||
{
|
||||
FILE *fd;
|
||||
GimpDrawable *drawable;
|
||||
GimpPixelRgn pixel_rgn;
|
||||
gint16 offset_x, offset_y, height, width;
|
||||
guint16 offset_x, offset_y;
|
||||
gint32 width, height;
|
||||
gint32 image, layer;
|
||||
guchar *dest, cmap[768];
|
||||
guint8 header_buf[128];
|
||||
|
||||
fd = g_fopen (filename, "rb");
|
||||
if (!fd)
|
||||
|
@ -296,13 +349,15 @@ load_image (const gchar *filename)
|
|||
gimp_progress_init_printf (_("Opening '%s'"),
|
||||
gimp_filename_to_utf8 (filename));
|
||||
|
||||
if (fread (&pcx_header, 128, 1, fd) == 0)
|
||||
if (fread (header_buf, 128, 1, fd) == 0)
|
||||
{
|
||||
g_message (_("Could not read header from '%s'"),
|
||||
gimp_filename_to_utf8 (filename));
|
||||
return -1;
|
||||
}
|
||||
|
||||
pcx_header_from_buffer (header_buf);
|
||||
|
||||
if (pcx_header.manufacturer != 10)
|
||||
{
|
||||
g_message (_("'%s' is not a PCX file"),
|
||||
|
@ -310,27 +365,21 @@ load_image (const gchar *filename)
|
|||
return -1;
|
||||
}
|
||||
|
||||
offset_x = GINT16_FROM_LE (pcx_header.x1);
|
||||
offset_y = GINT16_FROM_LE (pcx_header.y1);
|
||||
width = GINT16_FROM_LE (pcx_header.x2) - offset_x + 1;
|
||||
height = GINT16_FROM_LE (pcx_header.y2) - offset_y + 1;
|
||||
offset_x = GUINT16_FROM_LE (pcx_header.x1);
|
||||
offset_y = GUINT16_FROM_LE (pcx_header.y1);
|
||||
width = GUINT16_FROM_LE (pcx_header.x2) - offset_x + 1;
|
||||
height = GUINT16_FROM_LE (pcx_header.y2) - offset_y + 1;
|
||||
|
||||
if (width < 0)
|
||||
if ((width < 0) || (width > GIMP_MAX_IMAGE_SIZE))
|
||||
{
|
||||
g_message (_("Unsupported or invalid image width: %d"), width);
|
||||
return -1;
|
||||
}
|
||||
if (height < 0)
|
||||
if ((height < 0) || (height > GIMP_MAX_IMAGE_SIZE))
|
||||
{
|
||||
g_message (_("Unsupported or invalid image height: %d"), height);
|
||||
return -1;
|
||||
}
|
||||
if (GINT16_FROM_LE (pcx_header.bytesperline) <= 0)
|
||||
{
|
||||
g_message (_("Invalid number of bytes per line: %hd"),
|
||||
GINT16_FROM_LE (pcx_header.bytesperline));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pcx_header.planes == 3 && pcx_header.bpp == 8)
|
||||
{
|
||||
|
@ -352,27 +401,31 @@ load_image (const gchar *filename)
|
|||
if (pcx_header.planes == 1 && pcx_header.bpp == 1)
|
||||
{
|
||||
dest = (guchar *) g_malloc (width * height);
|
||||
load_1 (fd, width, height, dest, GINT16_FROM_LE (pcx_header.bytesperline));
|
||||
load_1 (fd, width, height, dest,
|
||||
GUINT16_FROM_LE (pcx_header.bytesperline));
|
||||
gimp_image_set_colormap (image, mono, 2);
|
||||
}
|
||||
else if (pcx_header.planes == 4 && pcx_header.bpp == 1)
|
||||
{
|
||||
dest = (guchar *) g_malloc (width * height);
|
||||
load_4(fd, width, height, dest, GINT16_FROM_LE (pcx_header.bytesperline));
|
||||
load_4 (fd, width, height, dest,
|
||||
GUINT16_FROM_LE (pcx_header.bytesperline));
|
||||
gimp_image_set_colormap (image, pcx_header.colormap, 16);
|
||||
}
|
||||
else if (pcx_header.planes == 1 && pcx_header.bpp == 8)
|
||||
{
|
||||
dest = (guchar *) g_malloc (width * height);
|
||||
load_8(fd, width, height, dest, GINT16_FROM_LE (pcx_header.bytesperline));
|
||||
fseek(fd, -768L, SEEK_END);
|
||||
fread(cmap, 768, 1, fd);
|
||||
load_8 (fd, width, height, dest,
|
||||
GUINT16_FROM_LE (pcx_header.bytesperline));
|
||||
fseek (fd, -768L, SEEK_END);
|
||||
fread (cmap, 768, 1, fd);
|
||||
gimp_image_set_colormap (image, cmap, 256);
|
||||
}
|
||||
else if (pcx_header.planes == 3 && pcx_header.bpp == 8)
|
||||
{
|
||||
dest = (guchar *) g_malloc (width * height * 3);
|
||||
load_24(fd, width, height, dest, GINT16_FROM_LE (pcx_header.bytesperline));
|
||||
load_24 (fd, width, height, dest,
|
||||
GUINT16_FROM_LE (pcx_header.bytesperline));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -392,14 +445,14 @@ load_image (const gchar *filename)
|
|||
}
|
||||
|
||||
static void
|
||||
load_8 (FILE *fp,
|
||||
gint width,
|
||||
gint height,
|
||||
guchar *buffer,
|
||||
gint16 bytes)
|
||||
load_8 (FILE *fp,
|
||||
gint width,
|
||||
gint height,
|
||||
guchar *buffer,
|
||||
guint16 bytes)
|
||||
{
|
||||
gint row;
|
||||
guchar *line= g_new (guchar, bytes);
|
||||
guchar *line = g_new (guchar, bytes);
|
||||
|
||||
for (row = 0; row < height; buffer += width, ++row)
|
||||
{
|
||||
|
@ -412,14 +465,14 @@ load_8 (FILE *fp,
|
|||
}
|
||||
|
||||
static void
|
||||
load_24 (FILE *fp,
|
||||
gint width,
|
||||
gint height,
|
||||
guchar *buffer,
|
||||
gint16 bytes)
|
||||
load_24 (FILE *fp,
|
||||
gint width,
|
||||
gint height,
|
||||
guchar *buffer,
|
||||
guint16 bytes)
|
||||
{
|
||||
gint x, y, c;
|
||||
guchar *line= g_new (guchar, bytes);
|
||||
guchar *line = g_new (guchar, bytes);
|
||||
|
||||
for (y = 0; y < height; buffer += width * 3, ++y)
|
||||
{
|
||||
|
@ -438,11 +491,11 @@ load_24 (FILE *fp,
|
|||
}
|
||||
|
||||
static void
|
||||
load_1 (FILE *fp,
|
||||
gint width,
|
||||
gint height,
|
||||
guchar *buffer,
|
||||
gint16 bytes)
|
||||
load_1 (FILE *fp,
|
||||
gint width,
|
||||
gint height,
|
||||
guchar *buffer,
|
||||
guint16 bytes)
|
||||
{
|
||||
gint x, y;
|
||||
guchar *line = g_new (guchar, bytes);
|
||||
|
@ -464,18 +517,19 @@ load_1 (FILE *fp,
|
|||
}
|
||||
|
||||
static void
|
||||
load_4 (FILE *fp,
|
||||
gint width,
|
||||
gint height,
|
||||
guchar *buffer,
|
||||
gint16 bytes)
|
||||
load_4 (FILE *fp,
|
||||
gint width,
|
||||
gint height,
|
||||
guchar *buffer,
|
||||
guint16 bytes)
|
||||
{
|
||||
gint x, y, c;
|
||||
guchar *line= g_new (guchar, bytes);
|
||||
guchar *line = g_new (guchar, bytes);
|
||||
|
||||
for (y = 0; y < height; buffer += width, ++y)
|
||||
{
|
||||
for (x = 0; x < width; ++x) buffer[x] = 0;
|
||||
for (x = 0; x < width; ++x)
|
||||
buffer[x] = 0;
|
||||
for (c = 0; c < 4; ++c)
|
||||
{
|
||||
readline(fp, line, bytes);
|
||||
|
@ -536,8 +590,10 @@ save_image (const gchar *filename,
|
|||
GimpImageType drawable_type;
|
||||
guchar *cmap= NULL;
|
||||
guchar *pixels;
|
||||
gint offset_x, offset_y, width, height;
|
||||
gint offset_x, offset_y;
|
||||
guint width, height;
|
||||
gint colors, i;
|
||||
guint8 header_buf[128];
|
||||
|
||||
drawable = gimp_drawable_get (layer);
|
||||
drawable_type = gimp_drawable_type (layer);
|
||||
|
@ -558,23 +614,23 @@ save_image (const gchar *filename,
|
|||
case GIMP_INDEXED_IMAGE:
|
||||
cmap = gimp_image_get_colormap (image, &colors);
|
||||
pcx_header.bpp = 8;
|
||||
pcx_header.bytesperline = GINT16_TO_LE (width);
|
||||
pcx_header.bytesperline = GUINT16_TO_LE (width);
|
||||
pcx_header.planes = 1;
|
||||
pcx_header.color = GINT16_TO_LE (1);
|
||||
pcx_header.color = GUINT16_TO_LE (1);
|
||||
break;
|
||||
|
||||
case GIMP_RGB_IMAGE:
|
||||
pcx_header.bpp = 8;
|
||||
pcx_header.planes = 3;
|
||||
pcx_header.color = GINT16_TO_LE (1);
|
||||
pcx_header.bytesperline = GINT16_TO_LE (width);
|
||||
pcx_header.color = GUINT16_TO_LE (1);
|
||||
pcx_header.bytesperline = GUINT16_TO_LE (width);
|
||||
break;
|
||||
|
||||
case GIMP_GRAY_IMAGE:
|
||||
pcx_header.bpp = 8;
|
||||
pcx_header.planes = 1;
|
||||
pcx_header.color = GINT16_TO_LE (2);
|
||||
pcx_header.bytesperline = GINT16_TO_LE (width);
|
||||
pcx_header.color = GUINT16_TO_LE (2);
|
||||
pcx_header.bytesperline = GUINT16_TO_LE (width);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -592,16 +648,44 @@ save_image (const gchar *filename,
|
|||
pixels = (guchar *) g_malloc (width * height * pcx_header.planes);
|
||||
gimp_pixel_rgn_get_rect (&pixel_rgn, pixels, 0, 0, width, height);
|
||||
|
||||
pcx_header.x1 = GINT16_TO_LE (offset_x);
|
||||
pcx_header.y1 = GINT16_TO_LE (offset_y);
|
||||
pcx_header.x2 = GINT16_TO_LE (offset_x + width - 1);
|
||||
pcx_header.y2 = GINT16_TO_LE (offset_y + height - 1);
|
||||
if ((offset_x < 0) || (offset_x > (1<<16)))
|
||||
{
|
||||
g_message (_("Invalid X offset: %d"), offset_x);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pcx_header.hdpi = GINT16_TO_LE (300);
|
||||
pcx_header.vdpi = GINT16_TO_LE (300);
|
||||
if ((offset_y < 0) || (offset_y > (1<<16)))
|
||||
{
|
||||
g_message (_("Invalid Y offset: %d"), offset_y);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (offset_x + width - 1 > (1<<16))
|
||||
{
|
||||
g_message (_("Right border out of bounds (must be < %d): %d"), (1<<16),
|
||||
offset_x + width - 1);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (offset_y + height - 1 > (1<<16))
|
||||
{
|
||||
g_message (_("Bottom border out of bounds (must be < %d): %d"), (1<<16),
|
||||
offset_y + height - 1);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pcx_header.x1 = GUINT16_TO_LE ((guint16)offset_x);
|
||||
pcx_header.y1 = GUINT16_TO_LE ((guint16)offset_y);
|
||||
pcx_header.x2 = GUINT16_TO_LE ((guint16)(offset_x + width - 1));
|
||||
pcx_header.y2 = GUINT16_TO_LE ((guint16)(offset_y + height - 1));
|
||||
|
||||
pcx_header.hdpi = GUINT16_TO_LE (300);
|
||||
pcx_header.vdpi = GUINT16_TO_LE (300);
|
||||
pcx_header.reserved = 0;
|
||||
|
||||
fwrite (&pcx_header, 128, 1, fp);
|
||||
pcx_header_to_buffer (header_buf);
|
||||
|
||||
fwrite (header_buf, 128, 1, fp);
|
||||
|
||||
switch (drawable_type)
|
||||
{
|
||||
|
@ -611,7 +695,9 @@ save_image (const gchar *filename,
|
|||
fwrite (cmap, colors, 3, fp);
|
||||
for (i = colors; i < 256; i++)
|
||||
{
|
||||
fputc (0, fp); fputc (0, fp); fputc (0, fp);
|
||||
fputc (0, fp);
|
||||
fputc (0, fp);
|
||||
fputc (0, fp);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -624,7 +710,9 @@ save_image (const gchar *filename,
|
|||
fputc (0x0c, fp);
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
fputc ((guchar) i, fp); fputc ((guchar) i, fp); fputc ((guchar) i, fp);
|
||||
fputc ((guchar) i, fp);
|
||||
fputc ((guchar) i, fp);
|
||||
fputc ((guchar) i, fp);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -635,7 +723,12 @@ save_image (const gchar *filename,
|
|||
gimp_drawable_detach (drawable);
|
||||
g_free (pixels);
|
||||
|
||||
fclose (fp);
|
||||
if (fclose (fp) != 0)
|
||||
{
|
||||
g_message (_("Writing to file '%s' failed: %s"),
|
||||
gimp_filename_to_utf8 (filename), g_strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -661,8 +754,9 @@ save_24 (FILE *fp,
|
|||
gint height,
|
||||
guchar *buffer)
|
||||
{
|
||||
int x, y, c;
|
||||
int x, y, c;
|
||||
guchar *line;
|
||||
|
||||
line = (guchar *) g_malloc (width);
|
||||
|
||||
for (y = 0; y < height; ++y)
|
||||
|
@ -676,7 +770,7 @@ save_24 (FILE *fp,
|
|||
writeline (fp, line, width);
|
||||
}
|
||||
buffer += width * 3;
|
||||
gimp_progress_update ((double) y / (double) height);
|
||||
gimp_progress_update ((double) y / (double) height);
|
||||
}
|
||||
g_free (line);
|
||||
}
|
||||
|
@ -686,8 +780,8 @@ writeline (FILE *fp,
|
|||
guchar *buffer,
|
||||
gint bytes)
|
||||
{
|
||||
guchar value, count;
|
||||
guchar *finish = buffer+ bytes;
|
||||
guchar value, count;
|
||||
guchar *finish = buffer + bytes;
|
||||
|
||||
while (buffer < finish)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue