[gimp/osx-build: 55/55] Bug 730211-Load XCF files with shifted layer offset table
- From: Sven Claussner <sclaussner src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/osx-build: 55/55] Bug 730211-Load XCF files with shifted layer offset table
- Date: Sun, 20 Jul 2014 19:14:36 +0000 (UTC)
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]