plug-ins: improve error handling of FLI export

Added GError parameters to all static file write functions, check for
failed writing and return an error if that is the case.

Additionally, at end of file make sure the last dummy byte is written to
make chunks an even size.
This commit is contained in:
Jacob Boerema 2022-05-16 11:20:52 -04:00
parent fccc13b782
commit ca8eee1755
2 changed files with 261 additions and 85 deletions

View File

@ -836,6 +836,8 @@ save_image (GFile *file,
buffer = gimp_drawable_get_buffer (drawable);
g_debug ("Writing frame: %d", cnt);
if (gimp_drawable_is_gray (drawable))
{
if (gimp_drawable_has_alpha (drawable))

View File

@ -80,27 +80,43 @@ fli_read_uint32 (FILE *f, guint32 *value, GError **error)
return TRUE;
}
static void
fli_write_char (FILE *f,
guchar b)
static gboolean
fli_write_char (FILE *f,
guchar b,
GError **error)
{
fwrite (&b, 1, 1, f);
if (fwrite (&b, 1, 1, f) != 1)
{
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
_("Error writing to file."));
return FALSE;
}
return TRUE;
}
static void
fli_write_short (FILE *f,
gushort w)
static gboolean
fli_write_short (FILE *f,
gushort w,
GError **error)
{
guchar b[2];
b[0] = w & 255;
b[1] = (w >> 8) & 255;
fwrite (&b, 1, 2, f);
if (fwrite (&b, 1, 2, f) != 2)
{
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
_("Error writing to file."));
return FALSE;
}
return TRUE;
}
static void
fli_write_uint32 (FILE *f,
guint32 l)
static gboolean
fli_write_uint32 (FILE *f,
guint32 l,
GError **error)
{
guchar b[4];
@ -109,7 +125,13 @@ fli_write_uint32 (FILE *f,
b[2] = (l >> 16) & 255;
b[3] = (l >> 24) & 255;
fwrite (&b, 1, 4, f);
if (fwrite (&b, 1, 4, f) != 4)
{
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
_("Error writing to file."));
return FALSE;
}
return TRUE;
}
gboolean
@ -209,27 +231,45 @@ fli_write_header (FILE *f,
{
fli_header->filesize = ftell (f);
fseek (f, 0, SEEK_SET);
fli_write_uint32 (f, fli_header->filesize); /* 0 */
fli_write_short (f, fli_header->magic); /* 4 */
fli_write_short (f, fli_header->frames); /* 6 */
fli_write_short (f, fli_header->width); /* 8 */
fli_write_short (f, fli_header->height); /* 10 */
fli_write_short (f, fli_header->depth); /* 12 */
fli_write_short (f, fli_header->flags); /* 14 */
if (! fli_write_uint32 (f, fli_header->filesize, error) || /* 0 */
! fli_write_short (f, fli_header->magic, error) || /* 4 */
! fli_write_short (f, fli_header->frames, error) || /* 6 */
! fli_write_short (f, fli_header->width, error) || /* 8 */
! fli_write_short (f, fli_header->height, error) || /* 10 */
! fli_write_short (f, fli_header->depth, error) || /* 12 */
! fli_write_short (f, fli_header->flags, error)) /* 14 */
{
g_prefix_error (error, _("Error writing header. "));
return FALSE;
}
if (fli_header->magic == HEADER_FLI)
{
/* FLI saves speed in 1/70s */
fli_write_short (f, fli_header->speed / 14); /* 16 */
if (! fli_write_short (f, (fli_header->speed + 7) / 14, error)) /* 16 */
{
g_prefix_error (error, _("Error writing header. "));
return FALSE;
}
}
else
{
if (fli_header->magic == HEADER_FLC)
{
/* FLC saves speed in 1/1000s */
fli_write_uint32 (f, fli_header->speed); /* 16 */
if (! fli_write_uint32 (f, fli_header->speed, error)) /* 16 */
{
g_prefix_error (error, _("Error writing header. "));
return FALSE;
}
fseek (f, 80, SEEK_SET);
fli_write_uint32 (f, fli_header->oframe1); /* 80 */
fli_write_uint32 (f, fli_header->oframe2); /* 84 */
if (! fli_write_uint32 (f, fli_header->oframe1, error) || /* 80 */
! fli_write_uint32 (f, fli_header->oframe2, error)) /* 84 */
{
g_prefix_error (error, _("Error writing header. "));
return FALSE;
}
}
else
{
@ -459,9 +499,13 @@ fli_write_frame (FILE *f,
frameend = ftell (f);
fli_frame.size = frameend - framepos;
fseek (f, framepos, SEEK_SET);
fli_write_uint32 (f, fli_frame.size);
fli_write_short (f, fli_frame.magic);
fli_write_short (f, fli_frame.chunks);
if (! fli_write_uint32 (f, fli_frame.size, error) ||
! fli_write_short (f, fli_frame.magic, error) ||
! fli_write_short (f, fli_frame.chunks, error))
{
g_prefix_error (error, _("Error writing frame header. "));
return FALSE;
}
fseek (f, frameend, SEEK_SET);
fli_header->frames++;
@ -554,11 +598,20 @@ fli_write_color (FILE *f,
gushort col_pos;
num_packets = 1;
fli_write_char (f, 0); /* skip no color */
fli_write_char (f, 0); /* 256 color */
if (! fli_write_char (f, 0, error) || /* skip no color */
! fli_write_char (f, 0, error)) /* 256 color */
{
g_prefix_error (error, _("Error writing color map. "));
return FALSE;
}
for (col_pos = 0; col_pos < 768; col_pos++)
{
fli_write_char (f, cmap[col_pos] >> 2);
if (! fli_write_char (f, cmap[col_pos] >> 2, error))
{
g_prefix_error (error, _("Error writing color map. "));
return FALSE;
}
}
}
else
@ -591,13 +644,21 @@ fli_write_color (FILE *f,
{
num_packets++;
fli_write_char (f, cnt_skip & 255);
fli_write_char (f, cnt_col & 255);
if (! fli_write_char (f, cnt_skip & 255, error) ||
! fli_write_char (f, cnt_col & 255, error))
{
g_prefix_error (error, _("Error writing color map. "));
return FALSE;
}
while (cnt_col > 0)
{
fli_write_char (f, cmap[col_start++] >> 2);
fli_write_char (f, cmap[col_start++] >> 2);
fli_write_char (f, cmap[col_start++] >> 2);
if (! fli_write_char (f, cmap[col_start++] >> 2, error) ||
! fli_write_char (f, cmap[col_start++] >> 2, error) ||
! fli_write_char (f, cmap[col_start++] >> 2, error))
{
g_prefix_error (error, _("Error writing color map. "));
return FALSE;
}
cnt_col--;
}
}
@ -610,9 +671,13 @@ fli_write_color (FILE *f,
chunk.magic = FLI_COLOR;
fseek (f, chunkpos, SEEK_SET);
fli_write_uint32 (f, chunk.size);
fli_write_short (f, chunk.magic);
fli_write_short (f, num_packets);
if (! fli_write_uint32 (f, chunk.size, error) ||
! fli_write_short (f, chunk.magic, error) ||
! fli_write_short (f, num_packets, error))
{
g_prefix_error (error, _("Error writing color map. "));
return FALSE;
}
if (chunk.size & 1)
chunk.size++;
@ -711,11 +776,20 @@ fli_write_color_2 (FILE *f,
gushort col_pos;
num_packets = 1;
fli_write_char (f, 0); /* skip no color */
fli_write_char (f, 0); /* 256 color */
if (! fli_write_char (f, 0, error) || /* skip no color */
! fli_write_char (f, 0, error)) /* 256 color */
{
g_prefix_error (error, _("Error writing color map. "));
return FALSE;
}
for (col_pos = 0; col_pos < 768; col_pos++)
{
fli_write_char (f, cmap[col_pos]);
if (! fli_write_char (f, cmap[col_pos], error))
{
g_prefix_error (error, _("Error writing color map. "));
return FALSE;
}
}
}
else
@ -745,14 +819,23 @@ fli_write_color_2 (FILE *f,
if (cnt_col > 0)
{
num_packets++;
fli_write_char (f, cnt_skip);
fli_write_char (f, cnt_col);
if (! fli_write_char (f, cnt_skip, error) ||
! fli_write_char (f, cnt_col, error))
{
g_prefix_error (error, _("Error writing color map. "));
return FALSE;
}
while (cnt_col > 0)
{
fli_write_char (f, cmap[col_start++]);
fli_write_char (f, cmap[col_start++]);
fli_write_char (f, cmap[col_start++]);
if (! fli_write_char (f, cmap[col_start++], error) ||
! fli_write_char (f, cmap[col_start++], error) ||
! fli_write_char (f, cmap[col_start++], error))
{
g_prefix_error (error, _("Error writing color map. "));
return FALSE;
}
cnt_col--;
}
}
@ -765,9 +848,13 @@ fli_write_color_2 (FILE *f,
chunk.magic = FLI_COLOR_2;
fseek (f, chunkpos, SEEK_SET);
fli_write_uint32 (f, chunk.size);
fli_write_short (f, chunk.magic);
fli_write_short (f, num_packets);
if (! fli_write_uint32 (f, chunk.size, error) ||
! fli_write_short (f, chunk.magic, error) ||
! fli_write_short (f, num_packets, error))
{
g_prefix_error (error, _("Error writing color map. "));
return FALSE;
}
if (chunk.size & 1)
chunk.size++;
@ -805,8 +892,12 @@ fli_write_black (FILE *f,
chunk.size = 6;
chunk.magic = FLI_BLACK;
fli_write_uint32 (f, chunk.size);
fli_write_short (f, chunk.magic);
if (! fli_write_uint32 (f, chunk.size, error) ||
! fli_write_short (f, chunk.magic, error))
{
g_prefix_error (error, _("Error writing black. "));
return FALSE;
}
return TRUE;
}
@ -841,16 +932,33 @@ fli_write_copy (FILE *f,
chunkpos = ftell (f);
fseek (f, chunkpos + 6, SEEK_SET);
fwrite (framebuf, fli_header->width, fli_header->height, f);
if (fwrite (framebuf, fli_header->width, fli_header->height, f) != fli_header->height)
{
g_prefix_error (error, _("Error writing frame. "));
return FALSE;
}
chunk.size = ftell (f) - chunkpos;
chunk.magic = FLI_COPY;
fseek (f, chunkpos, SEEK_SET);
fli_write_uint32 (f, chunk.size);
fli_write_short (f, chunk.magic);
if (chunk.size & 1)
chunk.size++;
{
/* Dummy char to make the chunk end on an even boundary. */
if (! fli_write_char (f, 0, error))
{
g_prefix_error (error, _("Error writing frame. "));
return FALSE;
}
chunk.size++;
}
fseek (f, chunkpos, SEEK_SET);
if (! fli_write_uint32 (f, chunk.size, error) ||
! fli_write_short (f, chunk.magic, error))
{
g_prefix_error (error, _("Error writing frame. "));
return FALSE;
}
fseek (f, chunkpos + chunk.size, SEEK_SET);
return TRUE;
}
@ -964,13 +1072,21 @@ fli_write_brun (FILE *f,
if (tc > 0)
{
bc++;
fli_write_char (f, (tc - 1)^0xFF);
fwrite (linebuf + t1, 1, tc, f);
if (! fli_write_char (f, (tc - 1)^0xFF, error) ||
fwrite (linebuf + t1, 1, tc, f) != tc)
{
g_prefix_error (error, _("Error writing frame. "));
return FALSE;
}
tc = 0;
}
bc++;
fli_write_char (f, pc);
fli_write_char (f, linebuf[xc]);
if (! fli_write_char (f, pc, error) ||
! fli_write_char (f, linebuf[xc], error))
{
g_prefix_error (error, _("Error writing frame. "));
return FALSE;
}
t1 = xc + pc;
}
else
@ -979,8 +1095,12 @@ fli_write_brun (FILE *f,
if (tc > 120)
{
bc++;
fli_write_char (f, (tc - 1)^0xFF);
fwrite (linebuf + t1, 1, tc, f);
if (! fli_write_char (f, (tc - 1)^0xFF, error) ||
fwrite (linebuf + t1, 1, tc, f) != tc)
{
g_prefix_error (error, _("Error writing frame. "));
return FALSE;
}
tc = 0;
t1 = xc + pc;
}
@ -990,25 +1110,46 @@ fli_write_brun (FILE *f,
if (tc > 0)
{
bc++;
fli_write_char (f, (tc - 1)^0xFF);
fwrite (linebuf + t1, 1, tc, f);
if (! fli_write_char (f, (tc - 1)^0xFF, error) ||
fwrite (linebuf + t1, 1, tc, f) != tc)
{
g_prefix_error (error, _("Error writing frame. "));
return FALSE;
}
tc = 0;
}
lineend = ftell (f);
fseek (f, linepos, SEEK_SET);
fli_write_char (f, bc);
if (! fli_write_char (f, bc, error))
{
g_prefix_error (error, _("Error writing frame. "));
return FALSE;
}
fseek (f, lineend, SEEK_SET);
}
chunk.size = ftell (f) - chunkpos;
chunk.magic = FLI_BRUN;
fseek (f, chunkpos, SEEK_SET);
fli_write_uint32 (f, chunk.size);
fli_write_short (f, chunk.magic);
if (chunk.size & 1)
chunk.size++;
{
/* Dummy char to make the chunk end on an even boundary. */
if (! fli_write_char (f, 0, error))
{
g_prefix_error (error, _("Error writing frame. "));
return FALSE;
}
chunk.size++;
}
fseek (f, chunkpos, SEEK_SET);
if (! fli_write_uint32 (f, chunk.size, error) ||
! fli_write_short (f, chunk.magic, error))
{
g_prefix_error (error, _("Error writing frame. "));
return FALSE;
}
fseek (f, chunkpos + chunk.size, SEEK_SET);
return TRUE;
}
@ -1146,8 +1287,12 @@ fli_write_lc (FILE *f,
if (numline == 0)
firstline = 0;
fli_write_short (f, firstline);
fli_write_short (f, numline);
if (! fli_write_short (f, firstline, error) ||
! fli_write_short (f, numline, error))
{
g_prefix_error (error, _("Error writing frame. "));
return FALSE;
}
for (yc = 0; yc < numline; yc++)
{
@ -1170,7 +1315,11 @@ fli_write_lc (FILE *f,
xc++;
sc++;
}
fli_write_char (f, sc);
if (! fli_write_char (f, sc, error))
{
g_prefix_error (error, _("Error writing frame. "));
return FALSE;
}
cc = 1;
while ((linebuf[xc] == linebuf[xc + cc]) &&
((xc + cc)<fli_header->width) &&
@ -1181,9 +1330,13 @@ fli_write_lc (FILE *f,
if (cc > 2)
{
bc++;
fli_write_char (f, (cc - 1)^0xFF);
fli_write_char (f, linebuf[xc]);
xc+=cc;
if (! fli_write_char (f, (cc - 1)^0xFF, error) ||
! fli_write_char (f, linebuf[xc], error))
{
g_prefix_error (error, _("Error writing frame. "));
return FALSE;
}
xc += cc;
}
else
{
@ -1209,26 +1362,47 @@ fli_write_lc (FILE *f,
(sc < 4) &&
((xc + tc) < fli_header->width));
bc++;
fli_write_char (f, tc);
fwrite (linebuf + xc, tc, 1, f);
xc+=tc;
if (! fli_write_char (f, tc, error) ||
fwrite (linebuf + xc, tc, 1, f) != 1)
{
g_prefix_error (error, _("Error writing frame. "));
return FALSE;
}
xc += tc;
}
}
lineend = ftell (f);
fseek (f, linepos, SEEK_SET);
fli_write_char (f, bc);
if (! fli_write_char (f, bc, error))
{
g_prefix_error (error, _("Error writing frame. "));
return FALSE;
}
fseek (f, lineend, SEEK_SET);
}
chunk.size = ftell (f) - chunkpos;
chunk.magic = FLI_LC;
fseek (f, chunkpos, SEEK_SET);
fli_write_uint32 (f, chunk.size);
fli_write_short (f, chunk.magic);
if (chunk.size & 1)
chunk.size++;
{
/* Dummy char to make the chunk end on an even boundary. */
if (! fli_write_char (f, 0, error))
{
g_prefix_error (error, _("Error writing frame. "));
return FALSE;
}
chunk.size++;
}
fseek (f, chunkpos, SEEK_SET);
if (! fli_write_uint32 (f, chunk.size, error) ||
! fli_write_short (f, chunk.magic, error))
{
g_prefix_error (error, _("Error writing frame. "));
return FALSE;
}
fseek (f, chunkpos + chunk.size, SEEK_SET);
return TRUE;
}