[gimp] Bug 731390 - XCF files have a max size of 4G



commit a0a5f714bbf0a2f25cff50a83fcb49cec824a40f
Author: Michael Natterer <mitch gimp org>
Date:   Thu Mar 23 11:44:41 2017 +0100

    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.

 app/xcf/xcf-load.c    |   67 +++++++++++++------------
 app/xcf/xcf-private.h |    5 +-
 app/xcf/xcf-read.c    |   23 +++++++++
 app/xcf/xcf-read.h    |    3 +
 app/xcf/xcf-save.c    |  127 ++++++++++++++++++++++++++----------------------
 app/xcf/xcf-seek.c    |    2 +-
 app/xcf/xcf-seek.h    |    6 +-
 app/xcf/xcf-write.c   |   35 ++++++++++++-
 app/xcf/xcf-write.h   |   42 +++++++++-------
 app/xcf/xcf.c         |    4 ++
 10 files changed, 196 insertions(+), 118 deletions(-)
---
diff --git a/app/xcf/xcf-load.c b/app/xcf/xcf-load.c
index 5c1410d..5856e08 100644
--- a/app/xcf/xcf-load.c
+++ b/app/xcf/xcf-load.c
@@ -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;
     }
 
diff --git a/app/xcf/xcf-private.h b/app/xcf/xcf-private.h
index a2af8ad..8762dbc 100644
--- a/app/xcf/xcf-private.h
+++ b/app/xcf/xcf-private.h
@@ -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;
 };
diff --git a/app/xcf/xcf-read.c b/app/xcf/xcf-read.c
index ad16144..b2a524c 100644
--- a/app/xcf/xcf-read.c
+++ b/app/xcf/xcf-read.c
@@ -51,6 +51,29 @@ xcf_read_int32 (GInputStream *input,
 }
 
 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,
                 gint          count)
diff --git a/app/xcf/xcf-read.h b/app/xcf/xcf-read.h
index 5f107f7..0e71832 100644
--- a/app/xcf/xcf-read.h
+++ b/app/xcf/xcf-read.h
@@ -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);
diff --git a/app/xcf/xcf-save.c b/app/xcf/xcf-save.c
index 46b408d..a89c349 100644
--- a/app/xcf/xcf-save.c
+++ b/app/xcf/xcf-save.c
@@ -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));
diff --git a/app/xcf/xcf-seek.c b/app/xcf/xcf-seek.c
index 140bc3e..257e0a9 100644
--- a/app/xcf/xcf-seek.c
+++ b/app/xcf/xcf-seek.c
@@ -29,7 +29,7 @@
 
 gboolean
 xcf_seek_pos (XcfInfo  *info,
-              guint     pos,
+              goffset   pos,
               GError  **error)
 {
   if (info->cp != pos)
diff --git a/app/xcf/xcf-seek.h b/app/xcf/xcf-seek.h
index ede3f2f..29845e6 100644
--- a/app/xcf/xcf-seek.h
+++ b/app/xcf/xcf-seek.h
@@ -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__ */
diff --git a/app/xcf/xcf-write.c b/app/xcf/xcf-write.c
index 8360027..5c54331 100644
--- a/app/xcf/xcf-write.c
+++ b/app/xcf/xcf-write.c
@@ -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)
     {
diff --git a/app/xcf/xcf-write.h b/app/xcf/xcf-write.h
index ef46646..1bb68d5 100644
--- a/app/xcf/xcf-write.h
+++ b/app/xcf/xcf-write.h
@@ -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__ */
diff --git a/app/xcf/xcf.c b/app/xcf/xcf.c
index ec55b79..efcee24 100644
--- a/app/xcf/xcf.c
+++ b/app/xcf/xcf.c
@@ -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);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]