[gimp/wip/wormnest/psp-mask: 1/4] plug-ins: refactor file-psp read_channel_data to separate the decompression functions.
- From: Jacob Boerema <jboerema src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/wip/wormnest/psp-mask: 1/4] plug-ins: refactor file-psp read_channel_data to separate the decompression functions.
- Date: Tue, 6 Oct 2020 19:54:26 +0000 (UTC)
commit f21af0d6c5968d2a470752a0f36702bfd32b84e4
Author: Jacob Boerema <jgboerema gmail com>
Date: Tue Sep 29 18:22:57 2020 -0400
plug-ins: refactor file-psp read_channel_data to separate the decompression functions.
Having the decompression routines in their own function will make it easier to
adapt read_channel_data to also handle mask channels.
Also added failure checks to all fread calls that didn't have them yet.
plug-ins/common/file-psp.c | 428 +++++++++++++++++++++++++++------------------
1 file changed, 262 insertions(+), 166 deletions(-)
---
diff --git a/plug-ins/common/file-psp.c b/plug-ins/common/file-psp.c
index 9678e10674..47212145da 100644
--- a/plug-ins/common/file-psp.c
+++ b/plug-ins/common/file-psp.c
@@ -1557,220 +1557,316 @@ upscale_indexed_sub_8 (FILE *f,
}
static int
-read_channel_data (FILE *f,
- PSPimage *ia,
- guchar **pixels,
- guint bytespp,
- guint offset,
- GeglBuffer *buffer,
- guint32 compressed_len,
- GError **error)
+read_uncompressed_channel (FILE *f,
+ guchar **pixels,
+ gint line_width, /* width in bytes of one scanline */
+ gint height,
+ guint bytespp, /* bytes per pixel */
+ guint bytesps, /* bytes per sample */
+ guint offset,
+ GError **error)
{
- gint i, y, line_width;
- gint width = gegl_buffer_get_width (buffer);
- gint height = gegl_buffer_get_height (buffer);
- gint npixels = width * height;
guchar *buf;
- guchar *buf2 = NULL; /* please the compiler */
- guchar runcount, byte;
- z_stream zstream;
-
- g_assert (ia->bytes_per_sample <= 2);
+ gint y, i;
- if (ia->depth < 8)
+ if (bytespp == 1)
{
- /* Scanlines for 1 and 4 bit only end on a 4-byte boundary. */
- line_width = (((width * ia->depth + 7) / 8) + ia->depth - 1) / 4 * 4;
+ if (fread (pixels[0], height * line_width, 1, f) < 1)
+ {
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+ _("Error reading channel"));
+ return -1;
+ }
}
else
{
- line_width = width * ia->bytes_per_sample;
- }
-
- switch (ia->compression)
- {
- case PSP_COMP_NONE:
- if (bytespp == 1)
+ buf = g_malloc (line_width);
+ if (bytesps == 1)
{
- fread (pixels[0], height * line_width, 1, f);
- }
- else
- {
- buf = g_malloc (line_width);
- if (ia->bytes_per_sample == 1)
+ for (y = 0; y < height; y++)
{
- for (y = 0; y < height; y++)
+ guchar *p, *q;
+
+ if (fread (buf, line_width, 1, f) < 1)
{
- guchar *p, *q;
-
- fread (buf, width, 1, f);
- /* Contrary to what the PSP specification seems to suggest
- scanlines are not stored on a 4-byte boundary. */
- p = buf;
- q = pixels[y] + offset;
- for (i = 0; i < width; i++)
- {
- *q = *p++;
- q += bytespp;
- }
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+ _("Error reading channel"));
+ return -1;
+ }
+ /* Contrary to what the PSP specification seems to suggest
+ scanlines are not stored on a 4-byte boundary. */
+ p = buf;
+ q = pixels[y] + offset;
+ for (i = 0; i < line_width; i++)
+ {
+ *q = *p++;
+ q += bytespp;
}
}
- else if (ia->bytes_per_sample == 2)
+ }
+ else if (bytesps == 2)
+ {
+ for (y = 0; y < height; y++)
{
- for (y = 0; y < height; y++)
+ guint16 *p, *q;
+ gint width = line_width / 2;
+
+ if (fread (buf, line_width, 1, f) < 1)
{
- guint16 *p, *q;
-
- fread (buf, width * ia->bytes_per_sample, 1, f);
- /* Contrary to what the PSP specification seems to suggest
- scanlines are not stored on a 4-byte boundary. */
- p = (guint16 *) buf;
- q = (guint16 *) (pixels[y] + offset);
- for (i = 0; i < width; i++)
- {
- *q = GUINT16_FROM_LE (*p++);
- q += bytespp / 2;
- }
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+ _("Error reading channel"));
+ return -1;
+ }
+ /* Contrary to what the PSP specification seems to suggest
+ scanlines are not stored on a 4-byte boundary. */
+ p = (guint16 *) buf;
+ q = (guint16 *) (pixels[y] + offset);
+ for (i = 0; i < width; i++)
+ {
+ *q = GUINT16_FROM_LE (*p++);
+ q += bytespp / 2;
}
}
-
- g_free (buf);
}
- break;
- case PSP_COMP_RLE:
- {
- guchar *q, *endq;
+ g_free (buf);
+ }
+ return 0;
+}
- q = pixels[0] + offset;
- if (ia->depth >= 8)
- endq = q + npixels * bytespp;
- else
- endq = q + line_width * height;
+static int
+read_rle_channel (FILE *f,
+ guchar **pixels,
+ gint line_width, /* width in bytes of one scanline */
+ gint height,
+ guint bytespp, /* bytes per pixel */
+ guint bytesps, /* bytes per sample */
+ guint offset,
+ GError **error)
+{
+ gint i;
+ guchar *q, *endq;
+ guchar *buf;
+ guchar runcount, byte;
- buf = g_malloc (127);
- while (q < endq)
- {
- fread (&runcount, 1, 1, f);
- if (runcount > 128)
- {
- runcount -= 128;
- fread (&byte, 1, 1, f);
- memset (buf, byte, runcount);
- }
- else
- fread (buf, runcount, 1, f);
-
- /* prevent buffer overflow for bogus data */
- if (runcount > (endq - q) / bytespp + ia->bytes_per_sample - 1)
- {
- g_printerr ("Buffer overflow decompressing RLE data.\n");
- break;
- }
-
- if (bytespp == 1)
- {
- memmove (q, buf, runcount);
- q += runcount;
- }
- else if (ia->bytes_per_sample == 1)
- {
- guchar *p = buf;
-
- for (i = 0; i < runcount; i++)
- {
- *q = *p++;
- q += bytespp;
- }
- }
- else if (ia->bytes_per_sample == 2)
- {
- guint16 *p = (guint16 *) buf;
- guint16 *r = (guint16 *) q;
-
- for (i = 0; i < runcount / 2; i++)
- {
- *r = GUINT16_FROM_LE (*p++);
- r += bytespp / 2;
- }
- q = (guchar *) r;
- }
- }
- g_free (buf);
- }
- break;
+ q = pixels[0] + offset;
+ endq = q + line_width / bytesps * height * bytespp;
- case PSP_COMP_LZ77:
- buf = g_malloc (compressed_len);
- fread (buf, compressed_len, 1, f);
- zstream.next_in = buf;
- zstream.avail_in = compressed_len;
- zstream.zalloc = psp_zalloc;
- zstream.zfree = psp_zfree;
- zstream.opaque = f;
- if (inflateInit (&zstream) != Z_OK)
+ buf = g_malloc (127);
+ while (q < endq)
+ {
+ if (fread (&runcount, 1, 1, f) < 1)
{
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
- _("zlib error"));
+ _("Error reading channel"));
return -1;
}
- if (bytespp == 1)
- zstream.next_out = pixels[0];
- else
+ if (runcount > 128)
{
- buf2 = g_malloc (npixels * ia->bytes_per_sample);
- zstream.next_out = buf2;
+ runcount -= 128;
+ if (fread (&byte, 1, 1, f) < 1)
+ {
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+ _("Error reading channel"));
+ return -1;
+ }
+ memset (buf, byte, runcount);
}
- zstream.avail_out = npixels * ia->bytes_per_sample;
- if (inflate (&zstream, Z_FINISH) != Z_STREAM_END)
+ else if (fread (buf, runcount, 1, f) < 1)
{
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
- _("zlib error"));
- inflateEnd (&zstream);
+ _("Error reading channel"));
return -1;
}
- inflateEnd (&zstream);
- g_free (buf);
- if (bytespp > 1)
+ /* prevent buffer overflow for bogus data */
+ if (runcount > (endq - q) / bytespp + bytesps)
+ {
+ g_printerr ("Buffer overflow decompressing RLE data.\n");
+ break;
+ }
+
+ if (bytespp == 1)
+ {
+ memmove (q, buf, runcount);
+ q += runcount;
+ }
+ else if (bytesps == 1)
{
- if (ia->bytes_per_sample == 1)
+ guchar *p = buf;
+
+ for (i = 0; i < runcount; i++)
{
- guchar *p, *q;
+ *q = *p++;
+ q += bytespp;
+ }
+ }
+ else if (bytesps == 2)
+ {
+ guint16 *p = (guint16 *) buf;
+ guint16 *r = (guint16 *) q;
- p = buf2;
- q = pixels[0] + offset;
- for (i = 0; i < npixels; i++)
- {
- *q = *p++;
- q += bytespp;
- }
- g_free (buf2);
+ for (i = 0; i < runcount / 2; i++)
+ {
+ *r = GUINT16_FROM_LE (*p++);
+ r += bytespp / 2;
}
- else if (ia->bytes_per_sample == 2)
+ q = (guchar *) r;
+ }
+ }
+ g_free (buf);
+ return 0;
+}
+
+static int
+read_lz77_channel (FILE *f,
+ guchar **pixels,
+ gint line_width, /* width in bytes of one scanline */
+ gint height,
+ guint bytespp, /* bytes per pixel */
+ guint bytesps, /* bytes per sample */
+ guint offset,
+ guint32 compressed_len, /* length of compressed data */
+ GError **error)
+{
+ guint32 npixels, nbytes;
+ gint i;
+ guchar *buf, *buf2;
+ z_stream zstream;
+
+ nbytes = line_width * height;
+ npixels = nbytes / bytesps;
+
+ buf = g_malloc (compressed_len);
+ if (fread (buf, compressed_len, 1, f) < 1)
+ {
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+ _("Error reading channel"));
+ return -1;
+ }
+ zstream.next_in = buf;
+ zstream.avail_in = compressed_len;
+ zstream.zalloc = psp_zalloc;
+ zstream.zfree = psp_zfree;
+ zstream.opaque = f;
+ if (inflateInit (&zstream) != Z_OK)
+ {
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+ _("zlib error"));
+ return -1;
+ }
+ if (bytespp == 1)
+ zstream.next_out = pixels[0];
+ else
+ {
+ buf2 = g_malloc (nbytes);
+ zstream.next_out = buf2;
+ }
+ zstream.avail_out = nbytes;
+ if (inflate (&zstream, Z_FINISH) != Z_STREAM_END)
+ {
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+ _("zlib error"));
+ inflateEnd (&zstream);
+ return -1;
+ }
+ inflateEnd (&zstream);
+ g_free (buf);
+
+ if (bytespp > 1)
+ {
+ if (bytesps == 1)
+ {
+ guchar *p, *q;
+
+ p = buf2;
+ q = pixels[0] + offset;
+ for (i = 0; i < npixels; i++)
{
- guint16 *p, *q;
+ *q = *p++;
+ q += bytespp;
+ }
+ g_free (buf2);
+ }
+ else if (bytesps == 2)
+ {
+ guint16 *p, *q;
- p = (guint16 *) buf2;
- q = (guint16 *) (pixels[0] + offset);
- for (i = 0; i < npixels; i++)
- {
- *q = GUINT16_FROM_LE (*p++);
- q += bytespp / 2;
- }
- g_free (buf2);
+ p = (guint16 *) buf2;
+ q = (guint16 *) (pixels[0] + offset);
+ for (i = 0; i < npixels; i++)
+ {
+ *q = GUINT16_FROM_LE (*p++);
+ q += bytespp / 2;
}
+ g_free (buf2);
}
+ }
+ return 0;
+}
+
+static int
+read_channel_data (FILE *f,
+ PSPimage *ia,
+ guchar **pixels,
+ guint bytespp,
+ guint offset,
+ GeglBuffer *buffer,
+ guint32 compressed_len,
+ GError **error)
+{
+ /* width, height below are the layer/channel dimensions,
+ not necessarily the same as the image dimensions. */
+ gint width = gegl_buffer_get_width (buffer);
+ gint height = gegl_buffer_get_height (buffer);
+ gint decompress_result = 0;
+ gint line_width;
+
+ g_assert (ia->bytes_per_sample <= 2);
+
+ if (ia->depth < 8)
+ {
+ /* Note that bytespp is assumed to be set to 1 for depth < 8. */
+ /* Scanlines for 1 and 4 bit only end on a 4-byte boundary. */
+ line_width = (((width * ia->depth + 7) / 8) + ia->depth - 1) / 4 * 4;
+ }
+ else
+ {
+ line_width = width * ia->bytes_per_sample;
+ }
+
+ switch (ia->compression)
+ {
+ case PSP_COMP_NONE:
+ decompress_result = read_uncompressed_channel (f, pixels, line_width, height,
+ bytespp, ia->bytes_per_sample,
+ offset, error);
+ break;
+
+ case PSP_COMP_RLE:
+ decompress_result = read_rle_channel (f, pixels, line_width, height,
+ bytespp, ia->bytes_per_sample,
+ offset, error);
+ break;
+
+ case PSP_COMP_LZ77:
+ decompress_result = read_lz77_channel (f, pixels, line_width, height,
+ bytespp, ia->bytes_per_sample,
+ offset, compressed_len, error);
+ break;
+
+ default:
+ decompress_result = -1;
break;
}
- if (ia->base_type == GIMP_INDEXED && ia->depth < 8)
+ if (decompress_result == 0 && ia->base_type == GIMP_INDEXED && ia->depth < 8)
{
/* We need to convert 1 and 4 bit to 8 bit indexed */
upscale_indexed_sub_8 (f, width, height, ia->depth, pixels[0]);
}
- return 0;
+ return decompress_result;
}
static gboolean
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]