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.
This commit is contained in:
Jacob Boerema 2021-05-17 18:54:13 -04:00
parent 6f523d33dd
commit 35f4b7b517
3 changed files with 133 additions and 74 deletions

View File

@ -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;
}
res_a->data_len = GUINT32_FROM_BE (res_a->data_len);
res_a->data_start = g_seekable_tell (G_SEEKABLE (input));
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;
}
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);
}
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
{
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);
}
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);
}

View File

@ -23,6 +23,7 @@
gint get_layer_resource_header (PSDlayerres *res_a,
guint16 psd_version,
GInputStream *input,
GError **error);

View File

@ -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)
{