[gimp] plug-ins: improve error handling of FLI export



commit ca8eee1755af8773f37314447ce679720f5fddc2
Author: Jacob Boerema <jgboerema gmail com>
Date:   Mon May 16 11:20:52 2022 -0400

    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.

 plug-ins/file-fli/fli-gimp.c |   2 +
 plug-ins/file-fli/fli.c      | 338 ++++++++++++++++++++++++++++++++-----------
 2 files changed, 258 insertions(+), 82 deletions(-)
---
diff --git a/plug-ins/file-fli/fli-gimp.c b/plug-ins/file-fli/fli-gimp.c
index a290344173..bbc8007c22 100644
--- a/plug-ins/file-fli/fli-gimp.c
+++ b/plug-ins/file-fli/fli-gimp.c
@@ -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))
diff --git a/plug-ins/file-fli/fli.c b/plug-ins/file-fli/fli.c
index dd19dc9861..7343817781 100644
--- a/plug-ins/file-fli/fli.c
+++ b/plug-ins/file-fli/fli.c
@@ -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;
 
+  if (chunk.size & 1)
+    {
+      /* 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);
-  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 frame. "));
+      return FALSE;
+    }
 
-  if (chunk.size & 1)
-    chunk.size++;
   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;
 
+  if (chunk.size & 1)
+    {
+      /* 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);
-  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 frame. "));
+      return FALSE;
+    }
 
-  if (chunk.size & 1)
-    chunk.size++;
   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;
 
+  if (chunk.size & 1)
+    {
+      /* 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);
-  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 frame. "));
+      return FALSE;
+    }
 
-  if (chunk.size & 1)
-    chunk.size++;
   fseek (f, chunkpos + chunk.size, SEEK_SET);
   return TRUE;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]