mirror of https://github.com/GNOME/gimp.git
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.
This commit is contained in:
parent
0d435f11b7
commit
5a4d865358
|
@ -139,6 +139,15 @@ static gboolean xcf_save_vectors (XcfInfo *info,
|
||||||
} \
|
} \
|
||||||
} G_STMT_END
|
} 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 { \
|
#define xcf_write_int8_check_error(info, data, count) G_STMT_START { \
|
||||||
info->cp += xcf_write_int8 (info->output, data, count, &tmp_error); \
|
info->cp += xcf_write_int8 (info->output, data, count, &tmp_error); \
|
||||||
if (tmp_error) \
|
if (tmp_error) \
|
||||||
|
@ -185,9 +194,6 @@ static gboolean xcf_save_vectors (XcfInfo *info,
|
||||||
} G_STMT_END
|
} G_STMT_END
|
||||||
|
|
||||||
|
|
||||||
static const guint32 zero = 0;
|
|
||||||
|
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
xcf_save_image (XcfInfo *info,
|
xcf_save_image (XcfInfo *info,
|
||||||
GimpImage *image,
|
GimpImage *image,
|
||||||
|
@ -258,19 +264,26 @@ xcf_save_image (XcfInfo *info,
|
||||||
|
|
||||||
xcf_progress_update (info);
|
xcf_progress_update (info);
|
||||||
|
|
||||||
/* 'offset' is where we will write the next layer or channel, which
|
/* 'saved_pos' is the next slot in the offset table */
|
||||||
* is after the offset table
|
saved_pos = info->cp;
|
||||||
*/
|
|
||||||
offset = info->cp + (n_layers + n_channels + 2) * 4;
|
/* 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))
|
for (list = all_layers; list; list = g_list_next (list))
|
||||||
{
|
{
|
||||||
GimpLayer *layer = list->data;
|
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);
|
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;
|
saved_pos = info->cp;
|
||||||
|
|
||||||
/* seek to the layer offset and save the layer */
|
/* 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 */
|
/* the next layer's offset is after the layer we just wrote */
|
||||||
offset = info->cp;
|
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);
|
xcf_progress_update (info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write out a '0' offset to indicate the end of the layer offsets */
|
/* skip a '0' in the offset table to indicate the end of the layer
|
||||||
xcf_write_int32_check_error (info, &zero, 1);
|
* offsets
|
||||||
|
*/
|
||||||
|
saved_pos += 4;
|
||||||
|
|
||||||
for (list = all_channels; list; list = g_list_next (list))
|
for (list = all_channels; list; list = g_list_next (list))
|
||||||
{
|
{
|
||||||
GimpChannel *channel = list->data;
|
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);
|
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;
|
saved_pos = info->cp;
|
||||||
|
|
||||||
/* seek to the channel offset and save the channel */
|
/* seek to the channel offset and save the channel */
|
||||||
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, channel, 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;
|
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);
|
xcf_progress_update (info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write out a '0' offset to indicate the end of the channel offsets */
|
/* there is already a '0' at the end of the offset table to indicate
|
||||||
xcf_write_int32_check_error (info, &zero, 1);
|
* the end of the channel offsets
|
||||||
|
*/
|
||||||
|
|
||||||
g_list_free (all_layers);
|
g_list_free (all_layers);
|
||||||
g_list_free (all_channels);
|
g_list_free (all_channels);
|
||||||
|
@ -1166,31 +1179,28 @@ xcf_save_layer (XcfInfo *info,
|
||||||
xcf_write_int32_check_error (info, &offset, 1);
|
xcf_write_int32_check_error (info, &offset, 1);
|
||||||
|
|
||||||
saved_pos = info->cp;
|
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,
|
xcf_check_error (xcf_save_buffer (info,
|
||||||
gimp_drawable_get_buffer (GIMP_DRAWABLE (layer)),
|
gimp_drawable_get_buffer (GIMP_DRAWABLE (layer)),
|
||||||
error));
|
error));
|
||||||
|
|
||||||
offset = info->cp;
|
offset = info->cp;
|
||||||
xcf_check_error (xcf_seek_pos (info, saved_pos, error));
|
|
||||||
|
|
||||||
/* write out the layer mask */
|
/* write out the layer mask */
|
||||||
if (gimp_layer_get_mask (layer))
|
if (gimp_layer_get_mask (layer))
|
||||||
{
|
{
|
||||||
GimpLayerMask *mask = 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_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),
|
xcf_check_error (xcf_save_channel (info, image, GIMP_CHANNEL (mask),
|
||||||
error));
|
error));
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
xcf_write_int32_check_error (info, &zero, 1);
|
|
||||||
xcf_check_error (xcf_seek_pos (info, offset, error));
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -1292,17 +1302,24 @@ xcf_save_buffer (XcfInfo *info,
|
||||||
tmp2 = xcf_calc_levels (height, XCF_TILE_HEIGHT);
|
tmp2 = xcf_calc_levels (height, XCF_TILE_HEIGHT);
|
||||||
nlevels = MAX (tmp1, tmp2);
|
nlevels = MAX (tmp1, tmp2);
|
||||||
|
|
||||||
/* 'offset' is where we will save the next level, which is after the
|
/* 'saved_pos' is the next slot in the offset table */
|
||||||
* level offset table
|
saved_pos = info->cp;
|
||||||
*/
|
|
||||||
offset = info->cp + (1 + nlevels) * 4;
|
/* 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++)
|
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);
|
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;
|
saved_pos = info->cp;
|
||||||
|
|
||||||
/* seek to the level offset and save the level */
|
/* 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 */
|
/* the next level's offset if after the level we just wrote */
|
||||||
offset = info->cp;
|
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 */
|
/* there is already a '0' at the end of the offset table to indicate
|
||||||
xcf_write_int32_check_error (info, &zero, 1);
|
* the end of the level offsets
|
||||||
|
*/
|
||||||
/* seek to after the last level we just wrote */
|
|
||||||
xcf_check_error (xcf_seek_pos (info, offset, error));
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -1380,19 +1392,26 @@ xcf_save_level (XcfInfo *info,
|
||||||
|
|
||||||
ntiles = n_tile_rows * n_tile_cols;
|
ntiles = n_tile_rows * n_tile_cols;
|
||||||
|
|
||||||
/* 'offset' is where we will write the next tile, which is after the
|
/* 'saved_pos' is the next slot in the offset table */
|
||||||
* tile offset table
|
saved_pos = info->cp;
|
||||||
*/
|
|
||||||
offset = info->cp + (ntiles + 1) * 4;
|
/* 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++)
|
for (i = 0; i < ntiles; i++)
|
||||||
{
|
{
|
||||||
GeglRectangle rect;
|
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);
|
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;
|
saved_pos = info->cp;
|
||||||
|
|
||||||
/* seek to the tile offset and save the tile */
|
/* 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 */
|
/* the next tile's offset is after the tile we just wrote */
|
||||||
offset = info->cp;
|
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 */
|
/* there is already a '0' at the end of the offset table to indicate
|
||||||
xcf_write_int32_check_error (info, &zero, 1);
|
* the end of the tile offsets
|
||||||
|
*/
|
||||||
/* seek to after the last tile we just wrote */
|
|
||||||
xcf_check_error (xcf_seek_pos (info, offset, error));
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,23 @@ xcf_write_int32 (GOutputStream *output,
|
||||||
return count * 4;
|
return count * 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
guint
|
||||||
xcf_write_float (GOutputStream *output,
|
xcf_write_float (GOutputStream *output,
|
||||||
const gfloat *data,
|
const gfloat *data,
|
||||||
|
|
|
@ -23,6 +23,9 @@ guint xcf_write_int32 (GOutputStream *output,
|
||||||
const guint32 *data,
|
const guint32 *data,
|
||||||
gint count,
|
gint count,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
guint xcf_write_zero_int32 (GOutputStream *output,
|
||||||
|
gint count,
|
||||||
|
GError **error);
|
||||||
guint xcf_write_float (GOutputStream *output,
|
guint xcf_write_float (GOutputStream *output,
|
||||||
const gfloat *data,
|
const gfloat *data,
|
||||||
gint count,
|
gint count,
|
||||||
|
|
Loading…
Reference in New Issue