[gimp/osx-build: 55/55] Bug 730211-Load XCF files with shifted layer offset table



commit e1e8e19237937766f44c7fdf8c184b64dfe8492b
Author: Massimo Valentini <mvalentini src gnome org>
Date:   Tue Jul 15 19:55:37 2014 +0200

    Bug 730211-Load XCF files with shifted layer offset table
    
    Load xcf files that have extra NULL characters between image properties
    and the layer offset table.
    
    Improvements to Massimo's patch:
    - Replace goto by while loop.
    - Add comments.

 app/xcf/xcf-load.c |  292 +++++++++++++++++++++++++++++++++-------------------
 1 files changed, 184 insertions(+), 108 deletions(-)
---
diff --git a/app/xcf/xcf-load.c b/app/xcf/xcf-load.c
index 88cf6f5..6c78ce2 100644
--- a/app/xcf/xcf-load.c
+++ b/app/xcf/xcf-load.c
@@ -129,6 +129,8 @@ static gboolean        xcf_load_vector        (XcfInfo      *info,
 
 static gboolean        xcf_skip_unknown_prop  (XcfInfo      *info,
                                                gsize         size);
+static gboolean        xcf_find_layer_offset_table (XcfInfo *info,
+                                                    glong    offset);
 
 
 #define xcf_progress_update(info) G_STMT_START  \
@@ -164,6 +166,9 @@ xcf_load_image (Gimp     *gimp,
   gint                height;
   gint                image_type;
   gint                num_successful_elements = 0;
+  guint32             retry_offset;
+  gboolean            retried                 = FALSE;
+  gboolean            terminate_loop            = FALSE;
 
   /* read in the image width, height and type */
   info->cp += xcf_read_int32 (info->fp, (guint32 *) &width, 1);
@@ -204,135 +209,160 @@ xcf_load_image (Gimp     *gimp,
 
   xcf_progress_update (info);
 
-  while (TRUE)
+  retry_offset = info->cp;
+
+  /* read in layers and channels; retry one time when they are accidently
+   * shifted in the file (see bug #730211)
+   */
+  while (! terminate_loop)
     {
-      GimpLayer *layer;
-      GList     *item_path = NULL;
+      while (TRUE)
+        {
+          GimpLayer *layer;
+          GList     *item_path = NULL;
 
-      /* read in the offset of the next layer */
-      info->cp += xcf_read_int32 (info->fp, &offset, 1);
+          /* read in the offset of the next layer */
+          info->cp += xcf_read_int32 (info->fp, &offset, 1);
 
-      /* if the offset is 0 then we are at the end
-       *  of the layer list.
-       */
-      if (offset == 0)
-        break;
-
-      /* save the current position as it is where the
-       *  next layer offset is stored.
-       */
-      saved_pos = info->cp;
+          /* if the offset is 0 then we are at the end
+           *  of the layer list.
+           */
+          if (offset == 0)
+            break;
 
-      /* seek to the layer offset */
-      if (! xcf_seek_pos (info, offset, NULL))
-        goto error;
+          /* save the current position as it is where the
+           *  next layer offset is stored.
+           */
+          saved_pos = info->cp;
 
-      /* read in the layer */
-      layer = xcf_load_layer (info, image, &item_path);
-      if (!layer)
-        goto error;
+          /* seek to the layer offset */
+          if (! xcf_seek_pos (info, offset, NULL))
+            goto error;
 
-      num_successful_elements++;
+          /* read in the layer */
+          layer = xcf_load_layer (info, image, &item_path);
+          if (!layer)
+            goto error;
 
-      xcf_progress_update (info);
+          num_successful_elements++;
 
-      /* add the layer to the image if its not the floating selection */
-      if (layer != info->floating_sel)
-        {
-          GimpContainer *layers = gimp_image_get_layers (image);
-          GimpContainer *container;
-          GimpLayer     *parent;
+          xcf_progress_update (info);
 
-          if (item_path)
+          /* add the layer to the image if its not the floating selection */
+          if (layer != info->floating_sel)
             {
-              if (info->floating_sel)
+              GimpContainer *layers = gimp_image_get_layers (image);
+              GimpContainer *container;
+              GimpLayer     *parent;
+
+              if (item_path)
                 {
-                  /* there is a floating selection, but it will get
-                   * added after all layers are loaded, so toplevel
-                   * layer indices are off-by-one. Adjust item paths
-                   * accordingly:
-                   */
-                  gint toplevel_index;
+                  if (info->floating_sel)
+                    {
+                      /* there is a floating selection, but it will get
+                       * added after all layers are loaded, so toplevel
+                       * layer indices are off-by-one. Adjust item paths
+                       * accordingly:
+                       */
+                      gint toplevel_index;
 
-                  toplevel_index = GPOINTER_TO_UINT (item_path->data);
+                      toplevel_index = GPOINTER_TO_UINT (item_path->data);
 
-                  toplevel_index--;
+                      toplevel_index--;
 
-                  item_path->data = GUINT_TO_POINTER (toplevel_index);
-                }
+                      item_path->data = GUINT_TO_POINTER (toplevel_index);
+                    }
 
-              parent = GIMP_LAYER
-                (gimp_item_stack_get_parent_by_path (GIMP_ITEM_STACK (layers),
-                                                     item_path,
-                                                     NULL));
+                  parent = GIMP_LAYER
+                    (gimp_item_stack_get_parent_by_path (GIMP_ITEM_STACK (layers),
+                                                         item_path,
+                                                         NULL));
 
-              container = gimp_viewable_get_children (GIMP_VIEWABLE (parent));
+                  container = gimp_viewable_get_children (GIMP_VIEWABLE (parent));
+
+                  g_list_free (item_path);
+                }
+              else
+                {
+                  parent    = NULL;
+                  container = layers;
+                }
 
-              g_list_free (item_path);
+              gimp_image_add_layer (image, layer,
+                                    parent,
+                                    gimp_container_get_n_children (container),
+                                    FALSE);
             }
-          else
+
+          /* restore the saved position so we'll be ready to
+           *  read the next offset.
+           */
+          if (! xcf_seek_pos (info, saved_pos, NULL))
+            goto error;
+        } /* read layers */
+
+      /* read channels */
+      while (TRUE)
+        {
+          GimpChannel *channel;
+
+          /* read in the offset of the next channel */
+          info->cp += xcf_read_int32 (info->fp, &offset, 1);
+
+          /* If the offset is 0, then we are at the end of the channel list. */
+          if (offset == 0)
+            break;
+
+          /* save the current position as it is where the
+           * next channel offset is stored.
+           */
+          saved_pos = info->cp;
+
+          /* seek to the channel offset */
+          if (! xcf_seek_pos (info, offset, NULL))
+            goto error;
+
+          /* read in the channel */
+          channel = xcf_load_channel (info, image);
+          if (!channel)
+            goto error;
+
+          num_successful_elements++;
+
+          xcf_progress_update (info);
+
+          /* add the channel to the image if its not the selection */
+          if (channel != gimp_image_get_mask (image))
+            gimp_image_add_channel (image, channel,
+                                    NULL, /* FIXME tree */
+                                    gimp_container_get_n_children (gimp_image_get_channels (image)),
+                                    FALSE);
+
+          /* restore the saved position so we'll be ready to
+           *  read the next offset.
+           */
+          if (! xcf_seek_pos (info, saved_pos, NULL))
+            goto error;
+        } /* read channels */
+
+      terminate_loop =
+          (num_successful_elements > 0) ||
+          retried ||
+          (! xcf_find_layer_offset_table (info, retry_offset));
+
+      if (! terminate_loop)
+        retried = TRUE;
+/*
+      if (num_successful_elements == 0 && !retried)
+        {
+          if (xcf_find_layer_offset_table (info, retry_offset))
             {
-              parent    = NULL;
-              container = layers;
+              retried = TRUE;
+              goto retry;
             }
-
-          gimp_image_add_layer (image, layer,
-                                parent,
-                                gimp_container_get_n_children (container),
-                                FALSE);
         }
-
-      /* restore the saved position so we'll be ready to
-       *  read the next offset.
-       */
-      if (! xcf_seek_pos (info, saved_pos, NULL))
-        goto error;
-    }
-
-  while (TRUE)
-    {
-      GimpChannel *channel;
-
-      /* read in the offset of the next channel */
-      info->cp += xcf_read_int32 (info->fp, &offset, 1);
-
-      /* if the offset is 0 then we are at the end
-       *  of the channel list.
-       */
-      if (offset == 0)
-        break;
-
-      /* save the current position as it is where the
-       *  next channel offset is stored.
-       */
-      saved_pos = info->cp;
-
-      /* seek to the channel offset */
-      if (! xcf_seek_pos (info, offset, NULL))
-        goto error;
-
-      /* read in the channel */
-      channel = xcf_load_channel (info, image);
-      if (!channel)
-        goto error;
-
-      num_successful_elements++;
-
-      xcf_progress_update (info);
-
-      /* add the channel to the image if its not the selection */
-      if (channel != gimp_image_get_mask (image))
-        gimp_image_add_channel (image, channel,
-                                NULL, /* FIXME tree */
-                                gimp_container_get_n_children (gimp_image_get_channels (image)),
-                                FALSE);
-
-      /* restore the saved position so we'll be ready to
-       *  read the next offset.
-       */
-      if (! xcf_seek_pos (info, saved_pos, NULL))
-        goto error;
-    }
+*/
+    } /* while (! terminate_loop) */
 
   xcf_load_add_masks (image);
 
@@ -2027,3 +2057,49 @@ xcf_skip_unknown_prop (XcfInfo *info,
 
   return TRUE;
 }
+
+static gboolean
+xcf_find_layer_offset_table (XcfInfo *info,
+                             glong    offset)
+{
+  guint8 c = 0;
+  guint8 buf[4] = { 0, };
+  guint layer_offset;
+  gint  i;
+
+  xcf_seek_pos (info, offset, NULL);
+
+  /* read all NULL-bytes; return if no byte was read */
+  while (c == 0)
+    {
+      if (xcf_read_int8 (info->fp, &c, 1) == 0)
+        return FALSE;
+      offset++;
+    }
+
+  /* read 4 bytes into buf; ; return if no byte was read */
+  buf[0] = c;
+  for (i = 1; i < 4; ++i)
+    {
+      if (xcf_read_int8 (info->fp, &c, 1) == 0)
+        return FALSE;
+      buf[i] = c;
+    }
+
+  layer_offset = 0;
+
+  /* move buf into layer_offset; set file position there */
+  for (i = 0; i < 4; ++i)
+    {
+      layer_offset = (layer_offset << 8) | buf[i];
+
+      if (layer_offset >= offset - 4 + i + 12)
+        {
+          info->cp = 0;
+          xcf_seek_pos (info, offset - 4 + i, NULL);
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}


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