[gimp] app: salvage loaded group and text layer of dimension 0.



commit 06be074650ca5a6a4d5885ea87750cc57731cc02
Author: Jehan <jehan girinstud io>
Date:   Thu Jul 11 16:32:45 2019 +0200

    app: salvage loaded group and text layer of dimension 0.
    
    Whereas normal layers of dimension 0x0 are definitely broken, group and
    text layers depend on their contents, which will be able to resize the
    layer appropriately and fix whatever rendering. This commit allows to
    salvage such layers, hence make XCF loading even more resistant to
    certain form of file corruption.
    
    This commit (and the previous one) are not theoretical but the result of
    discovering some old corrupted file, with an empty group of size 0x0
    (saved by GIMP itself, because of some old bug). Rather than destroying
    these layer groups, this just allows us to reopen them without any kind
    of loss!

 app/xcf/xcf-load.c | 69 +++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 58 insertions(+), 11 deletions(-)
---
diff --git a/app/xcf/xcf-load.c b/app/xcf/xcf-load.c
index 82d97c60a9..5f609e2d04 100644
--- a/app/xcf/xcf-load.c
+++ b/app/xcf/xcf-load.c
@@ -97,7 +97,9 @@ static gboolean        xcf_load_layer_props   (XcfInfo       *info,
                                                guint32       *text_layer_flags,
                                                guint32       *group_layer_flags);
 static gboolean        xcf_check_layer_props  (XcfInfo       *info,
-                                               GList        **item_path);
+                                               GList        **item_path,
+                                               gboolean      *is_group_layer,
+                                               gboolean      *is_text_layer);
 static gboolean        xcf_load_channel_props (XcfInfo       *info,
                                                GimpImage     *image,
                                                GimpChannel  **channel);
@@ -478,7 +480,12 @@ xcf_load_image (Gimp     *gimp,
           n_broken_layers++;
 
           if (! xcf_seek_pos (info, saved_pos, NULL))
-            goto error;
+            {
+              if (item_path)
+                g_list_free (item_path);
+
+              goto error;
+            }
 
           /* Don't just stop at the first broken layer. Load as much as
            * possible.
@@ -560,7 +567,10 @@ xcf_load_image (Gimp     *gimp,
     }
 
   if (broken_paths)
-    g_list_free_full (broken_paths, (GDestroyNotify) g_list_free);
+    {
+      g_list_free_full (broken_paths, (GDestroyNotify) g_list_free);
+      broken_paths = NULL;
+    }
 
   while (TRUE)
     {
@@ -649,6 +659,9 @@ xcf_load_image (Gimp     *gimp,
   return image;
 
  error:
+  if (broken_paths)
+    g_list_free_full (broken_paths, (GDestroyNotify) g_list_free);
+
   if (num_successful_elements == 0)
     goto hard_error;
 
@@ -1477,12 +1490,17 @@ xcf_load_layer_props (XcfInfo    *info,
 }
 
 static gboolean
-xcf_check_layer_props (XcfInfo  *info,
-                       GList   **item_path)
+xcf_check_layer_props (XcfInfo    *info,
+                       GList     **item_path,
+                       gboolean   *is_group_layer,
+                       gboolean   *is_text_layer)
 {
   PropType prop_type;
   guint32  prop_size;
 
+  g_return_val_if_fail (*is_group_layer == FALSE, FALSE);
+  g_return_val_if_fail (*is_text_layer  == FALSE, FALSE);
+
   while (TRUE)
     {
       if (! xcf_load_prop (info, &prop_type, &prop_size))
@@ -1493,6 +1511,21 @@ xcf_check_layer_props (XcfInfo  *info,
         case PROP_END:
           return TRUE;
 
+        case PROP_TEXT_LAYER_FLAGS:
+          *is_text_layer = TRUE;
+
+          if (! xcf_skip_unknown_prop (info, prop_size))
+            return FALSE;
+          break;
+
+        case PROP_GROUP_ITEM:
+        case PROP_GROUP_ITEM_FLAGS:
+          *is_group_layer = TRUE;
+
+          if (! xcf_skip_unknown_prop (info, prop_size))
+            return FALSE;
+          break;
+
         case PROP_ITEM_PATH:
           {
             goffset  base = info->cp;
@@ -1515,9 +1548,6 @@ xcf_check_layer_props (XcfInfo  *info,
           }
           break;
 
-        case PROP_TEXT_LAYER_FLAGS:
-        case PROP_GROUP_ITEM:
-        case PROP_GROUP_ITEM_FLAGS:
         case PROP_ACTIVE_LAYER:
         case PROP_FLOATING_SELECTION:
         case PROP_OPACITY:
@@ -1861,9 +1891,26 @@ xcf_load_layer (XcfInfo    *info,
 
   if (width <= 0 || height <= 0)
     {
-      /* Load item path anyway. */
-      xcf_check_layer_props (info, item_path);
-      return NULL;
+      gboolean is_group_layer = FALSE;
+      gboolean is_text_layer  = FALSE;
+      goffset  saved_pos;
+
+      saved_pos = info->cp;
+      /* Load item path and check if this is a group or text layer. */
+      xcf_check_layer_props (info, item_path, &is_group_layer, &is_text_layer);
+      if ((is_text_layer || is_group_layer) &&
+          xcf_seek_pos (info, saved_pos, NULL))
+        {
+          /* Something is wrong, but leave a chance to the layer because
+           * anyway group and text layer depends on their contents.
+           */
+          width = height = 1;
+          g_clear_pointer (item_path, g_list_free);
+        }
+      else
+        {
+          return NULL;
+        }
     }
 
   if (base_type == GIMP_GRAY)


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