diff --git a/plug-ins/file-psd/Makefile.am b/plug-ins/file-psd/Makefile.am index a190667249..13867542eb 100644 --- a/plug-ins/file-psd/Makefile.am +++ b/plug-ins/file-psd/Makefile.am @@ -67,4 +67,5 @@ file_psd_LDADD = \ $(IPTCDATA_LIBS) \ $(RT_LIBS) \ $(INTLLIBS) \ + $(Z_LIBS) \ $(file_psd_RC) diff --git a/plug-ins/file-psd/psd-load.c b/plug-ins/file-psd/psd-load.c index d2e4e0e8a7..1f7c29da24 100644 --- a/plug-ins/file-psd/psd-load.c +++ b/plug-ins/file-psd/psd-load.c @@ -24,6 +24,7 @@ #include #include +#include #include #include "psd.h" @@ -95,6 +96,7 @@ static gint read_channel_data (PSDchannel *channel, guint16 compression, const guint16 *rle_pack_len, FILE *f, + guint16 comp_len, GError **error); static void convert_1_bit (const gchar *src, @@ -465,19 +467,404 @@ read_image_resource_block (PSDimage *img_a, } static PSDlayer ** -read_layer_block (PSDimage *img_a, - FILE *f, - GError **error) +read_layer_info (PSDimage *img_a, + FILE *f, + GError **error) { - PSDlayer **lyr_a; + PSDlayer **lyr_a = NULL; guint32 block_len; - guint32 block_end; guint32 block_rem; gint32 read_len; gint32 write_len; gint lidx; /* Layer index */ gint cidx; /* Channel index */ + /* Get number of layers */ + if (fread (&img_a->num_layers, 2, 1, f) < 1) + { + psd_set_error (feof (f), errno, error); + img_a->num_layers = -1; + return NULL; + } + + img_a->num_layers = GINT16_FROM_BE (img_a->num_layers); + IFDBG(2) g_debug ("Number of layers: %d", img_a->num_layers); + + if (img_a->num_layers < 0) + { + img_a->transparency = TRUE; + img_a->num_layers = -img_a->num_layers; + } + + if (img_a->num_layers) + { + /* Read layer records */ + PSDlayerres res_a; + + /* Create pointer array for the layer records */ + lyr_a = g_new (PSDlayer *, img_a->num_layers); + + for (lidx = 0; lidx < img_a->num_layers; ++lidx) + { + /* Allocate layer record */ + lyr_a[lidx] = (PSDlayer *) g_malloc (sizeof (PSDlayer) ); + + /* Initialise record */ + lyr_a[lidx]->drop = FALSE; + lyr_a[lidx]->id = 0; + lyr_a[lidx]->group_type = 0; + + if (fread (&lyr_a[lidx]->top, 4, 1, f) < 1 + || fread (&lyr_a[lidx]->left, 4, 1, f) < 1 + || fread (&lyr_a[lidx]->bottom, 4, 1, f) < 1 + || fread (&lyr_a[lidx]->right, 4, 1, f) < 1 + || fread (&lyr_a[lidx]->num_channels, 2, 1, f) < 1) + { + psd_set_error (feof (f), errno, error); + return NULL; + } + + lyr_a[lidx]->top = GINT32_FROM_BE (lyr_a[lidx]->top); + lyr_a[lidx]->left = GINT32_FROM_BE (lyr_a[lidx]->left); + lyr_a[lidx]->bottom = GINT32_FROM_BE (lyr_a[lidx]->bottom); + lyr_a[lidx]->right = GINT32_FROM_BE (lyr_a[lidx]->right); + lyr_a[lidx]->num_channels = GUINT16_FROM_BE (lyr_a[lidx]->num_channels); + + if (lyr_a[lidx]->num_channels > MAX_CHANNELS) + { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + _("Too many channels in layer: %d"), + lyr_a[lidx]->num_channels); + return NULL; + } + if (lyr_a[lidx]->bottom < lyr_a[lidx]->top || + lyr_a[lidx]->bottom - lyr_a[lidx]->top > GIMP_MAX_IMAGE_SIZE) + { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + _("Unsupported or invalid layer height: %d"), + lyr_a[lidx]->bottom - lyr_a[lidx]->top); + return NULL; + } + if (lyr_a[lidx]->right < lyr_a[lidx]->left || + lyr_a[lidx]->right - lyr_a[lidx]->left > GIMP_MAX_IMAGE_SIZE) + { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + _("Unsupported or invalid layer width: %d"), + lyr_a[lidx]->right - lyr_a[lidx]->left); + return NULL; + } + + if ((lyr_a[lidx]->right - lyr_a[lidx]->left) > + G_MAXINT32 / MAX (lyr_a[lidx]->bottom - lyr_a[lidx]->top, 1)) + { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + _("Unsupported or invalid layer size: %dx%d"), + lyr_a[lidx]->right - lyr_a[lidx]->left, + lyr_a[lidx]->bottom - lyr_a[lidx]->top); + return NULL; + } + + IFDBG(2) g_debug ("Layer %d, Coords %d %d %d %d, channels %d, ", + lidx, lyr_a[lidx]->left, lyr_a[lidx]->top, + lyr_a[lidx]->right, lyr_a[lidx]->bottom, + lyr_a[lidx]->num_channels); + + lyr_a[lidx]->chn_info = g_new (ChannelLengthInfo, lyr_a[lidx]->num_channels); + + for (cidx = 0; cidx < lyr_a[lidx]->num_channels; ++cidx) + { + if (fread (&lyr_a[lidx]->chn_info[cidx].channel_id, 2, 1, f) < 1 + || fread (&lyr_a[lidx]->chn_info[cidx].data_len, 4, 1, f) < 1) + { + psd_set_error (feof (f), errno, error); + return NULL; + } + lyr_a[lidx]->chn_info[cidx].channel_id = + GINT16_FROM_BE (lyr_a[lidx]->chn_info[cidx].channel_id); + lyr_a[lidx]->chn_info[cidx].data_len = + GUINT32_FROM_BE (lyr_a[lidx]->chn_info[cidx].data_len); + img_a->layer_data_len += lyr_a[lidx]->chn_info[cidx].data_len; + IFDBG(3) g_debug ("Channel ID %d, data len %d", + lyr_a[lidx]->chn_info[cidx].channel_id, + lyr_a[lidx]->chn_info[cidx].data_len); + } + + if (fread (lyr_a[lidx]->mode_key, 4, 1, f) < 1 + || fread (lyr_a[lidx]->blend_mode, 4, 1, f) < 1 + || fread (&lyr_a[lidx]->opacity, 1, 1, f) < 1 + || fread (&lyr_a[lidx]->clipping, 1, 1, f) < 1 + || fread (&lyr_a[lidx]->flags, 1, 1, f) < 1 + || fread (&lyr_a[lidx]->filler, 1, 1, f) < 1 + || fread (&lyr_a[lidx]->extra_len, 4, 1, f) < 1) + { + psd_set_error (feof (f), errno, error); + return NULL; + } + if (memcmp (lyr_a[lidx]->mode_key, "8BIM", 4) != 0) + { + IFDBG(1) g_debug ("Incorrect layer mode signature %.4s", + lyr_a[lidx]->mode_key); + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + _("The file is corrupt!")); + return NULL; + } + + lyr_a[lidx]->layer_flags.trans_prot = lyr_a[lidx]->flags & 1 ? TRUE : FALSE; + lyr_a[lidx]->layer_flags.visible = lyr_a[lidx]->flags & 2 ? FALSE : TRUE; + + if (lyr_a[lidx]->flags & 8) + lyr_a[lidx]->layer_flags.irrelevant = lyr_a[lidx]->flags & 16 ? TRUE : FALSE; + else + lyr_a[lidx]->layer_flags.irrelevant = FALSE; + + lyr_a[lidx]->extra_len = GUINT32_FROM_BE (lyr_a[lidx]->extra_len); + block_rem = lyr_a[lidx]->extra_len; + IFDBG(2) g_debug ("\n\tLayer mode sig: %.4s\n\tBlend mode: %.4s\n\t" + "Opacity: %d\n\tClipping: %d\n\tExtra data len: %d\n\t" + "Alpha lock: %d\n\tVisible: %d\n\tIrrelevant: %d", + lyr_a[lidx]->mode_key, + lyr_a[lidx]->blend_mode, + lyr_a[lidx]->opacity, + lyr_a[lidx]->clipping, + lyr_a[lidx]->extra_len, + lyr_a[lidx]->layer_flags.trans_prot, + lyr_a[lidx]->layer_flags.visible, + lyr_a[lidx]->layer_flags.irrelevant); + IFDBG(3) g_debug ("Remaining length %d", block_rem); + + /* Layer mask data */ + if (fread (&block_len, 4, 1, f) < 1) + { + psd_set_error (feof (f), errno, error); + return NULL; + } + block_len = GUINT32_FROM_BE (block_len); + block_rem -= (block_len + 4); + IFDBG(3) g_debug ("Remaining length %d", block_rem); + + lyr_a[lidx]->layer_mask_extra.top = 0; + lyr_a[lidx]->layer_mask_extra.left = 0; + lyr_a[lidx]->layer_mask_extra.bottom = 0; + lyr_a[lidx]->layer_mask_extra.right = 0; + lyr_a[lidx]->layer_mask.top = 0; + lyr_a[lidx]->layer_mask.left = 0; + lyr_a[lidx]->layer_mask.bottom = 0; + lyr_a[lidx]->layer_mask.right = 0; + lyr_a[lidx]->layer_mask.def_color = 0; + lyr_a[lidx]->layer_mask.extra_def_color = 0; + lyr_a[lidx]->layer_mask.mask_flags.relative_pos = FALSE; + lyr_a[lidx]->layer_mask.mask_flags.disabled = FALSE; + lyr_a[lidx]->layer_mask.mask_flags.invert = FALSE; + + switch (block_len) + { + case 0: + break; + + case 20: + if (fread (&lyr_a[lidx]->layer_mask.top, 4, 1, f) < 1 + || fread (&lyr_a[lidx]->layer_mask.left, 4, 1, f) < 1 + || fread (&lyr_a[lidx]->layer_mask.bottom, 4, 1, f) < 1 + || fread (&lyr_a[lidx]->layer_mask.right, 4, 1, f) < 1 + || fread (&lyr_a[lidx]->layer_mask.def_color, 1, 1, f) < 1 + || fread (&lyr_a[lidx]->layer_mask.flags, 1, 1, f) < 1 + || fread (&lyr_a[lidx]->layer_mask.extra_def_color, 1, 1, f) < 1 + || fread (&lyr_a[lidx]->layer_mask.extra_flags, 1, 1, f) < 1) + { + psd_set_error (feof (f), errno, error); + return NULL; + } + lyr_a[lidx]->layer_mask.top = + GINT32_FROM_BE (lyr_a[lidx]->layer_mask.top); + lyr_a[lidx]->layer_mask.left = + GINT32_FROM_BE (lyr_a[lidx]->layer_mask.left); + lyr_a[lidx]->layer_mask.bottom = + GINT32_FROM_BE (lyr_a[lidx]->layer_mask.bottom); + lyr_a[lidx]->layer_mask.right = + GINT32_FROM_BE (lyr_a[lidx]->layer_mask.right); + lyr_a[lidx]->layer_mask.mask_flags.relative_pos = + lyr_a[lidx]->layer_mask.flags & 1 ? TRUE : FALSE; + lyr_a[lidx]->layer_mask.mask_flags.disabled = + lyr_a[lidx]->layer_mask.flags & 2 ? TRUE : FALSE; + lyr_a[lidx]->layer_mask.mask_flags.invert = + lyr_a[lidx]->layer_mask.flags & 4 ? TRUE : FALSE; + break; + case 36: /* If we have a 36 byte mask record assume second data set is correct */ + if (fread (&lyr_a[lidx]->layer_mask_extra.top, 4, 1, f) < 1 + || fread (&lyr_a[lidx]->layer_mask_extra.left, 4, 1, f) < 1 + || fread (&lyr_a[lidx]->layer_mask_extra.bottom, 4, 1, f) < 1 + || fread (&lyr_a[lidx]->layer_mask_extra.right, 4, 1, f) < 1 + || fread (&lyr_a[lidx]->layer_mask.extra_def_color, 1, 1, f) < 1 + || fread (&lyr_a[lidx]->layer_mask.extra_flags, 1, 1, f) < 1 + || fread (&lyr_a[lidx]->layer_mask.def_color, 1, 1, f) < 1 + || fread (&lyr_a[lidx]->layer_mask.flags, 1, 1, f) < 1 + || fread (&lyr_a[lidx]->layer_mask.top, 4, 1, f) < 1 + || fread (&lyr_a[lidx]->layer_mask.left, 4, 1, f) < 1 + || fread (&lyr_a[lidx]->layer_mask.bottom, 4, 1, f) < 1 + || fread (&lyr_a[lidx]->layer_mask.right, 4, 1, f) < 1) + { + psd_set_error (feof (f), errno, error); + return NULL; + } + lyr_a[lidx]->layer_mask_extra.top = + GINT32_FROM_BE (lyr_a[lidx]->layer_mask_extra.top); + lyr_a[lidx]->layer_mask_extra.left = + GINT32_FROM_BE (lyr_a[lidx]->layer_mask_extra.left); + lyr_a[lidx]->layer_mask_extra.bottom = + GINT32_FROM_BE (lyr_a[lidx]->layer_mask_extra.bottom); + lyr_a[lidx]->layer_mask_extra.right = + GINT32_FROM_BE (lyr_a[lidx]->layer_mask_extra.right); + lyr_a[lidx]->layer_mask.top = + GINT32_FROM_BE (lyr_a[lidx]->layer_mask.top); + lyr_a[lidx]->layer_mask.left = + GINT32_FROM_BE (lyr_a[lidx]->layer_mask.left); + lyr_a[lidx]->layer_mask.bottom = + GINT32_FROM_BE (lyr_a[lidx]->layer_mask.bottom); + lyr_a[lidx]->layer_mask.right = + GINT32_FROM_BE (lyr_a[lidx]->layer_mask.right); + lyr_a[lidx]->layer_mask.mask_flags.relative_pos = + lyr_a[lidx]->layer_mask.flags & 1 ? TRUE : FALSE; + lyr_a[lidx]->layer_mask.mask_flags.disabled = + lyr_a[lidx]->layer_mask.flags & 2 ? TRUE : FALSE; + lyr_a[lidx]->layer_mask.mask_flags.invert = + lyr_a[lidx]->layer_mask.flags & 4 ? TRUE : FALSE; + break; + + default: + IFDBG(1) g_debug ("Unknown layer mask record size ... skipping"); + if (fseek (f, block_len, SEEK_CUR) < 0) + { + psd_set_error (feof (f), errno, error); + return NULL; + } + } + + /* sanity checks */ + if (lyr_a[lidx]->layer_mask.bottom < lyr_a[lidx]->layer_mask.top || + lyr_a[lidx]->layer_mask.bottom - lyr_a[lidx]->layer_mask.top > GIMP_MAX_IMAGE_SIZE) + { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + _("Unsupported or invalid layer mask height: %d"), + lyr_a[lidx]->layer_mask.bottom - lyr_a[lidx]->layer_mask.top); + return NULL; + } + if (lyr_a[lidx]->layer_mask.right < lyr_a[lidx]->layer_mask.left || + lyr_a[lidx]->layer_mask.right - lyr_a[lidx]->layer_mask.left > GIMP_MAX_IMAGE_SIZE) + { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + _("Unsupported or invalid layer mask width: %d"), + lyr_a[lidx]->layer_mask.right - lyr_a[lidx]->layer_mask.left); + return NULL; + } + + if ((lyr_a[lidx]->layer_mask.right - lyr_a[lidx]->layer_mask.left) > + G_MAXINT32 / MAX (lyr_a[lidx]->layer_mask.bottom - lyr_a[lidx]->layer_mask.top, 1)) + { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + _("Unsupported or invalid layer mask size: %dx%d"), + lyr_a[lidx]->layer_mask.right - lyr_a[lidx]->layer_mask.left, + lyr_a[lidx]->layer_mask.bottom - lyr_a[lidx]->layer_mask.top); + return NULL; + } + + IFDBG(2) g_debug ("Layer mask coords %d %d %d %d, Rel pos %d", + lyr_a[lidx]->layer_mask.left, + lyr_a[lidx]->layer_mask.top, + lyr_a[lidx]->layer_mask.right, + lyr_a[lidx]->layer_mask.bottom, + lyr_a[lidx]->layer_mask.mask_flags.relative_pos); + + IFDBG(3) g_debug ("Default mask color, %d, %d", + lyr_a[lidx]->layer_mask.def_color, + lyr_a[lidx]->layer_mask.extra_def_color); + + /* Layer blending ranges */ /* FIXME */ + if (fread (&block_len, 4, 1, f) < 1) + { + psd_set_error (feof (f), errno, error); + return NULL; + } + + block_len = GUINT32_FROM_BE (block_len); + block_rem -= (block_len + 4); + IFDBG(3) g_debug ("Remaining length %d", block_rem); + + if (block_len > 0) + { + if (fseek (f, block_len, SEEK_CUR) < 0) + { + psd_set_error (feof (f), errno, error); + return NULL; + } + } + + lyr_a[lidx]->name = fread_pascal_string (&read_len, &write_len, + 4, f, error); + if (*error) + return NULL; + + block_rem -= read_len; + IFDBG(3) g_debug ("Remaining length %d", block_rem); + + /* Adjustment layer info */ /* FIXME */ + + while (block_rem > 7) + { + if (get_layer_resource_header (&res_a, f, error) < 0) + return NULL; + + block_rem -= 12; + + //Round up to the nearest even byte + while (res_a.data_len % 4 != 0) + res_a.data_len++; + + if (res_a.data_len > block_rem) + { + IFDBG(1) g_debug ("Unexpected end of layer resource data"); + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + _("The file is corrupt!")); + return NULL; + } + + if (load_layer_resource (&res_a, lyr_a[lidx], f, error) < 0) + return NULL; + block_rem -= res_a.data_len; + } + if (block_rem > 0) + { + if (fseek (f, block_rem, SEEK_CUR) < 0) + { + psd_set_error (feof (f), errno, error); + return NULL; + } + } + } + + img_a->layer_data_start = ftell(f); + if (fseek (f, img_a->layer_data_len, SEEK_CUR) < 0) + { + psd_set_error (feof (f), errno, error); + return NULL; + } + + IFDBG(1) g_debug ("Layer image data block size %d", + img_a->layer_data_len); + } + + return lyr_a; +} + + +static PSDlayer ** +read_layer_block (PSDimage *img_a, + FILE *f, + GError **error) +{ + PSDlayer **lyr_a = NULL; + guint32 block_len; + guint32 block_end; + if (fread (&block_len, 4, 1, f) < 1) { psd_set_error (feof (f), errno, error); @@ -499,385 +886,50 @@ read_layer_block (PSDimage *img_a, } else { + guint32 total_len = img_a->mask_layer_len; + img_a->mask_layer_start = ftell (f); block_end = img_a->mask_layer_start + img_a->mask_layer_len; - /* Get number of layers */ - if (fread (&block_len, 4, 1, f) < 1 - || fread (&img_a->num_layers, 2, 1, f) < 1) + /* Layer info */ + if (fread (&block_len, 4, 1, f) == 1 && block_len) { - psd_set_error (feof (f), errno, error); - img_a->num_layers = -1; - return NULL; - } - img_a->num_layers = GINT16_FROM_BE (img_a->num_layers); - IFDBG(2) g_debug ("Number of layers: %d", img_a->num_layers); + block_len = GUINT32_FROM_BE (block_len); + IFDBG(1) g_debug ("Layer info size = %d", block_len); - if (img_a->num_layers < 0) - { - img_a->transparency = TRUE; - img_a->num_layers = -img_a->num_layers; - } + lyr_a = read_layer_info (img_a, f, error); - if (img_a->num_layers) - { - /* Read layer records */ - PSDlayerres res_a; - - /* Create pointer array for the layer records */ - lyr_a = g_new (PSDlayer *, img_a->num_layers); - - for (lidx = 0; lidx < img_a->num_layers; ++lidx) - { - /* Allocate layer record */ - lyr_a[lidx] = (PSDlayer *) g_malloc (sizeof (PSDlayer) ); - - /* Initialise record */ - lyr_a[lidx]->drop = FALSE; - lyr_a[lidx]->id = 0; - lyr_a[lidx]->group_type = 0; - - if (fread (&lyr_a[lidx]->top, 4, 1, f) < 1 - || fread (&lyr_a[lidx]->left, 4, 1, f) < 1 - || fread (&lyr_a[lidx]->bottom, 4, 1, f) < 1 - || fread (&lyr_a[lidx]->right, 4, 1, f) < 1 - || fread (&lyr_a[lidx]->num_channels, 2, 1, f) < 1) - { - psd_set_error (feof (f), errno, error); - return NULL; - } - - lyr_a[lidx]->top = GINT32_FROM_BE (lyr_a[lidx]->top); - lyr_a[lidx]->left = GINT32_FROM_BE (lyr_a[lidx]->left); - lyr_a[lidx]->bottom = GINT32_FROM_BE (lyr_a[lidx]->bottom); - lyr_a[lidx]->right = GINT32_FROM_BE (lyr_a[lidx]->right); - lyr_a[lidx]->num_channels = GUINT16_FROM_BE (lyr_a[lidx]->num_channels); - - if (lyr_a[lidx]->num_channels > MAX_CHANNELS) - { - g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, - _("Too many channels in layer: %d"), - lyr_a[lidx]->num_channels); - return NULL; - } - if (lyr_a[lidx]->bottom < lyr_a[lidx]->top || - lyr_a[lidx]->bottom - lyr_a[lidx]->top > GIMP_MAX_IMAGE_SIZE) - { - g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, - _("Unsupported or invalid layer height: %d"), - lyr_a[lidx]->bottom - lyr_a[lidx]->top); - return NULL; - } - if (lyr_a[lidx]->right < lyr_a[lidx]->left || - lyr_a[lidx]->right - lyr_a[lidx]->left > GIMP_MAX_IMAGE_SIZE) - { - g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, - _("Unsupported or invalid layer width: %d"), - lyr_a[lidx]->right - lyr_a[lidx]->left); - return NULL; - } - - if ((lyr_a[lidx]->right - lyr_a[lidx]->left) > - G_MAXINT32 / MAX (lyr_a[lidx]->bottom - lyr_a[lidx]->top, 1)) - { - g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, - _("Unsupported or invalid layer size: %dx%d"), - lyr_a[lidx]->right - lyr_a[lidx]->left, - lyr_a[lidx]->bottom - lyr_a[lidx]->top); - return NULL; - } - - IFDBG(2) g_debug ("Layer %d, Coords %d %d %d %d, channels %d, ", - lidx, lyr_a[lidx]->left, lyr_a[lidx]->top, - lyr_a[lidx]->right, lyr_a[lidx]->bottom, - lyr_a[lidx]->num_channels); - - lyr_a[lidx]->chn_info = g_new (ChannelLengthInfo, lyr_a[lidx]->num_channels); - - for (cidx = 0; cidx < lyr_a[lidx]->num_channels; ++cidx) - { - if (fread (&lyr_a[lidx]->chn_info[cidx].channel_id, 2, 1, f) < 1 - || fread (&lyr_a[lidx]->chn_info[cidx].data_len, 4, 1, f) < 1) - { - psd_set_error (feof (f), errno, error); - return NULL; - } - lyr_a[lidx]->chn_info[cidx].channel_id = - GINT16_FROM_BE (lyr_a[lidx]->chn_info[cidx].channel_id); - lyr_a[lidx]->chn_info[cidx].data_len = - GUINT32_FROM_BE (lyr_a[lidx]->chn_info[cidx].data_len); - img_a->layer_data_len += lyr_a[lidx]->chn_info[cidx].data_len; - IFDBG(3) g_debug ("Channel ID %d, data len %d", - lyr_a[lidx]->chn_info[cidx].channel_id, - lyr_a[lidx]->chn_info[cidx].data_len); - } - - if (fread (lyr_a[lidx]->mode_key, 4, 1, f) < 1 - || fread (lyr_a[lidx]->blend_mode, 4, 1, f) < 1 - || fread (&lyr_a[lidx]->opacity, 1, 1, f) < 1 - || fread (&lyr_a[lidx]->clipping, 1, 1, f) < 1 - || fread (&lyr_a[lidx]->flags, 1, 1, f) < 1 - || fread (&lyr_a[lidx]->filler, 1, 1, f) < 1 - || fread (&lyr_a[lidx]->extra_len, 4, 1, f) < 1) - { - psd_set_error (feof (f), errno, error); - return NULL; - } - if (memcmp (lyr_a[lidx]->mode_key, "8BIM", 4) != 0) - { - IFDBG(1) g_debug ("Incorrect layer mode signature %.4s", - lyr_a[lidx]->mode_key); - g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, - _("The file is corrupt!")); - return NULL; - } - - lyr_a[lidx]->layer_flags.trans_prot = lyr_a[lidx]->flags & 1 ? TRUE : FALSE; - lyr_a[lidx]->layer_flags.visible = lyr_a[lidx]->flags & 2 ? FALSE : TRUE; - - if (lyr_a[lidx]->flags & 8) - lyr_a[lidx]->layer_flags.irrelevant = lyr_a[lidx]->flags & 16 ? TRUE : FALSE; - else - lyr_a[lidx]->layer_flags.irrelevant = FALSE; - - lyr_a[lidx]->extra_len = GUINT32_FROM_BE (lyr_a[lidx]->extra_len); - block_rem = lyr_a[lidx]->extra_len; - IFDBG(2) g_debug ("\n\tLayer mode sig: %.4s\n\tBlend mode: %.4s\n\t" - "Opacity: %d\n\tClipping: %d\n\tExtra data len: %d\n\t" - "Alpha lock: %d\n\tVisible: %d\n\tIrrelevant: %d", - lyr_a[lidx]->mode_key, - lyr_a[lidx]->blend_mode, - lyr_a[lidx]->opacity, - lyr_a[lidx]->clipping, - lyr_a[lidx]->extra_len, - lyr_a[lidx]->layer_flags.trans_prot, - lyr_a[lidx]->layer_flags.visible, - lyr_a[lidx]->layer_flags.irrelevant); - IFDBG(3) g_debug ("Remaining length %d", block_rem); - - /* Layer mask data */ - if (fread (&block_len, 4, 1, f) < 1) - { - psd_set_error (feof (f), errno, error); - return NULL; - } - block_len = GUINT32_FROM_BE (block_len); - block_rem -= (block_len + 4); - IFDBG(3) g_debug ("Remaining length %d", block_rem); - - lyr_a[lidx]->layer_mask_extra.top = 0; - lyr_a[lidx]->layer_mask_extra.left = 0; - lyr_a[lidx]->layer_mask_extra.bottom = 0; - lyr_a[lidx]->layer_mask_extra.right = 0; - lyr_a[lidx]->layer_mask.top = 0; - lyr_a[lidx]->layer_mask.left = 0; - lyr_a[lidx]->layer_mask.bottom = 0; - lyr_a[lidx]->layer_mask.right = 0; - lyr_a[lidx]->layer_mask.def_color = 0; - lyr_a[lidx]->layer_mask.extra_def_color = 0; - lyr_a[lidx]->layer_mask.mask_flags.relative_pos = FALSE; - lyr_a[lidx]->layer_mask.mask_flags.disabled = FALSE; - lyr_a[lidx]->layer_mask.mask_flags.invert = FALSE; - - switch (block_len) - { - case 0: - break; - - case 20: - if (fread (&lyr_a[lidx]->layer_mask.top, 4, 1, f) < 1 - || fread (&lyr_a[lidx]->layer_mask.left, 4, 1, f) < 1 - || fread (&lyr_a[lidx]->layer_mask.bottom, 4, 1, f) < 1 - || fread (&lyr_a[lidx]->layer_mask.right, 4, 1, f) < 1 - || fread (&lyr_a[lidx]->layer_mask.def_color, 1, 1, f) < 1 - || fread (&lyr_a[lidx]->layer_mask.flags, 1, 1, f) < 1 - || fread (&lyr_a[lidx]->layer_mask.extra_def_color, 1, 1, f) < 1 - || fread (&lyr_a[lidx]->layer_mask.extra_flags, 1, 1, f) < 1) - { - psd_set_error (feof (f), errno, error); - return NULL; - } - lyr_a[lidx]->layer_mask.top = - GINT32_FROM_BE (lyr_a[lidx]->layer_mask.top); - lyr_a[lidx]->layer_mask.left = - GINT32_FROM_BE (lyr_a[lidx]->layer_mask.left); - lyr_a[lidx]->layer_mask.bottom = - GINT32_FROM_BE (lyr_a[lidx]->layer_mask.bottom); - lyr_a[lidx]->layer_mask.right = - GINT32_FROM_BE (lyr_a[lidx]->layer_mask.right); - lyr_a[lidx]->layer_mask.mask_flags.relative_pos = - lyr_a[lidx]->layer_mask.flags & 1 ? TRUE : FALSE; - lyr_a[lidx]->layer_mask.mask_flags.disabled = - lyr_a[lidx]->layer_mask.flags & 2 ? TRUE : FALSE; - lyr_a[lidx]->layer_mask.mask_flags.invert = - lyr_a[lidx]->layer_mask.flags & 4 ? TRUE : FALSE; - break; - case 36: /* If we have a 36 byte mask record assume second data set is correct */ - if (fread (&lyr_a[lidx]->layer_mask_extra.top, 4, 1, f) < 1 - || fread (&lyr_a[lidx]->layer_mask_extra.left, 4, 1, f) < 1 - || fread (&lyr_a[lidx]->layer_mask_extra.bottom, 4, 1, f) < 1 - || fread (&lyr_a[lidx]->layer_mask_extra.right, 4, 1, f) < 1 - || fread (&lyr_a[lidx]->layer_mask.extra_def_color, 1, 1, f) < 1 - || fread (&lyr_a[lidx]->layer_mask.extra_flags, 1, 1, f) < 1 - || fread (&lyr_a[lidx]->layer_mask.def_color, 1, 1, f) < 1 - || fread (&lyr_a[lidx]->layer_mask.flags, 1, 1, f) < 1 - || fread (&lyr_a[lidx]->layer_mask.top, 4, 1, f) < 1 - || fread (&lyr_a[lidx]->layer_mask.left, 4, 1, f) < 1 - || fread (&lyr_a[lidx]->layer_mask.bottom, 4, 1, f) < 1 - || fread (&lyr_a[lidx]->layer_mask.right, 4, 1, f) < 1) - { - psd_set_error (feof (f), errno, error); - return NULL; - } - lyr_a[lidx]->layer_mask_extra.top = - GINT32_FROM_BE (lyr_a[lidx]->layer_mask_extra.top); - lyr_a[lidx]->layer_mask_extra.left = - GINT32_FROM_BE (lyr_a[lidx]->layer_mask_extra.left); - lyr_a[lidx]->layer_mask_extra.bottom = - GINT32_FROM_BE (lyr_a[lidx]->layer_mask_extra.bottom); - lyr_a[lidx]->layer_mask_extra.right = - GINT32_FROM_BE (lyr_a[lidx]->layer_mask_extra.right); - lyr_a[lidx]->layer_mask.top = - GINT32_FROM_BE (lyr_a[lidx]->layer_mask.top); - lyr_a[lidx]->layer_mask.left = - GINT32_FROM_BE (lyr_a[lidx]->layer_mask.left); - lyr_a[lidx]->layer_mask.bottom = - GINT32_FROM_BE (lyr_a[lidx]->layer_mask.bottom); - lyr_a[lidx]->layer_mask.right = - GINT32_FROM_BE (lyr_a[lidx]->layer_mask.right); - lyr_a[lidx]->layer_mask.mask_flags.relative_pos = - lyr_a[lidx]->layer_mask.flags & 1 ? TRUE : FALSE; - lyr_a[lidx]->layer_mask.mask_flags.disabled = - lyr_a[lidx]->layer_mask.flags & 2 ? TRUE : FALSE; - lyr_a[lidx]->layer_mask.mask_flags.invert = - lyr_a[lidx]->layer_mask.flags & 4 ? TRUE : FALSE; - break; - - default: - IFDBG(1) g_debug ("Unknown layer mask record size ... skipping"); - if (fseek (f, block_len, SEEK_CUR) < 0) - { - psd_set_error (feof (f), errno, error); - return NULL; - } - } - - /* sanity checks */ - if (lyr_a[lidx]->layer_mask.bottom < lyr_a[lidx]->layer_mask.top || - lyr_a[lidx]->layer_mask.bottom - lyr_a[lidx]->layer_mask.top > GIMP_MAX_IMAGE_SIZE) - { - g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, - _("Unsupported or invalid layer mask height: %d"), - lyr_a[lidx]->layer_mask.bottom - lyr_a[lidx]->layer_mask.top); - return NULL; - } - if (lyr_a[lidx]->layer_mask.right < lyr_a[lidx]->layer_mask.left || - lyr_a[lidx]->layer_mask.right - lyr_a[lidx]->layer_mask.left > GIMP_MAX_IMAGE_SIZE) - { - g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, - _("Unsupported or invalid layer mask width: %d"), - lyr_a[lidx]->layer_mask.right - lyr_a[lidx]->layer_mask.left); - return NULL; - } - - if ((lyr_a[lidx]->layer_mask.right - lyr_a[lidx]->layer_mask.left) > - G_MAXINT32 / MAX (lyr_a[lidx]->layer_mask.bottom - lyr_a[lidx]->layer_mask.top, 1)) - { - g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, - _("Unsupported or invalid layer mask size: %dx%d"), - lyr_a[lidx]->layer_mask.right - lyr_a[lidx]->layer_mask.left, - lyr_a[lidx]->layer_mask.bottom - lyr_a[lidx]->layer_mask.top); - return NULL; - } - - IFDBG(2) g_debug ("Layer mask coords %d %d %d %d, Rel pos %d", - lyr_a[lidx]->layer_mask.left, - lyr_a[lidx]->layer_mask.top, - lyr_a[lidx]->layer_mask.right, - lyr_a[lidx]->layer_mask.bottom, - lyr_a[lidx]->layer_mask.mask_flags.relative_pos); - - IFDBG(3) g_debug ("Default mask color, %d, %d", - lyr_a[lidx]->layer_mask.def_color, - lyr_a[lidx]->layer_mask.extra_def_color); - - /* Layer blending ranges */ /* FIXME */ - if (fread (&block_len, 4, 1, f) < 1) - { - psd_set_error (feof (f), errno, error); - return NULL; - } - - block_len = GUINT32_FROM_BE (block_len); - block_rem -= (block_len + 4); - IFDBG(3) g_debug ("Remaining length %d", block_rem); - - if (block_len > 0) - { - if (fseek (f, block_len, SEEK_CUR) < 0) - { - psd_set_error (feof (f), errno, error); - return NULL; - } - } - - lyr_a[lidx]->name = fread_pascal_string (&read_len, &write_len, - 4, f, error); - if (*error) - return NULL; - - block_rem -= read_len; - IFDBG(3) g_debug ("Remaining length %d", block_rem); - - /* Adjustment layer info */ /* FIXME */ - - while (block_rem > 7) - { - if (get_layer_resource_header (&res_a, f, error) < 0) - return NULL; - - block_rem -= 12; - - //Round up to the nearest even byte - while (res_a.data_len % 4 != 0) - res_a.data_len++; - - if (res_a.data_len > block_rem) - { - IFDBG(1) g_debug ("Unexpected end of layer resource data"); - g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, - _("The file is corrupt!")); - return NULL; - } - - if (load_layer_resource (&res_a, lyr_a[lidx], f, error) < 0) - return NULL; - block_rem -= res_a.data_len; - } - if (block_rem > 0) - { - if (fseek (f, block_rem, SEEK_CUR) < 0) - { - psd_set_error (feof (f), errno, error); - return NULL; - } - } - } - - img_a->layer_data_start = ftell(f); - if (fseek (f, img_a->layer_data_len, SEEK_CUR) < 0) - { - psd_set_error (feof (f), errno, error); - return NULL; - } - - IFDBG(1) g_debug ("Layer image data block size %d", - img_a->layer_data_len); + total_len -= block_len; } else - lyr_a = NULL; + { + img_a->num_layers = 0; + lyr_a = NULL; + } - /* Read global layer mask record */ /* FIXME */ + /* Global layer mask info */ + if (fread (&block_len, 4, 1, f) == 1 && block_len) + { + block_len = GUINT32_FROM_BE (block_len); + IFDBG(1) g_debug ("Global layer mask info size = %d", block_len); + + /* read_global_layer_mask_info (img_a, f, error); */ + fseek (f, block_len, SEEK_CUR); + + total_len -= block_len; + } + + /* Additional Layer Information */ + if (total_len > 12) + { + gchar signature_key[8]; + + if (fread (&signature_key, 4, 2, f) == 2 && + (memcmp (signature_key, "8BIMLr16", 8) == 0 || + memcmp (signature_key, "8BIMLr32", 8) == 0) && + fread (&block_len, 4, 1, f) == 1 && block_len) + lyr_a = read_layer_info (img_a, f, error); + } /* Skip to end of block */ if (fseek (f, block_end, SEEK_SET) < 0) @@ -1242,7 +1294,7 @@ add_layers (gint32 image_id, IFDBG(3) g_debug ("Raw data length: %d", lyr_a[lidx]->chn_info[cidx].data_len - 2); if (read_channel_data (lyr_chn[cidx], img_a->bps, - PSD_COMP_RAW, NULL, f, + PSD_COMP_RAW, NULL, f, 0, error) < 1) return -1; break; @@ -1268,7 +1320,7 @@ add_layers (gint32 image_id, IFDBG(3) g_debug ("RLE decode - data"); if (read_channel_data (lyr_chn[cidx], img_a->bps, - PSD_COMP_RLE, rle_pack_len, f, + PSD_COMP_RLE, rle_pack_len, f, 0, error) < 1) return -1; @@ -1277,6 +1329,13 @@ add_layers (gint32 image_id, case PSD_COMP_ZIP: /* ? */ case PSD_COMP_ZIP_PRED: + if (read_channel_data (lyr_chn[cidx], img_a->bps, + comp_mode, NULL, f, + lyr_a[lidx]->chn_info[cidx].data_len - 2, + error) < 1) + return -1; + break; + default: g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Unsupported compression mode: %d"), comp_mode); @@ -1456,7 +1515,8 @@ add_layers (gint32 image_id, IFDBG(3) g_debug ("Mask channel index %d", user_mask_chn); IFDBG(3) g_debug ("Relative pos %d", lyr_a[lidx]->layer_mask.mask_flags.relative_pos); - layer_size = lm_w * lm_h; + bps = (img_a->bps + 1) / 8; + layer_size = lm_w * lm_h * bps; pixels = g_malloc (layer_size); IFDBG(3) g_debug ("Allocate Pixels %d", layer_size); /* Crop mask at layer boundary */ @@ -1480,8 +1540,7 @@ add_layers (gint32 image_id, { if (coli + lm_x >= 0 && coli + lm_x < l_w) { - pixels[i] = - lyr_chn[user_mask_chn]->data[(rowi * lm_w) + coli]; + memcpy (&pixels[i * bps], &lyr_chn[user_mask_chn]->data[(rowi * lm_w + coli) * bps], bps); i++; } } @@ -1637,7 +1696,7 @@ add_merged_image (gint32 image_id, chn_a[cidx].columns = img_a->columns; chn_a[cidx].rows = img_a->rows; if (read_channel_data (&chn_a[cidx], img_a->bps, - PSD_COMP_RAW, NULL, f, + PSD_COMP_RAW, NULL, f, 0, error) < 1) return -1; } @@ -1669,7 +1728,7 @@ add_merged_image (gint32 image_id, for (cidx = 0; cidx < total_channels; ++cidx) { if (read_channel_data (&chn_a[cidx], img_a->bps, - PSD_COMP_RLE, rle_pack_len[cidx], f, + PSD_COMP_RLE, rle_pack_len[cidx], f, 0, error) < 1) return -1; g_free (rle_pack_len[cidx]); @@ -1922,19 +1981,33 @@ get_gimp_image_type (GimpImageBaseType image_base_type, return image_type; } +static voidpf +zzalloc (voidpf opaque, uInt items, uInt size) +{ + /* overflow check missing */ + return g_malloc (items * size); +} + +static void +zzfree (voidpf opaque, voidpf address) +{ + g_free (address); +} + static gint read_channel_data (PSDchannel *channel, guint16 bps, guint16 compression, const guint16 *rle_pack_len, FILE *f, + guint16 comp_len, GError **error) { gchar *raw_data; gchar *src; gchar *dst; guint32 readline_len; - gint i; + gint i, j; if (bps == 1) readline_len = ((channel->columns + 7) / 8); @@ -1990,16 +2063,94 @@ read_channel_data (PSDchannel *channel, g_free (dst); } break; + case PSD_COMP_ZIP: + case PSD_COMP_ZIP_PRED: + { + z_stream zs; + + src = g_malloc (comp_len); + if (fread (src, comp_len, 1, f) < 1) + { + psd_set_error (feof (f), errno, error); + g_free (src); + return -1; + } + + zs.next_in = (guchar*) src; + zs.avail_in = comp_len; + zs.next_out = (guchar*) raw_data; + zs.avail_out = readline_len * channel->rows; + zs.zalloc = zzalloc; + zs.zfree = zzfree; + + if (inflateInit (&zs) == Z_OK && + inflate (&zs, Z_FINISH) == Z_STREAM_END) + { + inflateEnd (&zs); + } + else + { + psd_set_error (feof (f), errno, error); + g_free (src); + return -1; + } + + g_free (src); + break; + } } /* Convert channel data to GIMP format */ switch (bps) { - case 32: - case 16: + case 32: + { + guint32 *src = (guint32*) raw_data; + guint32 *dst = g_malloc (channel->rows * channel->columns * 4); + + channel->data = (gchar*) dst; + + for (i = 0; i < channel->rows * channel->columns; ++i) + dst[i] = GUINT32_FROM_BE (src[i]); + + if (compression == PSD_COMP_ZIP_PRED) + { + for (i = 0; i < channel->rows; ++i) + for (j = 1; j < channel->columns; ++j) + dst[i * channel->columns + j] += dst[i * channel->columns + j - 1]; + } + break; + } + + case 16: + { + guint16 *src = (guint16*) raw_data; + guint16 *dst = g_malloc (channel->rows * channel->columns * 2); + + channel->data = (gchar*) dst; + + for (i = 0; i < channel->rows * channel->columns; ++i) + dst[i] = GUINT16_FROM_BE (src[i]); + + if (compression == PSD_COMP_ZIP_PRED) + { + for (i = 0; i < channel->rows; ++i) + for (j = 1; j < channel->columns; ++j) + dst[i * channel->columns + j] += dst[i * channel->columns + j - 1]; + } + break; + } + case 8: - channel->data = (gchar *) g_malloc (channel->rows * channel->columns * bps / 8 ); + channel->data = g_malloc (channel->rows * channel->columns * bps / 8 ); memcpy (channel->data, raw_data, (channel->rows * channel->columns * bps / 8)); + + if (compression == PSD_COMP_ZIP_PRED) + { + for (i = 0; i < channel->rows; ++i) + for (j = 1; j < channel->columns; ++j) + channel->data[i * channel->columns + j] += channel->data[i * channel->columns + j - 1]; + } break; case 1: