[gimp] Bug 738329 - xcf_seek_pos() can cause unexpected OS behavior
- From: Michael Natterer <mitch src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] Bug 738329 - xcf_seek_pos() can cause unexpected OS behavior
- Date: Sat, 18 Oct 2014 16:29:05 +0000 (UTC)
commit 5a4d865358818fdbae203716bd6e33f86f5905c6
Author: Michael Natterer <mitch gimp org>
Date: Fri Oct 17 19:12:05 2014 +0200
Bug 738329 - xcf_seek_pos() can cause unexpected OS behavior
Change XCF saving to never seek past the end of the partially written
file. The only places where we still did this was when skipping the
offset tables for layers, channels, levels and tiles.
Now we write an all-zero offset table first, and then only seek around
in areas of the file that already exist. This also simplifies the code
a bit. Changed comments to make it clear what happens.
app/xcf/xcf-save.c | 132 ++++++++++++++++++++++++++++-----------------------
app/xcf/xcf-write.c | 17 +++++++
app/xcf/xcf-write.h | 35 +++++++------
3 files changed, 109 insertions(+), 75 deletions(-)
---
diff --git a/app/xcf/xcf-save.c b/app/xcf/xcf-save.c
index b1c4cff..c0383e9 100644
--- a/app/xcf/xcf-save.c
+++ b/app/xcf/xcf-save.c
@@ -139,6 +139,15 @@ static gboolean xcf_save_vectors (XcfInfo *info,
} \
} G_STMT_END
+#define xcf_write_zero_int32_check_error(info, count) G_STMT_START { \
+ info->cp += xcf_write_zero_int32 (info->output, count, &tmp_error); \
+ if (tmp_error) \
+ { \
+ g_propagate_error (error, tmp_error); \
+ return FALSE; \
+ } \
+ } G_STMT_END
+
#define xcf_write_int8_check_error(info, data, count) G_STMT_START { \
info->cp += xcf_write_int8 (info->output, data, count, &tmp_error); \
if (tmp_error) \
@@ -185,9 +194,6 @@ static gboolean xcf_save_vectors (XcfInfo *info,
} G_STMT_END
-static const guint32 zero = 0;
-
-
gboolean
xcf_save_image (XcfInfo *info,
GimpImage *image,
@@ -258,19 +264,26 @@ xcf_save_image (XcfInfo *info,
xcf_progress_update (info);
- /* 'offset' is where we will write the next layer or channel, which
- * is after the offset table
- */
- offset = info->cp + (n_layers + n_channels + 2) * 4;
+ /* 'saved_pos' is the next slot in the offset table */
+ saved_pos = info->cp;
+
+ /* write an empty offset table */
+ xcf_write_zero_int32_check_error (info, n_layers + n_channels + 2);
+
+ /* 'offset' is where we will write the next layer or channel */
+ offset = info->cp;
for (list = all_layers; list; list = g_list_next (list))
{
GimpLayer *layer = list->data;
- /* write the offset of the layer */
+ /* seek back to the next slot in the offset table and write the
+ * offset of the layer
+ */
+ xcf_check_error (xcf_seek_pos (info, saved_pos, error));
xcf_write_int32_check_error (info, &offset, 1);
- /* 'saved_pos' is the next slot in the layer offset table */
+ /* remember the next slot in the offset table */
saved_pos = info->cp;
/* seek to the layer offset and save the layer */
@@ -280,40 +293,40 @@ xcf_save_image (XcfInfo *info,
/* the next layer's offset is after the layer we just wrote */
offset = info->cp;
- /* seek back to the next slot in the offset table */
- xcf_check_error (xcf_seek_pos (info, saved_pos, error));
-
xcf_progress_update (info);
}
- /* write out a '0' offset to indicate the end of the layer offsets */
- xcf_write_int32_check_error (info, &zero, 1);
+ /* skip a '0' in the offset table to indicate the end of the layer
+ * offsets
+ */
+ saved_pos += 4;
for (list = all_channels; list; list = g_list_next (list))
{
GimpChannel *channel = list->data;
- /* write the offset of the channel */
+ /* seek back to the next slot in the offset table and write the
+ * offset of the channel
+ */
+ xcf_check_error (xcf_seek_pos (info, saved_pos, error));
xcf_write_int32_check_error (info, &offset, 1);
- /* 'saved_pos' is the next slot in the channel offset table */
+ /* remember the next slot in the offset table */
saved_pos = info->cp;
/* seek to the channel offset and save the channel */
xcf_check_error (xcf_seek_pos (info, offset, error));
xcf_check_error (xcf_save_channel (info, image, channel, error));
- /* the next channels's offset is after the layer we just wrote */
+ /* the next channels's offset is after the channel we just wrote */
offset = info->cp;
- /* seek back to the next slot in the offset table */
- xcf_check_error (xcf_seek_pos (info, saved_pos, error));
-
xcf_progress_update (info);
}
- /* write out a '0' offset to indicate the end of the channel offsets */
- xcf_write_int32_check_error (info, &zero, 1);
+ /* there is already a '0' at the end of the offset table to indicate
+ * the end of the channel offsets
+ */
g_list_free (all_layers);
g_list_free (all_channels);
@@ -1161,36 +1174,33 @@ xcf_save_layer (XcfInfo *info,
/* write out the layer properties */
xcf_save_layer_props (info, image, layer, error);
- /* write out the layer tile hierarchy */
+ /* write out the layer tile hierarchy */
offset = info->cp + 8;
xcf_write_int32_check_error (info, &offset, 1);
saved_pos = info->cp;
- xcf_check_error (xcf_seek_pos (info, offset, error));
+
+ /* write a zero layer mask offset */
+ xcf_write_zero_int32_check_error (info, 1);
xcf_check_error (xcf_save_buffer (info,
gimp_drawable_get_buffer (GIMP_DRAWABLE (layer)),
error));
offset = info->cp;
- xcf_check_error (xcf_seek_pos (info, saved_pos, error));
/* write out the layer mask */
if (gimp_layer_get_mask (layer))
{
GimpLayerMask *mask = gimp_layer_get_mask (layer);
+ xcf_check_error (xcf_seek_pos (info, saved_pos, error));
xcf_write_int32_check_error (info, &offset, 1);
- xcf_check_error (xcf_seek_pos (info, offset, error));
+ xcf_check_error (xcf_seek_pos (info, offset, error));
xcf_check_error (xcf_save_channel (info, image, GIMP_CHANNEL (mask),
error));
}
- else
- {
- xcf_write_int32_check_error (info, &zero, 1);
- xcf_check_error (xcf_seek_pos (info, offset, error));
- }
return TRUE;
}
@@ -1292,17 +1302,24 @@ xcf_save_buffer (XcfInfo *info,
tmp2 = xcf_calc_levels (height, XCF_TILE_HEIGHT);
nlevels = MAX (tmp1, tmp2);
- /* 'offset' is where we will save the next level, which is after the
- * level offset table
- */
- offset = info->cp + (1 + nlevels) * 4;
+ /* 'saved_pos' is the next slot in the offset table */
+ saved_pos = info->cp;
+
+ /* write an empty offset table */
+ xcf_write_zero_int32_check_error (info, nlevels + 1);
+
+ /* 'offset' is where we will write the next level */
+ offset = info->cp;
for (i = 0; i < nlevels; i++)
{
- /* write the offset of the level */
+ /* seek back to the next slot in the offset table and write the
+ * offset of the level
+ */
+ xcf_check_error (xcf_seek_pos (info, saved_pos, error));
xcf_write_int32_check_error (info, &offset, 1);
- /* 'saved_pos' is the next slot in the level offset table */
+ /* remember the next slot in the offset table */
saved_pos = info->cp;
/* seek to the level offset and save the level */
@@ -1326,16 +1343,11 @@ xcf_save_buffer (XcfInfo *info,
/* the next level's offset if after the level we just wrote */
offset = info->cp;
-
- /* seek back to the next slot in the offset table */
- xcf_check_error (xcf_seek_pos (info, saved_pos, error));
}
- /* write out a '0' offset to indicate the end of the level offsets */
- xcf_write_int32_check_error (info, &zero, 1);
-
- /* seek to after the last level we just wrote */
- xcf_check_error (xcf_seek_pos (info, offset, error));
+ /* there is already a '0' at the end of the offset table to indicate
+ * the end of the level offsets
+ */
return TRUE;
}
@@ -1380,19 +1392,26 @@ xcf_save_level (XcfInfo *info,
ntiles = n_tile_rows * n_tile_cols;
- /* 'offset' is where we will write the next tile, which is after the
- * tile offset table
- */
- offset = info->cp + (ntiles + 1) * 4;
+ /* 'saved_pos' is the next slot in the offset table */
+ saved_pos = info->cp;
+
+ /* write an empty offset table */
+ xcf_write_zero_int32_check_error (info, ntiles + 1);
+
+ /* 'offset' is where we will write the next tile */
+ offset = info->cp;
for (i = 0; i < ntiles; i++)
{
GeglRectangle rect;
- /* write the offset of the tile */
+ /* seek back to the next slot in the offset table and write the
+ * offset of the tile
+ */
+ xcf_check_error (xcf_seek_pos (info, saved_pos, error));
xcf_write_int32_check_error (info, &offset, 1);
- /* 'saved_pos' is the next slot in the tile offset table */
+ /* remember the next slot in the offset table */
saved_pos = info->cp;
/* seek to the tile offset and save the tile */
@@ -1424,16 +1443,11 @@ xcf_save_level (XcfInfo *info,
/* the next tile's offset is after the tile we just wrote */
offset = info->cp;
-
- /* seek back to the next slot in the offset table */
- xcf_check_error (xcf_seek_pos (info, saved_pos, error));
}
- /* write out a '0' offset to indicate the end of the tile offsets */
- xcf_write_int32_check_error (info, &zero, 1);
-
- /* seek to after the last tile we just wrote */
- xcf_check_error (xcf_seek_pos (info, offset, error));
+ /* there is already a '0' at the end of the offset table to indicate
+ * the end of the tile offsets
+ */
return TRUE;
}
diff --git a/app/xcf/xcf-write.c b/app/xcf/xcf-write.c
index 2574cde..8360027 100644
--- a/app/xcf/xcf-write.c
+++ b/app/xcf/xcf-write.c
@@ -56,6 +56,23 @@ xcf_write_int32 (GOutputStream *output,
}
guint
+xcf_write_zero_int32 (GOutputStream *output,
+ gint count,
+ GError **error)
+{
+ if (count > 0)
+ {
+ guint32 *tmp = g_alloca (count * 4);
+
+ memset (tmp, 0, count * 4);
+
+ return xcf_write_int8 (output, (const guint8 *) tmp, count * 4, error);
+ }
+
+ return 0;
+}
+
+guint
xcf_write_float (GOutputStream *output,
const gfloat *data,
gint count,
diff --git a/app/xcf/xcf-write.h b/app/xcf/xcf-write.h
index cf5c5f8..ef46646 100644
--- a/app/xcf/xcf-write.h
+++ b/app/xcf/xcf-write.h
@@ -19,22 +19,25 @@
#define __XCF_WRITE_H__
-guint xcf_write_int32 (GOutputStream *output,
- const guint32 *data,
- gint count,
- GError **error);
-guint xcf_write_float (GOutputStream *output,
- const gfloat *data,
- gint count,
- GError **error);
-guint xcf_write_int8 (GOutputStream *output,
- const guint8 *data,
- gint count,
- GError **error);
-guint xcf_write_string (GOutputStream *output,
- gchar **data,
- gint count,
- GError **error);
+guint xcf_write_int32 (GOutputStream *output,
+ const guint32 *data,
+ gint count,
+ GError **error);
+guint xcf_write_zero_int32 (GOutputStream *output,
+ gint count,
+ GError **error);
+guint xcf_write_float (GOutputStream *output,
+ const gfloat *data,
+ gint count,
+ GError **error);
+guint xcf_write_int8 (GOutputStream *output,
+ const guint8 *data,
+ gint count,
+ GError **error);
+guint xcf_write_string (GOutputStream *output,
+ gchar **data,
+ gint count,
+ GError **error);
#endif /* __XCF_WRITE_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]