[gimp] plug-ins: make PSD resource loading handle 64-bit lengths.



commit 35f4b7b5177e1982081f071cdbd07bb222e76faa
Author: Jacob Boerema <jgboerema gmail com>
Date:   Mon May 17 18:54:13 2021 -0400

    plug-ins: make PSD resource loading handle 64-bit lengths.
    
    For PSB images certain resources have 64-bit lengths.
    Let's handle this transparently by adding a psd_version
    parameter and depending on that and the type of
    resource we decide if the length to read is 32 or 64-bit.
    
    We also return the total header size. This way the
    calling function can use that to determine the
    remaining length.
    
    Because we needed to check the signature when
    loading the header we remove that check from
    the load_layer_resource function since that
    would be redundant.

 plug-ins/file-psd/psd-layer-res-load.c | 186 +++++++++++++++++++++------------
 plug-ins/file-psd/psd-layer-res-load.h |   1 +
 plug-ins/file-psd/psd-load.c           |  20 +++-
 3 files changed, 133 insertions(+), 74 deletions(-)
---
diff --git a/plug-ins/file-psd/psd-layer-res-load.c b/plug-ins/file-psd/psd-layer-res-load.c
index 460825809f..3e36c2733f 100644
--- a/plug-ins/file-psd/psd-layer-res-load.c
+++ b/plug-ins/file-psd/psd-layer-res-load.c
@@ -196,26 +196,77 @@ static gint     load_resource_lnsr    (const PSDlayerres     *res_a,
                                        GError               **error);
 
 /* Public Functions */
+
+/* Returns < 0 for errors, else returns the size of the resource header
+ * which should be either 4 or 8. */
 gint
 get_layer_resource_header (PSDlayerres   *res_a,
+                           guint16        psd_version,
                            GInputStream  *input,
                            GError       **error)
 {
-  g_debug ("get_layer_resource_header");
-  if (psd_read (input, res_a->sig,       4, error) < 4 ||
-      psd_read (input, res_a->key,       4, error) < 4 ||
-      psd_read (input, &res_a->data_len, 4, error) < 4)
+  gint  block_len_size = 4;
+
+  if (psd_read (input, res_a->sig, 4, error) < 4 ||
+      psd_read (input, res_a->key, 4, error) < 4)
+    {
+      psd_set_error (error);
+      return -1;
+    }
+  else if (memcmp (res_a->sig, "8BIM", 4) != 0 &&
+           memcmp (res_a->sig, "8B64", 4) != 0)
+    {
+      IFDBG(1) g_debug ("Unknown layer resource signature %.4s", res_a->sig);
+    }
+
+  if (psd_version == 1)
+    block_len_size = 4;
+  else
+    {
+      /* For PSB only certain block resources have a double sized length
+        * so we need to check which resource it is first before we can
+        * read the block length.
+        * According to the docs: LMsk, Lr16, Lr32, Layr, Mt16, Mt32, Mtrn,
+        * Alph, FMsk, lnk2, FEid, FXid, PxSD have an 8 byte length. */
+      if (memcmp (res_a->key, "LMsk", 4) == 0 ||
+          memcmp (res_a->key, "Lr16", 4) == 0 ||
+          memcmp (res_a->key, "Lr32", 4) == 0 ||
+          memcmp (res_a->key, "Layr", 4) == 0 ||
+          memcmp (res_a->key, "Mt16", 4) == 0 ||
+          memcmp (res_a->key, "Mt32", 4) == 0 ||
+          memcmp (res_a->key, "Mtrn", 4) == 0 ||
+          memcmp (res_a->key, "Alph", 4) == 0 ||
+          memcmp (res_a->key, "FMsk", 4) == 0 ||
+          memcmp (res_a->key, "lnk2", 4) == 0 ||
+          memcmp (res_a->key, "FEid", 4) == 0 ||
+          memcmp (res_a->key, "FXid", 4) == 0 ||
+          memcmp (res_a->key, "PxSD", 4) == 0 ||
+          /* Apparently also using 8 bytes in size but not mentioned in specs: */
+          memcmp (res_a->key, "lnkE", 4) == 0 ||
+          memcmp (res_a->key, "pths", 4) == 0
+          )
+        block_len_size = 8;
+      else
+        block_len_size = 4;
+      IFDBG(3) g_debug ("PSB: Using block_len_size %d", block_len_size);
+    }
+
+  if (psd_read (input, &res_a->data_len, block_len_size, error) < block_len_size)
     {
       psd_set_error (error);
       return -1;
     }
-  res_a->data_len = GUINT32_FROM_BE (res_a->data_len);
-  res_a->data_start = g_seekable_tell (G_SEEKABLE (input));
+
+  if (block_len_size == 4)
+    res_a->data_len = GUINT32_FROM_BE (res_a->data_len);
+  else
+    res_a->data_len = GUINT64_FROM_BE (res_a->data_len);
+  res_a->data_start = PSD_TELL (input);
 
   IFDBG(2) g_debug ("Sig: %.4s, key: %.4s, start: %" G_GOFFSET_FORMAT ", len: %" G_GOFFSET_FORMAT,
                      res_a->sig, res_a->key, res_a->data_start, res_a->data_len);
 
-  return 0;
+  return block_len_size + 8;
 }
 
 gint
@@ -232,67 +283,60 @@ load_layer_resource (PSDlayerres   *res_a,
     }
 
   /* Process layer resource blocks */
-  if (memcmp (res_a->sig, "8BIM", 4) != 0)
-    {
-      IFDBG(1) g_debug ("Unknown layer resource signature %.4s", res_a->sig);
-    }
-  else
-    {
-      if (memcmp (res_a->key, PSD_LADJ_LEVEL, 4) == 0
-          || memcmp (res_a->key, PSD_LADJ_CURVE, 4) == 0
-          || memcmp (res_a->key, PSD_LADJ_BRIGHTNESS, 4) == 0
-          || memcmp (res_a->key, PSD_LADJ_BALANCE, 4) == 0
-          || memcmp (res_a->key, PSD_LADJ_BLACK_WHITE, 4) == 0
-          || memcmp (res_a->key, PSD_LADJ_HUE, 4) == 0
-          || memcmp (res_a->key, PSD_LADJ_HUE2, 4) == 0
-          || memcmp (res_a->key, PSD_LADJ_SELECTIVE, 4) == 0
-          || memcmp (res_a->key, PSD_LADJ_MIXER, 4) == 0
-          || memcmp (res_a->key, PSD_LADJ_GRAD_MAP, 4) == 0
-          || memcmp (res_a->key, PSD_LADJ_PHOTO_FILT, 4) == 0
-          || memcmp (res_a->key, PSD_LADJ_EXPOSURE, 4) == 0
-          || memcmp (res_a->key, PSD_LADJ_THRESHOLD, 4) == 0
-          || memcmp (res_a->key, PSD_LADJ_INVERT, 4) == 0
-          || memcmp (res_a->key, PSD_LADJ_POSTERIZE, 4) == 0)
-        load_resource_ladj (res_a, lyr_a, input, error);
-
-      else if (memcmp (res_a->key, PSD_LFIL_SOLID, 4) == 0
-               || memcmp (res_a->key, PSD_LFIL_PATTERN, 4) == 0
-               || memcmp (res_a->key, PSD_LFIL_GRADIENT, 4) == 0)
-        load_resource_lfil (res_a, lyr_a, input, error);
-
-      else if (memcmp (res_a->key, PSD_LFX_FX, 4) == 0
-               || memcmp (res_a->key, PSD_LFX_FX2, 4) == 0)
-        load_resource_lfx (res_a, lyr_a, input, error);
-
-      else if (memcmp (res_a->key, PSD_LTYP_TYPE, 4) == 0
-               || memcmp (res_a->key, PSD_LTYP_TYPE2, 4) == 0)
-        load_resource_ltyp (res_a, lyr_a, input, error);
-
-      else if (memcmp (res_a->key, PSD_LPRP_UNICODE, 4) == 0)
-        load_resource_luni (res_a, lyr_a, input, error);
-
-      else if (memcmp (res_a->key, PSD_LPRP_ID, 4) == 0)
-        load_resource_lyid (res_a, lyr_a, input, error);
-
-      else if (memcmp (res_a->key, PSD_LPRP_COLOR, 4) == 0)
-        load_resource_lclr (res_a, lyr_a, input, error);
-
-      else if (memcmp (res_a->key, PSD_LOTH_SECTION, 4) == 0
-               || memcmp (res_a->key, PSD_LOTH_SECTION2, 4) == 0) /* bug #789981 */
-        load_resource_lsct (res_a, lyr_a, input, error);
-
-      else if (memcmp (res_a->key, PSD_LFX_FX, 4) == 0)
-        load_resource_lrfx (res_a, lyr_a, input, error);
-
-      else if (memcmp (res_a->key, PSD_LPRP_VERSION, 4) == 0)
-        load_resource_lyvr (res_a, lyr_a, input, error);
-
-      else if (memcmp (res_a->key, PSD_LPRP_SOURCE, 4) == 0)
-        load_resource_lnsr (res_a, lyr_a, input, error);
+  if (memcmp (res_a->key, PSD_LADJ_LEVEL, 4) == 0
+      || memcmp (res_a->key, PSD_LADJ_CURVE, 4) == 0
+      || memcmp (res_a->key, PSD_LADJ_BRIGHTNESS, 4) == 0
+      || memcmp (res_a->key, PSD_LADJ_BALANCE, 4) == 0
+      || memcmp (res_a->key, PSD_LADJ_BLACK_WHITE, 4) == 0
+      || memcmp (res_a->key, PSD_LADJ_HUE, 4) == 0
+      || memcmp (res_a->key, PSD_LADJ_HUE2, 4) == 0
+      || memcmp (res_a->key, PSD_LADJ_SELECTIVE, 4) == 0
+      || memcmp (res_a->key, PSD_LADJ_MIXER, 4) == 0
+      || memcmp (res_a->key, PSD_LADJ_GRAD_MAP, 4) == 0
+      || memcmp (res_a->key, PSD_LADJ_PHOTO_FILT, 4) == 0
+      || memcmp (res_a->key, PSD_LADJ_EXPOSURE, 4) == 0
+      || memcmp (res_a->key, PSD_LADJ_THRESHOLD, 4) == 0
+      || memcmp (res_a->key, PSD_LADJ_INVERT, 4) == 0
+      || memcmp (res_a->key, PSD_LADJ_POSTERIZE, 4) == 0)
+    load_resource_ladj (res_a, lyr_a, input, error);
+
+  else if (memcmp (res_a->key, PSD_LFIL_SOLID, 4) == 0
+           || memcmp (res_a->key, PSD_LFIL_PATTERN, 4) == 0
+           || memcmp (res_a->key, PSD_LFIL_GRADIENT, 4) == 0)
+    load_resource_lfil (res_a, lyr_a, input, error);
+
+  else if (memcmp (res_a->key, PSD_LFX_FX, 4) == 0
+           || memcmp (res_a->key, PSD_LFX_FX2, 4) == 0)
+    load_resource_lfx (res_a, lyr_a, input, error);
+
+  else if (memcmp (res_a->key, PSD_LTYP_TYPE, 4) == 0
+           || memcmp (res_a->key, PSD_LTYP_TYPE2, 4) == 0)
+    load_resource_ltyp (res_a, lyr_a, input, error);
+
+  else if (memcmp (res_a->key, PSD_LPRP_UNICODE, 4) == 0)
+    load_resource_luni (res_a, lyr_a, input, error);
+
+  else if (memcmp (res_a->key, PSD_LPRP_ID, 4) == 0)
+    load_resource_lyid (res_a, lyr_a, input, error);
+
+  else if (memcmp (res_a->key, PSD_LPRP_COLOR, 4) == 0)
+    load_resource_lclr (res_a, lyr_a, input, error);
+
+  else if (memcmp (res_a->key, PSD_LOTH_SECTION, 4) == 0
+           || memcmp (res_a->key, PSD_LOTH_SECTION2, 4) == 0) /* bug #789981 */
+    load_resource_lsct (res_a, lyr_a, input, error);
+
+  else if (memcmp (res_a->key, PSD_LFX_FX, 4) == 0)
+    load_resource_lrfx (res_a, lyr_a, input, error);
+
+  else if (memcmp (res_a->key, PSD_LPRP_VERSION, 4) == 0)
+    load_resource_lyvr (res_a, lyr_a, input, error);
+
+  else if (memcmp (res_a->key, PSD_LPRP_SOURCE, 4) == 0)
+    load_resource_lnsr (res_a, lyr_a, input, error);
 
-      else
-        load_resource_unknown (res_a, lyr_a, input, error);
-    }
+  else
+    load_resource_unknown (res_a, lyr_a, input, error);
 
   if (error && *error)
     return -1;
@@ -569,7 +613,9 @@ load_resource_lsct (const PSDlayerres  *res_a,
           psd_set_error (error);
           return -1;
         }
-      if (memcmp (signature, "8BIM", 4) == 0)
+      /* Not sure if 8B64 is possible here but it won't hurt to check. */
+      if (memcmp (signature, "8BIM", 4) == 0 ||
+          memcmp (signature, "8B64", 4) == 0)
         {
           memcpy (lyr_a->blend_mode, blend_mode, 4);
           IFDBG(3) g_debug ("Section divider layer mode sig: %.4s, blend mode: %.4s",
@@ -614,7 +660,9 @@ load_resource_lrfx (const PSDlayerres  *res_a,
           return -1;
         }
 
-      if (memcmp (signature, "8BIM", 4) != 0)
+      /* Not sure if 8B64 is possible here but it won't hurt to check. */
+      if (memcmp (signature, "8BIM", 4) != 0 &&
+          memcmp (signature, "8B64", 4) != 0)
         {
           IFDBG(1) g_debug ("Unknown layer resource signature %.4s", signature);
         }
diff --git a/plug-ins/file-psd/psd-layer-res-load.h b/plug-ins/file-psd/psd-layer-res-load.h
index 930d160c88..da445c04e8 100644
--- a/plug-ins/file-psd/psd-layer-res-load.h
+++ b/plug-ins/file-psd/psd-layer-res-load.h
@@ -23,6 +23,7 @@
 
 
 gint  get_layer_resource_header (PSDlayerres   *res_a,
+                                 guint16        psd_version,
                                  GInputStream  *input,
                                  GError       **error);
 
diff --git a/plug-ins/file-psd/psd-load.c b/plug-ins/file-psd/psd-load.c
index 4799bb2fa3..02285715e3 100644
--- a/plug-ins/file-psd/psd-load.c
+++ b/plug-ins/file-psd/psd-load.c
@@ -616,7 +616,9 @@ read_layer_info (PSDimage      *img_a,
               psd_set_error (error);
               return NULL;
             }
-          if (memcmp (lyr_a[lidx]->mode_key, "8BIM", 4) != 0)
+          /* Not sure if 8B64 is possible here but it won't hurt to check. */
+          if (memcmp (lyr_a[lidx]->mode_key, "8BIM", 4) != 0 &&
+              memcmp (lyr_a[lidx]->mode_key, "8B64", 4) != 0)
             {
               IFDBG(1) g_debug ("Incorrect layer mode signature %.4s",
                                 lyr_a[lidx]->mode_key);
@@ -911,16 +913,24 @@ read_layer_info (PSDimage      *img_a,
             return NULL;
 
           block_rem -= read_len;
-          IFDBG(3) g_debug ("Remaining length %" G_GOFFSET_FORMAT, block_rem);
+          IFDBG(3) g_debug ("Offset: %" G_GOFFSET_FORMAT ", Remaining length %" G_GSIZE_FORMAT,
+                            PSD_TELL(input), block_rem);
 
           /* Adjustment layer info */           /* FIXME */
 
           while (block_rem > 7)
             {
-              if (get_layer_resource_header (&res_a, input, error) < 0)
-                return NULL;
+              gint  header_size;
+              IFDBG(3) g_debug ("Offset: %" G_GOFFSET_FORMAT ", Remaining length %" G_GSIZE_FORMAT,
+                                PSD_TELL(input), block_rem);
+              header_size = get_layer_resource_header (&res_a, img_a->version, input, error);
+              if (header_size < 0)
+                {
+                  psd_set_error (error);
+                  return NULL;
+                }
 
-              block_rem -= 12;
+              block_rem -= header_size;
 
               if (res_a.data_len % 2 != 0)
                 {


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