Bug 731390 - XCF files have a max size of 4G
Step one, without changing anything in the saved XCFs yet: Abstract reading and writing of file offsets away into their own xcf_read_offset() and xcf_write_offset() functions, which take "goffset" instead of "guint32". Also change xcf_seek_pos() to take a goffset argument. Change all file offset variables in xcf-load.c, xcf-write.c and struct XcfInfo to goffset, and add new member "bytes_per_offset" to XcfInfo, which is currently always 4.
This commit is contained in:
parent
f861585051
commit
a0a5f714bb
10 changed files with 196 additions and 118 deletions
|
|
@ -150,8 +150,8 @@ xcf_load_image (Gimp *gimp,
|
|||
GimpImage *image = NULL;
|
||||
const GimpParasite *parasite;
|
||||
gboolean has_metadata = FALSE;
|
||||
guint32 saved_pos;
|
||||
guint32 offset;
|
||||
goffset saved_pos;
|
||||
goffset offset;
|
||||
gint width;
|
||||
gint height;
|
||||
gint image_type;
|
||||
|
|
@ -393,7 +393,7 @@ xcf_load_image (Gimp *gimp,
|
|||
GList *item_path = NULL;
|
||||
|
||||
/* read in the offset of the next layer */
|
||||
info->cp += xcf_read_int32 (info->input, &offset, 1);
|
||||
info->cp += xcf_read_offset (info->input, &offset, 1);
|
||||
|
||||
/* if the offset is 0 then we are at the end
|
||||
* of the layer list.
|
||||
|
|
@ -477,7 +477,7 @@ xcf_load_image (Gimp *gimp,
|
|||
GimpChannel *channel;
|
||||
|
||||
/* read in the offset of the next channel */
|
||||
info->cp += xcf_read_int32 (info->input, &offset, 1);
|
||||
info->cp += xcf_read_offset (info->input, &offset, 1);
|
||||
|
||||
/* if the offset is 0 then we are at the end
|
||||
* of the channel list.
|
||||
|
|
@ -801,7 +801,7 @@ xcf_load_image_props (XcfInfo *info,
|
|||
|
||||
case PROP_PARASITES:
|
||||
{
|
||||
glong base = info->cp;
|
||||
goffset base = info->cp;
|
||||
|
||||
while (info->cp - base < prop_size)
|
||||
{
|
||||
|
|
@ -912,14 +912,14 @@ xcf_load_image_props (XcfInfo *info,
|
|||
|
||||
case PROP_VECTORS:
|
||||
{
|
||||
guint32 base = info->cp;
|
||||
goffset base = info->cp;
|
||||
|
||||
if (xcf_load_vectors (info, image))
|
||||
{
|
||||
if (base + prop_size != info->cp)
|
||||
{
|
||||
g_printerr ("Mismatch in PROP_VECTORS size: "
|
||||
"skipping %d bytes.\n",
|
||||
"skipping " G_GOFFSET_FORMAT " bytes.\n",
|
||||
base + prop_size - info->cp);
|
||||
xcf_seek_pos (info, base + prop_size, NULL);
|
||||
}
|
||||
|
|
@ -978,9 +978,8 @@ xcf_load_layer_props (XcfInfo *info,
|
|||
|
||||
case PROP_FLOATING_SELECTION:
|
||||
info->floating_sel = *layer;
|
||||
info->cp +=
|
||||
xcf_read_int32 (info->input,
|
||||
(guint32 *) &info->floating_sel_offset, 1);
|
||||
info->cp += xcf_read_offset (info->input,
|
||||
&info->floating_sel_offset, 1);
|
||||
break;
|
||||
|
||||
case PROP_OPACITY:
|
||||
|
|
@ -1147,7 +1146,7 @@ xcf_load_layer_props (XcfInfo *info,
|
|||
|
||||
case PROP_PARASITES:
|
||||
{
|
||||
glong base = info->cp;
|
||||
goffset base = info->cp;
|
||||
|
||||
while (info->cp - base < prop_size)
|
||||
{
|
||||
|
|
@ -1220,8 +1219,8 @@ xcf_load_layer_props (XcfInfo *info,
|
|||
|
||||
case PROP_ITEM_PATH:
|
||||
{
|
||||
glong base = info->cp;
|
||||
GList *path = NULL;
|
||||
goffset base = info->cp;
|
||||
GList *path = NULL;
|
||||
|
||||
while (info->cp - base < prop_size)
|
||||
{
|
||||
|
|
@ -1408,7 +1407,7 @@ xcf_load_channel_props (XcfInfo *info,
|
|||
|
||||
case PROP_PARASITES:
|
||||
{
|
||||
glong base = info->cp;
|
||||
goffset base = info->cp;
|
||||
|
||||
while ((info->cp - base) < prop_size)
|
||||
{
|
||||
|
|
@ -1481,8 +1480,8 @@ xcf_load_layer (XcfInfo *info,
|
|||
{
|
||||
GimpLayer *layer;
|
||||
GimpLayerMask *layer_mask;
|
||||
guint32 hierarchy_offset;
|
||||
guint32 layer_mask_offset;
|
||||
goffset hierarchy_offset;
|
||||
goffset layer_mask_offset;
|
||||
gboolean apply_mask = TRUE;
|
||||
gboolean edit_mask = FALSE;
|
||||
gboolean show_mask = FALSE;
|
||||
|
|
@ -1592,8 +1591,8 @@ xcf_load_layer (XcfInfo *info,
|
|||
}
|
||||
|
||||
/* read the hierarchy and layer mask offsets */
|
||||
info->cp += xcf_read_int32 (info->input, &hierarchy_offset, 1);
|
||||
info->cp += xcf_read_int32 (info->input, &layer_mask_offset, 1);
|
||||
info->cp += xcf_read_offset (info->input, &hierarchy_offset, 1);
|
||||
info->cp += xcf_read_offset (info->input, &layer_mask_offset, 1);
|
||||
|
||||
/* read in the hierarchy (ignore it for group layers, both as an
|
||||
* optimization and because the hierarchy's extents don't match
|
||||
|
|
@ -1664,7 +1663,7 @@ xcf_load_channel (XcfInfo *info,
|
|||
GimpImage *image)
|
||||
{
|
||||
GimpChannel *channel;
|
||||
guint32 hierarchy_offset;
|
||||
goffset hierarchy_offset;
|
||||
gint width;
|
||||
gint height;
|
||||
gboolean is_fs_drawable;
|
||||
|
|
@ -1697,7 +1696,7 @@ xcf_load_channel (XcfInfo *info,
|
|||
xcf_progress_update (info);
|
||||
|
||||
/* read the hierarchy and layer mask offsets */
|
||||
info->cp += xcf_read_int32 (info->input, &hierarchy_offset, 1);
|
||||
info->cp += xcf_read_offset (info->input, &hierarchy_offset, 1);
|
||||
|
||||
/* read in the hierarchy */
|
||||
if (!xcf_seek_pos (info, hierarchy_offset, NULL))
|
||||
|
|
@ -1725,7 +1724,7 @@ xcf_load_layer_mask (XcfInfo *info,
|
|||
{
|
||||
GimpLayerMask *layer_mask;
|
||||
GimpChannel *channel;
|
||||
guint32 hierarchy_offset;
|
||||
goffset hierarchy_offset;
|
||||
gint width;
|
||||
gint height;
|
||||
gboolean is_fs_drawable;
|
||||
|
|
@ -1759,7 +1758,7 @@ xcf_load_layer_mask (XcfInfo *info,
|
|||
xcf_progress_update (info);
|
||||
|
||||
/* read the hierarchy and layer mask offsets */
|
||||
info->cp += xcf_read_int32 (info->input, &hierarchy_offset, 1);
|
||||
info->cp += xcf_read_offset (info->input, &hierarchy_offset, 1);
|
||||
|
||||
/* read in the hierarchy */
|
||||
if (! xcf_seek_pos (info, hierarchy_offset, NULL))
|
||||
|
|
@ -1787,7 +1786,7 @@ xcf_load_buffer (XcfInfo *info,
|
|||
GeglBuffer *buffer)
|
||||
{
|
||||
const Babl *format;
|
||||
guint32 offset;
|
||||
goffset offset;
|
||||
gint width;
|
||||
gint height;
|
||||
gint bpp;
|
||||
|
|
@ -1806,7 +1805,7 @@ xcf_load_buffer (XcfInfo *info,
|
|||
bpp != babl_format_get_bytes_per_pixel (format))
|
||||
return FALSE;
|
||||
|
||||
info->cp += xcf_read_int32 (info->input, &offset, 1); /* top level */
|
||||
info->cp += xcf_read_offset (info->input, &offset, 1); /* top level */
|
||||
|
||||
/* seek to the level offset */
|
||||
if (!xcf_seek_pos (info, offset, NULL))
|
||||
|
|
@ -1829,8 +1828,9 @@ xcf_load_level (XcfInfo *info,
|
|||
{
|
||||
const Babl *format;
|
||||
gint bpp;
|
||||
guint32 saved_pos;
|
||||
guint32 offset, offset2;
|
||||
goffset saved_pos;
|
||||
goffset offset;
|
||||
goffset offset2;
|
||||
gint n_tile_rows;
|
||||
gint n_tile_cols;
|
||||
guint ntiles;
|
||||
|
|
@ -1853,7 +1853,7 @@ xcf_load_level (XcfInfo *info,
|
|||
* if it is '0', then this tile level is empty
|
||||
* and we can simply return.
|
||||
*/
|
||||
info->cp += xcf_read_int32 (info->input, &offset, 1);
|
||||
info->cp += xcf_read_offset (info->input, &offset, 1);
|
||||
if (offset == 0)
|
||||
return TRUE;
|
||||
|
||||
|
|
@ -1881,11 +1881,13 @@ xcf_load_level (XcfInfo *info,
|
|||
saved_pos = info->cp;
|
||||
|
||||
/* read in the offset of the next tile so we can calculate the amount
|
||||
of data needed for this tile*/
|
||||
info->cp += xcf_read_int32 (info->input, &offset2, 1);
|
||||
* of data needed for this tile
|
||||
*/
|
||||
info->cp += xcf_read_offset (info->input, &offset2, 1);
|
||||
|
||||
/* if the offset is 0 then we need to read in the maximum possible
|
||||
allowing for negative compression */
|
||||
* allowing for negative compression
|
||||
*/
|
||||
if (offset2 == 0)
|
||||
offset2 = offset + XCF_TILE_WIDTH * XCF_TILE_WIDTH * bpp * 1.5;
|
||||
/* 1.5 is probably more
|
||||
|
|
@ -1943,13 +1945,14 @@ xcf_load_level (XcfInfo *info,
|
|||
return FALSE;
|
||||
|
||||
/* read in the offset of the next tile */
|
||||
info->cp += xcf_read_int32 (info->input, &offset, 1);
|
||||
info->cp += xcf_read_offset (info->input, &offset, 1);
|
||||
}
|
||||
|
||||
if (offset != 0)
|
||||
{
|
||||
gimp_message (info->gimp, G_OBJECT (info->progress), GIMP_MESSAGE_ERROR,
|
||||
"encountered garbage after reading level: %d", offset);
|
||||
"encountered garbage after reading level: " G_GOFFSET_FORMAT,
|
||||
offset);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -98,14 +98,15 @@ struct _XcfInfo
|
|||
GInputStream *input;
|
||||
GOutputStream *output;
|
||||
GSeekable *seekable;
|
||||
guint cp;
|
||||
goffset cp;
|
||||
gint bytes_per_offset;
|
||||
GFile *file;
|
||||
GimpTattoo tattoo_state;
|
||||
GimpLayer *active_layer;
|
||||
GimpChannel *active_channel;
|
||||
GimpDrawable *floating_sel_drawable;
|
||||
GimpLayer *floating_sel;
|
||||
guint floating_sel_offset;
|
||||
goffset floating_sel_offset;
|
||||
XcfCompressionType compression;
|
||||
gint file_version;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -50,6 +50,29 @@ xcf_read_int32 (GInputStream *input,
|
|||
return total;
|
||||
}
|
||||
|
||||
guint
|
||||
xcf_read_offset (GInputStream *input,
|
||||
goffset *data,
|
||||
gint count)
|
||||
{
|
||||
guint total = 0;
|
||||
gint32 *int_offsets = g_alloca (count * sizeof (gint32));
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
total += xcf_read_int8 (input, (guint8 *) int_offsets, count * 4);
|
||||
|
||||
while (count--)
|
||||
{
|
||||
*data = g_ntohl (*int_offsets);
|
||||
int_offsets++;
|
||||
data++;
|
||||
}
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
guint
|
||||
xcf_read_float (GInputStream *input,
|
||||
gfloat *data,
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@
|
|||
guint xcf_read_int32 (GInputStream *input,
|
||||
guint32 *data,
|
||||
gint count);
|
||||
guint xcf_read_offset (GInputStream *input,
|
||||
goffset *data,
|
||||
gint count);
|
||||
guint xcf_read_float (GInputStream *input,
|
||||
gfloat *data,
|
||||
gint count);
|
||||
|
|
|
|||
|
|
@ -139,13 +139,22 @@ 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; \
|
||||
} \
|
||||
#define xcf_write_offset_check_error(info, data, count) G_STMT_START { \
|
||||
info->cp += xcf_write_offset (info->output, data, count, &tmp_error); \
|
||||
if (tmp_error) \
|
||||
{ \
|
||||
g_propagate_error (error, tmp_error); \
|
||||
return FALSE; \
|
||||
} \
|
||||
} G_STMT_END
|
||||
|
||||
#define xcf_write_zero_offset_check_error(info, count) G_STMT_START { \
|
||||
info->cp += xcf_write_zero_offset (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 { \
|
||||
|
|
@ -202,8 +211,8 @@ xcf_save_image (XcfInfo *info,
|
|||
GList *all_layers;
|
||||
GList *all_channels;
|
||||
GList *list;
|
||||
guint32 saved_pos;
|
||||
guint32 offset;
|
||||
goffset saved_pos;
|
||||
goffset offset;
|
||||
guint32 value;
|
||||
guint n_layers;
|
||||
guint n_channels;
|
||||
|
|
@ -255,9 +264,7 @@ xcf_save_image (XcfInfo *info,
|
|||
|
||||
max_progress = 1 + n_layers + n_channels;
|
||||
|
||||
/* write the property information for the image.
|
||||
*/
|
||||
|
||||
/* write the property information for the image */
|
||||
xcf_check_error (xcf_save_image_props (info, image, error));
|
||||
|
||||
xcf_progress_update (info);
|
||||
|
|
@ -266,7 +273,7 @@ xcf_save_image (XcfInfo *info,
|
|||
saved_pos = info->cp;
|
||||
|
||||
/* write an empty offset table */
|
||||
xcf_write_zero_int32_check_error (info, n_layers + n_channels + 2);
|
||||
xcf_write_zero_offset_check_error (info, n_layers + n_channels + 2);
|
||||
|
||||
/* 'offset' is where we will write the next layer or channel */
|
||||
offset = info->cp;
|
||||
|
|
@ -279,7 +286,7 @@ xcf_save_image (XcfInfo *info,
|
|||
* offset of the layer
|
||||
*/
|
||||
xcf_check_error (xcf_seek_pos (info, saved_pos, error));
|
||||
xcf_write_int32_check_error (info, &offset, 1);
|
||||
xcf_write_offset_check_error (info, &offset, 1);
|
||||
|
||||
/* remember the next slot in the offset table */
|
||||
saved_pos = info->cp;
|
||||
|
|
@ -297,7 +304,7 @@ xcf_save_image (XcfInfo *info,
|
|||
/* skip a '0' in the offset table to indicate the end of the layer
|
||||
* offsets
|
||||
*/
|
||||
saved_pos += 4;
|
||||
saved_pos += info->bytes_per_offset;
|
||||
|
||||
for (list = all_channels; list; list = g_list_next (list))
|
||||
{
|
||||
|
|
@ -307,7 +314,7 @@ xcf_save_image (XcfInfo *info,
|
|||
* offset of the channel
|
||||
*/
|
||||
xcf_check_error (xcf_seek_pos (info, saved_pos, error));
|
||||
xcf_write_int32_check_error (info, &offset, 1);
|
||||
xcf_write_offset_check_error (info, &offset, 1);
|
||||
|
||||
/* remember the next slot in the offset table */
|
||||
saved_pos = info->cp;
|
||||
|
|
@ -454,6 +461,7 @@ xcf_save_image_props (XcfInfo *info,
|
|||
gimp_parasite_name (compat_parasite));
|
||||
gimp_parasite_free (compat_parasite);
|
||||
}
|
||||
|
||||
xcf_check_error (xcf_save_prop (info, image, PROP_END, error));
|
||||
|
||||
return TRUE;
|
||||
|
|
@ -683,15 +691,15 @@ xcf_save_prop (XcfInfo *info,
|
|||
|
||||
case PROP_FLOATING_SELECTION:
|
||||
{
|
||||
guint32 dummy;
|
||||
goffset dummy;
|
||||
|
||||
dummy = 0;
|
||||
size = 4;
|
||||
size = info->bytes_per_offset;
|
||||
|
||||
xcf_write_prop_type_check_error (info, prop_type);
|
||||
xcf_write_int32_check_error (info, &size, 1);
|
||||
info->floating_sel_offset = info->cp;
|
||||
xcf_write_int32_check_error (info, &dummy, 1);
|
||||
xcf_write_offset_check_error (info, &dummy, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -1067,16 +1075,19 @@ xcf_save_prop (XcfInfo *info,
|
|||
|
||||
if (gimp_parasite_list_persistent_length (list) > 0)
|
||||
{
|
||||
guint32 base, length = 0;
|
||||
long pos;
|
||||
goffset base;
|
||||
goffset pos;
|
||||
guint32 length = 0;
|
||||
|
||||
xcf_write_prop_type_check_error (info, prop_type);
|
||||
|
||||
/* because we don't know how much room the parasite list will take
|
||||
* we save the file position and write the length later
|
||||
/* because we don't know how much room the parasite list
|
||||
* will take we save the file position and write the
|
||||
* length later
|
||||
*/
|
||||
pos = info->cp;
|
||||
xcf_write_int32_check_error (info, &length, 1);
|
||||
|
||||
base = info->cp;
|
||||
|
||||
xcf_check_error (xcf_save_parasite_list (info, list, error));
|
||||
|
|
@ -1108,13 +1119,14 @@ xcf_save_prop (XcfInfo *info,
|
|||
|
||||
case PROP_PATHS:
|
||||
{
|
||||
guint32 base, length = 0;
|
||||
glong pos;
|
||||
goffset base;
|
||||
goffset pos;
|
||||
guint32 length = 0;
|
||||
|
||||
xcf_write_prop_type_check_error (info, prop_type);
|
||||
|
||||
/* because we don't know how much room the paths list will take
|
||||
* we save the file position and write the length later
|
||||
/* because we don't know how much room the paths list will
|
||||
* take we save the file position and write the length later
|
||||
*/
|
||||
pos = info->cp;
|
||||
xcf_write_int32_check_error (info, &length, 1);
|
||||
|
|
@ -1169,13 +1181,14 @@ xcf_save_prop (XcfInfo *info,
|
|||
|
||||
case PROP_VECTORS:
|
||||
{
|
||||
guint32 base, length = 0;
|
||||
glong pos;
|
||||
goffset base;
|
||||
goffset pos;
|
||||
guint32 length = 0;
|
||||
|
||||
xcf_write_prop_type_check_error (info, prop_type);
|
||||
|
||||
/* because we don't know how much room the paths list will take
|
||||
* we save the file position and write the length later
|
||||
/* because we don't know how much room the paths list will
|
||||
* take we save the file position and write the length later
|
||||
*/
|
||||
pos = info->cp;
|
||||
xcf_write_int32_check_error (info, &length, 1);
|
||||
|
|
@ -1253,8 +1266,8 @@ xcf_save_layer (XcfInfo *info,
|
|||
GimpLayer *layer,
|
||||
GError **error)
|
||||
{
|
||||
guint32 saved_pos;
|
||||
guint32 offset;
|
||||
goffset saved_pos;
|
||||
goffset offset;
|
||||
guint32 value;
|
||||
const gchar *string;
|
||||
GError *tmp_error = NULL;
|
||||
|
|
@ -1266,7 +1279,7 @@ xcf_save_layer (XcfInfo *info,
|
|||
{
|
||||
saved_pos = info->cp;
|
||||
xcf_check_error (xcf_seek_pos (info, info->floating_sel_offset, error));
|
||||
xcf_write_int32_check_error (info, &saved_pos, 1);
|
||||
xcf_write_offset_check_error (info, &saved_pos, 1);
|
||||
xcf_check_error (xcf_seek_pos (info, saved_pos, error));
|
||||
}
|
||||
|
||||
|
|
@ -1288,13 +1301,13 @@ xcf_save_layer (XcfInfo *info,
|
|||
xcf_save_layer_props (info, image, layer, error);
|
||||
|
||||
/* write out the layer tile hierarchy */
|
||||
offset = info->cp + 8;
|
||||
xcf_write_int32_check_error (info, &offset, 1);
|
||||
offset = info->cp + 2 * info->bytes_per_offset;
|
||||
xcf_write_offset_check_error (info, &offset, 1);
|
||||
|
||||
saved_pos = info->cp;
|
||||
|
||||
/* write a zero layer mask offset */
|
||||
xcf_write_zero_int32_check_error (info, 1);
|
||||
xcf_write_zero_offset_check_error (info, 1);
|
||||
|
||||
xcf_check_error (xcf_save_buffer (info,
|
||||
gimp_drawable_get_buffer (GIMP_DRAWABLE (layer)),
|
||||
|
|
@ -1308,7 +1321,7 @@ xcf_save_layer (XcfInfo *info,
|
|||
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_offset_check_error (info, &offset, 1);
|
||||
|
||||
xcf_check_error (xcf_seek_pos (info, offset, error));
|
||||
xcf_check_error (xcf_save_channel (info, image, GIMP_CHANNEL (mask),
|
||||
|
|
@ -1324,8 +1337,8 @@ xcf_save_channel (XcfInfo *info,
|
|||
GimpChannel *channel,
|
||||
GError **error)
|
||||
{
|
||||
guint32 saved_pos;
|
||||
guint32 offset;
|
||||
goffset saved_pos;
|
||||
goffset offset;
|
||||
guint32 value;
|
||||
const gchar *string;
|
||||
GError *tmp_error = NULL;
|
||||
|
|
@ -1337,7 +1350,7 @@ xcf_save_channel (XcfInfo *info,
|
|||
{
|
||||
saved_pos = info->cp;
|
||||
xcf_check_error (xcf_seek_pos (info, info->floating_sel_offset, error));
|
||||
xcf_write_int32_check_error (info, &saved_pos, 1);
|
||||
xcf_write_offset_check_error (info, &saved_pos, 1);
|
||||
xcf_check_error (xcf_seek_pos (info, saved_pos, error));
|
||||
}
|
||||
|
||||
|
|
@ -1356,8 +1369,8 @@ xcf_save_channel (XcfInfo *info,
|
|||
xcf_save_channel_props (info, image, channel, error);
|
||||
|
||||
/* write out the channel tile hierarchy */
|
||||
offset = info->cp + 4;
|
||||
xcf_write_int32_check_error (info, &offset, 1);
|
||||
offset = info->cp + info->bytes_per_offset;
|
||||
xcf_write_offset_check_error (info, &offset, 1);
|
||||
|
||||
xcf_check_error (xcf_save_buffer (info,
|
||||
gimp_drawable_get_buffer (GIMP_DRAWABLE (channel)),
|
||||
|
|
@ -1370,7 +1383,7 @@ static gint
|
|||
xcf_calc_levels (gint size,
|
||||
gint tile_size)
|
||||
{
|
||||
int levels;
|
||||
gint levels;
|
||||
|
||||
levels = 1;
|
||||
while (size > tile_size)
|
||||
|
|
@ -1389,8 +1402,8 @@ xcf_save_buffer (XcfInfo *info,
|
|||
GError **error)
|
||||
{
|
||||
const Babl *format;
|
||||
guint32 saved_pos;
|
||||
guint32 offset;
|
||||
goffset saved_pos;
|
||||
goffset offset;
|
||||
guint32 width;
|
||||
guint32 height;
|
||||
guint32 bpp;
|
||||
|
|
@ -1409,8 +1422,6 @@ xcf_save_buffer (XcfInfo *info,
|
|||
xcf_write_int32_check_error (info, (guint32 *) &height, 1);
|
||||
xcf_write_int32_check_error (info, (guint32 *) &bpp, 1);
|
||||
|
||||
saved_pos = info->cp;
|
||||
|
||||
tmp1 = xcf_calc_levels (width, XCF_TILE_WIDTH);
|
||||
tmp2 = xcf_calc_levels (height, XCF_TILE_HEIGHT);
|
||||
nlevels = MAX (tmp1, tmp2);
|
||||
|
|
@ -1419,7 +1430,7 @@ xcf_save_buffer (XcfInfo *info,
|
|||
saved_pos = info->cp;
|
||||
|
||||
/* write an empty offset table */
|
||||
xcf_write_zero_int32_check_error (info, nlevels + 1);
|
||||
xcf_write_zero_offset_check_error (info, nlevels + 1);
|
||||
|
||||
/* 'offset' is where we will write the next level */
|
||||
offset = info->cp;
|
||||
|
|
@ -1430,7 +1441,7 @@ xcf_save_buffer (XcfInfo *info,
|
|||
* offset of the level
|
||||
*/
|
||||
xcf_check_error (xcf_seek_pos (info, saved_pos, error));
|
||||
xcf_write_int32_check_error (info, &offset, 1);
|
||||
xcf_write_offset_check_error (info, &offset, 1);
|
||||
|
||||
/* remember the next slot in the offset table */
|
||||
saved_pos = info->cp;
|
||||
|
|
@ -1471,10 +1482,10 @@ xcf_save_level (XcfInfo *info,
|
|||
GError **error)
|
||||
{
|
||||
const Babl *format;
|
||||
guint32 *offset_table;
|
||||
guint32 *next_offset;
|
||||
guint32 saved_pos;
|
||||
guint32 offset;
|
||||
goffset *offset_table;
|
||||
goffset *next_offset;
|
||||
goffset saved_pos;
|
||||
goffset offset;
|
||||
guint32 width;
|
||||
guint32 height;
|
||||
gint bpp;
|
||||
|
|
@ -1511,15 +1522,15 @@ xcf_save_level (XcfInfo *info,
|
|||
* tile, see bug #686862. allocate ntiles + 1 slots because a zero
|
||||
* offset indicates the offset table's end.
|
||||
*/
|
||||
offset_table = g_alloca ((ntiles + 1) * sizeof (gint32));
|
||||
memset (offset_table, 0, (ntiles + 1) * sizeof (gint32));
|
||||
offset_table = g_alloca ((ntiles + 1) * sizeof (goffset));
|
||||
memset (offset_table, 0, (ntiles + 1) * sizeof (goffset));
|
||||
next_offset = offset_table;
|
||||
|
||||
/* 'saved_pos' is the offset of the tile offset table */
|
||||
saved_pos = info->cp;
|
||||
|
||||
/* write an empty offset table */
|
||||
xcf_write_zero_int32_check_error (info, ntiles + 1);
|
||||
xcf_write_zero_offset_check_error (info, ntiles + 1);
|
||||
|
||||
/* 'offset' is where we will write the next tile */
|
||||
offset = info->cp;
|
||||
|
|
@ -1561,7 +1572,7 @@ xcf_save_level (XcfInfo *info,
|
|||
|
||||
/* seek back to the offset table and write it */
|
||||
xcf_check_error (xcf_seek_pos (info, saved_pos, error));
|
||||
xcf_write_int32_check_error (info, offset_table, ntiles + 1);
|
||||
xcf_write_offset_check_error (info, offset_table, ntiles + 1);
|
||||
|
||||
/* seek to the end of the file */
|
||||
xcf_check_error (xcf_seek_pos (info, offset, error));
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
gboolean
|
||||
xcf_seek_pos (XcfInfo *info,
|
||||
guint pos,
|
||||
goffset pos,
|
||||
GError **error)
|
||||
{
|
||||
if (info->cp != pos)
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@
|
|||
#define __XCF_SEEK_H__
|
||||
|
||||
|
||||
gboolean xcf_seek_pos (XcfInfo *info,
|
||||
guint pos,
|
||||
GError **error);
|
||||
gboolean xcf_seek_pos (XcfInfo *info,
|
||||
goffset pos,
|
||||
GError **error);
|
||||
|
||||
|
||||
#endif /* __XCF_SEEK_H__ */
|
||||
|
|
|
|||
|
|
@ -56,9 +56,38 @@ xcf_write_int32 (GOutputStream *output,
|
|||
}
|
||||
|
||||
guint
|
||||
xcf_write_zero_int32 (GOutputStream *output,
|
||||
gint count,
|
||||
GError **error)
|
||||
xcf_write_offset (GOutputStream *output,
|
||||
const goffset *data,
|
||||
gint count,
|
||||
GError **error)
|
||||
{
|
||||
GError *tmp_error = NULL;
|
||||
gint i;
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
guint32 tmp = g_htonl (data[i]);
|
||||
|
||||
xcf_write_int8 (output, (const guint8 *) &tmp, 4, &tmp_error);
|
||||
|
||||
if (tmp_error)
|
||||
{
|
||||
g_propagate_error (error, tmp_error);
|
||||
|
||||
return i * 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count * 4;
|
||||
}
|
||||
|
||||
guint
|
||||
xcf_write_zero_offset (GOutputStream *output,
|
||||
gint count,
|
||||
GError **error)
|
||||
{
|
||||
if (count > 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,25 +19,29 @@
|
|||
#define __XCF_WRITE_H__
|
||||
|
||||
|
||||
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);
|
||||
guint xcf_write_int32 (GOutputStream *output,
|
||||
const guint32 *data,
|
||||
gint count,
|
||||
GError **error);
|
||||
guint xcf_write_offset (GOutputStream *output,
|
||||
const goffset *data,
|
||||
gint count,
|
||||
GError **error);
|
||||
guint xcf_write_zero_offset (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__ */
|
||||
|
|
|
|||
|
|
@ -280,6 +280,8 @@ xcf_load_stream (Gimp *gimp,
|
|||
|
||||
success = TRUE;
|
||||
|
||||
info.bytes_per_offset = 4;
|
||||
|
||||
info.cp += xcf_read_int8 (info.input, (guint8 *) id, 14);
|
||||
|
||||
if (! g_str_has_prefix (id, "gimp xcf "))
|
||||
|
|
@ -367,6 +369,8 @@ xcf_save_stream (Gimp *gimp,
|
|||
COMPRESS_ZLIB,
|
||||
NULL, NULL);
|
||||
|
||||
info.bytes_per_offset = 4;
|
||||
|
||||
if (progress)
|
||||
gimp_progress_start (progress, FALSE, _("Saving '%s'"), filename);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue