kwo pushed a commit to branch master.

http://git.enlightenment.org/legacy/imlib2_loaders.git/commit/?id=a4bcffe55adbf1492bf399f57bf4faa289445bb7

commit a4bcffe55adbf1492bf399f57bf4faa289445bb7
Author: Kim Woelders <k...@woelders.dk>
Date:   Sun Nov 17 12:52:07 2019 +0100

    XCF loader: Cosmetic rearrangements
---
 src/modules/loaders/loader_xcf.c | 1908 ++++++++++++++++++--------------------
 1 file changed, 919 insertions(+), 989 deletions(-)

diff --git a/src/modules/loaders/loader_xcf.c b/src/modules/loaders/loader_xcf.c
index 86bdf9c..7ca745d 100644
--- a/src/modules/loaders/loader_xcf.c
+++ b/src/modules/loaders/loader_xcf.c
@@ -59,29 +59,22 @@
 #include "loader_common.h"
 #include "loader_xcf.h"
 
-/* #define XCF_DBG */
-
-#define FREE(X) { free(X); X = NULL; }
-
-#ifdef XCF_DBG
-#define D(fmt, args...) \
-{ \
-  printf("Imlib2 XCF loader: "); \
-  printf(fmt, ## args); \
-}
+#define XCF_DBG 0
+#if XCF_DBG
+#define D(fmt...) printf("Imlib2 XCF loader: " fmt)
 #else
-#define D(fmt, args...)
+#define D(fmt...)
 #endif
 
 #define TILE_WIDTH   64
 #define TILE_HEIGHT  64
 
-/* --------------------------------------------------------------------------- 
typedefs ------------ */
+/* ------------ typedefs ------------ */
 
 typedef struct _Layer Layer;
 typedef struct _Tile Tile;
 
-/* 
------------------------------------------------------------------------------ 
enums ------------ */
+/* ------------ enums ------------ */
 
 /* These are all the properties that a layer or channel can have.
    Only some of them are actually used. */
@@ -161,7 +154,7 @@ typedef enum {
    INDEXEDA_GIMAGE
 } GimpImageType;
 
-/* 
---------------------------------------------------------------------------- 
structs ------------ */
+/* ------------ structs ------------ */
 
 /* Ok, this is what's left of Gimp's layer abstraction. I kicked out
    all the stuff that's unnecessary and added the necessary stuff
@@ -254,361 +247,548 @@ struct _GimpImage {
    Layer              *floating_sel;
 } _image;
 
-/* ------------------------------------------------------------------------- 
prototypes ------------ */
-
-/* stuff that was adapted from xcf.c */
-
-static void         xcf_seek_pos(int pos);
-static int          xcf_read_int32(FILE * fp, DATA32 * data, int count);
-
-/*static int        xcf_read_float (FILE *fp, float *data, int count);*/
-static int          xcf_read_int8(FILE * fp, DATA8 * data, int count);
-static int          xcf_read_string(FILE * fp, char **data, int count);
-static char         xcf_load_prop(PropType * prop_type, DATA32 * prop_size);
-static void         xcf_load_image(void);
-static char         xcf_load_image_props(void);
-
-static Layer       *xcf_load_channel(void);
-static char         xcf_load_channel_props(Layer * layer);
-static Layer       *xcf_load_layer(void);
-static char         xcf_load_layer_props(Layer * layer);
-static char         xcf_load_hierarchy(Tile ** tiles,
-                                       int *num_rows, int *num_cols, int *bpp);
-static char         xcf_load_level(Tile ** tiles, int hierarchy_width,
-                                   int hierarchy_height, int bpp,
-                                   int *num_rows, int *num_cols);
-static char         xcf_load_tile(Tile * tile);
-static char         xcf_load_tile_rle(Tile * tile, int data_length);
-
-/* new stuff :) */
-
-static Tile        *allocate_tiles(int width, int height, int bpp,
-                                   int *num_rows, int *num_cols);
-static void         free_tiles(Tile * tiles, int num_tiles);
-static void         init_tile(Tile * tile, int width, int height, int bpp);
-static Layer       *new_layer(int width, int height, GimpImageType type,
-                              int opacity, LayerModeEffects mode);
-static void         free_layer(Layer * layer);
-static void         add_layer_to_image(Layer * layer);
-static void         read_tiles_into_data(Tile * tiles, int num_cols, int width,
-                                         int height, int bpp, DATA8 ** data,
-                                         int use_cmap);
-static void         apply_layer_mask(Layer * layer);
-static void         set_layer_opacity(Layer * layer);
-static void         flatten_image(void);
-
-static char         xcf_file_init(char *filename);
-static void         xcf_cleanup(void);
-static void         xcf_to_imlib(ImlibImage * im);
-
-/* 
---------------------------------------------------------------------------- 
globals ------------ */
+/* ------------ globals ------------ */
 
 /* This makes using the Gimp sources easier */
 struct _GimpImage  *image = &_image;
 
-/* 
------------------------------------------------------------------------------- 
code ------------ */
+/* ------------ prototypes ------------ */
+
+/* new stuff :) */
 
 static void
-xcf_seek_pos(int pos)
+free_tiles(Tile * tiles, int num_tiles)
 {
-   if (image->cp != pos)
-     {
-        image->cp = pos;
-        fseek(image->fp, image->cp, SEEK_SET);
-     }
-}
+   int                 i;
 
-static int
-xcf_read_int32(FILE * fp, DATA32 * data, int count)
-{
-   int                 total;
+   D("%s: tiles=%p num=%d\n", __func__, tiles, num_tiles);
 
-   total = count;
-   if (count > 0)
+   for (i = 0; i < num_tiles; i++)
      {
-        xcf_read_int8(fp, (DATA8 *) data, count * 4);
-
-        while (count--)
+        if (tiles[i].data)
           {
-             *data = (DATA32) ntohl(*data);
-             data++;
+             free(tiles[i].data);
+             tiles[i].data = NULL;
           }
      }
-
-   return total * 4;
+   free(tiles);
 }
 
-/*
-static int
-xcf_read_float (FILE     *fp,
-               float    *data,
-               int       count)
+static void
+init_tile(Tile * tile, int width, int height, int bpp)
 {
-  return (xcf_read_int32(fp, (DATA32 *)((void *)data), count));
+   D("%s: tile=%p\n", __func__, tile);
+
+   if (!tile)
+      return;
+
+   tile->bpp = bpp;
+   tile->ewidth = width;
+   tile->eheight = height;
+   tile->data = malloc(sizeof(DATA8) * width * height * bpp);
+   if (!tile->data)
+     {
+        D("Couldn't allocate tile.\n");
+     }
 }
-*/
 
-static int
-xcf_read_int8(FILE * fp, DATA8 * data, int count)
+static Tile        *
+allocate_tiles(int width, int height, int bpp, int *num_rows, int *num_cols)
 {
-   int                 total;
-   int                 bytes;
+   Tile               *tiles;
+   int                 i, j, k, right_tile, bottom_tile;
+   int                 tile_width, tile_height;
 
-   total = count;
-   while (count > 0)
+   (*num_rows) = (height + TILE_HEIGHT - 1) / TILE_HEIGHT;
+   (*num_cols) = (width + TILE_WIDTH - 1) / TILE_WIDTH;
+
+   tiles = calloc((*num_rows) * (*num_cols), sizeof(Tile));
+   if (!tiles)
      {
-        bytes = fread((char *)data, sizeof(char), count, fp);
-        if (bytes <= 0)         /* something bad happened */
-           break;
-        count -= bytes;
-        data += bytes;
+        D("Couldn't allocate tiles.\n");
+        return NULL;
      }
 
-   return total;
-}
+   D("%s: tiles=%p %dx%d\n", __func__, tiles, *num_cols, *num_rows);
 
-static int
-xcf_read_string(FILE * fp, char **data, int count)
-{
-   DATA32              tmp;
-   int                 total;
-   int                 i;
+   right_tile = width - (((*num_cols) - 1) * TILE_WIDTH);
+   bottom_tile = height - (((*num_rows) - 1) * TILE_HEIGHT);
 
-   total = 0;
-   for (i = 0; i < count; i++)
+   for (i = 0, k = 0; i < (*num_rows); i++)
      {
-        total += xcf_read_int32(fp, &tmp, 1);
-        if (tmp > 0)
-          {
-             data[i] = malloc(sizeof(DATA8) * tmp);
-             total += xcf_read_int8(fp, (DATA8 *) data[i], tmp);
-          }
-        else
+        for (j = 0; j < (*num_cols); j++, k++)
           {
-             data[i] = NULL;
+             tile_width = ((j == (*num_cols) - 1) ? right_tile : TILE_WIDTH);
+             tile_height = ((i == (*num_rows) - 1) ? bottom_tile : 
TILE_HEIGHT);
+             init_tile(&(tiles[k]), tile_width, tile_height, bpp);
           }
      }
 
-   return total;
-}
+   D("Allocated %ix%i tiles.\n", (*num_cols), (*num_rows));
 
-static char
-xcf_load_prop(PropType * prop_type, DATA32 * prop_size)
-{
-   image->cp += xcf_read_int32(image->fp, (DATA32 *) prop_type, 1);
-   image->cp += xcf_read_int32(image->fp, (DATA32 *) prop_size, 1);
-   return 1;
+   return tiles;
 }
 
-static char
-xcf_load_image_props(void)
+static Layer       *
+new_layer(int width, int height, GimpImageType type, int opacity,
+          LayerModeEffects mode)
 {
-   PropType            prop_type;
-   DATA32              prop_size;
+   Layer              *layer;
 
-   while (1)
+   layer = calloc(1, sizeof(Layer));
+   if (!layer)
      {
-        if (!xcf_load_prop(&prop_type, &prop_size))
-           return 0;
-
-        switch (prop_type)
-          {
-          case PROP_END:
-             {
-                D("Finished reading image properties.\n");
-                return 1;
-             }
-          case PROP_COLORMAP:
-             {
-                if (image->file_version == 0)
-                  {
-                     unsigned int        i;
-
-                     fprintf(stderr,
-                             "XCF warning: version 0 of XCF file format\n"
-                             "did not save indexed colormaps correctly.\n"
-                             "Substituting grayscale map.\n");
-                     image->cp +=
-                        xcf_read_int32(image->fp, &image->num_cols, 1);
-                     image->cmap = malloc(sizeof(DATA8) * image->num_cols * 3);
-                     xcf_seek_pos(image->cp + image->num_cols);
-                     for (i = 0; i < image->num_cols; i++)
-                       {
-                          image->cmap[i * 3 + 0] = i;
-                          image->cmap[i * 3 + 1] = i;
-                          image->cmap[i * 3 + 2] = i;
-                       }
-                  }
-                else
-                  {
-                     D("Loading colormap.\n");
-                     image->cp +=
-                        xcf_read_int32(image->fp, &image->num_cols, 1);
-                     image->cmap = malloc(sizeof(DATA8) * image->num_cols * 3);
-                     image->cp +=
-                        xcf_read_int8(image->fp, (DATA8 *) image->cmap,
-                                      image->num_cols * 3);
-                  }
-             }
-             break;
-
-          case PROP_COMPRESSION:
-             {
-                DATA8               compression;
-
-                image->cp += xcf_read_int8(image->fp, &compression, 1);
-
-                if ((compression != COMPRESS_NONE) &&
-                    (compression != COMPRESS_RLE) &&
-                    (compression != COMPRESS_ZLIB) &&
-                    (compression != COMPRESS_FRACTAL))
-                  {
-                     fprintf(stderr, "unknown xcf compression type: %d\n",
-                             (int)compression);
-                     return 0;
-                  }
-
-                D("Image compression type: %i\n", compression);
+        D("Couldn't allocate layer.\n");
+        return NULL;
+     }
 
-                image->compression = compression;
-             }
-             break;
+   D("%s: layer=%p\n", __func__, layer);
 
-             /* I threw out all of the following: --cK */
-          case PROP_TATTOO:
-          case PROP_PARASITES:
-          case PROP_UNIT:
-          case PROP_PATHS:
-          case PROP_USER_UNIT:
-          case PROP_GUIDES:
-          case PROP_RESOLUTION:
-          default:
-             {
-                DATA8               buf[16];
-                int                 amount;
-
-                D("Skipping unexpected/unknown image property: %d\n",
-                  prop_type);
-
-                while (prop_size > 0)
-                  {
-                     amount = (16 < prop_size ? 16 : prop_size);
-                     image->cp += xcf_read_int8(image->fp, buf, amount);
-                     prop_size -= (16 < amount ? 16 : amount);
-                  }
-             }
-             break;
-          }
-     }
+   layer->width = width;
+   layer->height = height;
+   layer->type = type;
+   layer->opacity = opacity;
+   layer->mode = mode;
 
-   return 0;
+   return layer;
 }
 
 static void
-xcf_load_image(void)
+free_layer(Layer * layer)
 {
-   Layer              *layer;
-   DATA32              saved_pos;
-   DATA32              offset;
-   int                 width;
-   int                 height;
-   int                 image_type;
-   int                 num_successful_elements = 0;
-
-   /* read in the image width, height and type */
-   image->cp += xcf_read_int32(image->fp, (DATA32 *) & width, 1);
-   image->cp += xcf_read_int32(image->fp, (DATA32 *) & height, 1);
-   image->cp += xcf_read_int32(image->fp, (DATA32 *) & image_type, 1);
-
-   image->width = width;
-   image->height = height;
-   image->base_type = image_type;
-
-   D("Loading %ix%i image.\n", width, height);
+   D("%s: layer=%p\n", __func__, layer);
 
-   /* read the image properties */
-   if (!xcf_load_image_props())
-      goto hard_error;
+   if (!layer)
+      return;
 
-   while (1)
+   if (layer->tiles)
      {
-        /* read in the offset of the next layer */
-        image->cp += xcf_read_int32(image->fp, &offset, 1);
+        free_tiles(layer->tiles, layer->num_rows * layer->num_cols);
+        layer->tiles = NULL;
+     }
 
-        /* if the offset is 0 then we are at the end
-         *  of the layer list.
-         */
-        if (offset == 0)
-           break;
+   if (layer->mask)
+     {
+        free_layer(layer->mask);
+        layer->mask = NULL;
+     }
 
-        /* save the current position as it is where the
-         *  next layer offset is stored.
-         */
-        saved_pos = image->cp;
+   if (layer->data)
+      free(layer->data);
 
-        /* seek to the layer offset */
-        xcf_seek_pos(offset);
+   free(layer);
+}
 
-        /* read in the layer */
-        layer = xcf_load_layer();
-        if (!layer)
-           goto error;
+static void
+add_layer_to_image(Layer * layer)
+{
+   if (!layer)
+      return;
 
-        num_successful_elements++;
+   if (image->last_layer)
+     {
+        image->last_layer->next = layer;
+        layer->prev = image->last_layer;
+     }
+   else
+     {
+        image->layers = layer;
+        layer->prev = NULL;
+     }
+   layer->next = NULL;
+   image->last_layer = layer;
+}
 
-        /* add the layer to the image if it's visible */
-        if (layer->visible)
-           add_layer_to_image(layer);
-        else
-           free_layer(layer);
+static void
+set_layer_opacity(Layer * layer)
+{
+   int                 i;
+   DATA8              *ptr;
 
-        /* restore the saved position so we'll be ready to
-         *  read the next offset.
-         */
-        xcf_seek_pos(saved_pos);
+   if (!layer)
+      return;
 
+   if (layer->opacity != 255)
+     {
+        for (i = 0, ptr = layer->data; i < layer->width * layer->height;
+             i++, ptr += 4)
+          {
+             *(ptr + 3) = (*(ptr + 3) * layer->opacity) >> 8;
+          }
      }
+}
 
-   /* If we were a Gimp we would now load the user-defined channels here ... */
+static void
+apply_layer_mask(Layer * layer)
+{
+   DATA8              *ptr1;
+   DATA8              *ptr2;
+   int                 i, tmp;
 
-   /* Flat-o-rama now :) */
-   flatten_image();
+   D("Applying layer mask.\n");
 
-   return;
+   if (!layer)
+      return;
 
- error:
-   if (num_successful_elements == 0)
-      goto hard_error;
+   if (!layer->mask)
+      return;
 
-   fprintf(stderr,
-           "XCF: This file is corrupt!  I have loaded as much\nof it as I can, 
but it is incomplete.\n");
+   ptr1 = layer->data;
+   ptr2 = layer->mask->data;
 
-   return;
+   for (i = 0; i < layer->width * layer->height; i++)
+     {
+        tmp = (*(ptr1 + 3) * *(ptr2)) / 256;
+        if (tmp > 255)
+           tmp = 255;
 
- hard_error:
-   fprintf(stderr,
-           "XCF: This file is corrupt!  I could not even\nsalvage any partial 
image data from it.\n");
-   return;
+        *(ptr1 + 3) = (DATA8) tmp;
+        ptr1 += 4;
+        ptr2 += 4;
+     }
 }
 
-static char
-xcf_load_layer_props(Layer * layer)
+static void
+flatten_image(void)
 {
-   PropType            prop_type;
-   DATA32              prop_size;
+   Layer              *l = image->last_layer;
+   Layer              *lp;
+   int                 layer_index;
 
-   while (1)
-     {
-        if (!xcf_load_prop(&prop_type, &prop_size))
-           return 0;
+   image->data = calloc(image->width * image->height, sizeof(DATA32));
+   layer_index = 0;
+
+   while (l)
+     {
+        /* Ok, paste each layer on top of the image, using the mode's merging 
type.
+         * We're moving upward through the layer stack.
+         * --cK.
+         */
+        if (image->single_layer_index < 0
+            || layer_index == image->single_layer_index)
+          {
+             switch (l->mode)
+               {
+               case MULTIPLY_MODE:
+                  D("MULTIPLY\n");
+                  combine_pixels_mult(l->data, l->width, l->height,
+                                      image->data, image->width, image->height,
+                                      l->offset_x, l->offset_y);
+                  break;
+               case DIVIDE_MODE:
+                  D("DIVIDE\n");
+                  combine_pixels_div(l->data, l->width, l->height,
+                                     image->data, image->width, image->height,
+                                     l->offset_x, l->offset_y);
+                  break;
+               case SCREEN_MODE:
+                  D("SCREEN\n");
+                  combine_pixels_screen(l->data, l->width, l->height,
+                                        image->data, image->width,
+                                        image->height, l->offset_x,
+                                        l->offset_y);
+                  break;
+               case OVERLAY_MODE:
+                  D("OVERLAY\n");
+                  combine_pixels_overlay(l->data, l->width, l->height,
+                                         image->data, image->width,
+                                         image->height, l->offset_x,
+                                         l->offset_y);
+                  break;
+               case DIFFERENCE_MODE:
+                  D("DIFF\n");
+                  combine_pixels_diff(l->data, l->width, l->height,
+                                      image->data, image->width, image->height,
+                                      l->offset_x, l->offset_y);
+                  break;
+               case ADDITION_MODE:
+                  D("ADD\n");
+                  combine_pixels_add(l->data, l->width, l->height,
+                                     image->data, image->width, image->height,
+                                     l->offset_x, l->offset_y);
+                  break;
+               case SUBTRACT_MODE:
+                  D("SUB\n");
+                  combine_pixels_sub(l->data, l->width, l->height,
+                                     image->data, image->width, image->height,
+                                     l->offset_x, l->offset_y);
+                  break;
+               case DARKEN_ONLY_MODE:
+                  D("DARKEN\n");
+                  combine_pixels_darken(l->data, l->width, l->height,
+                                        image->data, image->width,
+                                        image->height, l->offset_x,
+                                        l->offset_y);
+                  break;
+               case LIGHTEN_ONLY_MODE:
+                  D("LIGHTEN\n");
+                  combine_pixels_lighten(l->data, l->width, l->height,
+                                         image->data, image->width,
+                                         image->height, l->offset_x,
+                                         l->offset_y);
+                  break;
+
+               case HUE_MODE:
+                  D("HUE\n");
+                  combine_pixels_hue(l->data, l->width, l->height,
+                                     image->data, image->width, image->height,
+                                     l->offset_x, l->offset_y);
+                  break;
+               case SATURATION_MODE:
+                  D("SATURATION\n");
+                  combine_pixels_sat(l->data, l->width, l->height,
+                                     image->data, image->width, image->height,
+                                     l->offset_x, l->offset_y);
+                  break;
+               case VALUE_MODE:
+                  D("VALUE\n");
+                  combine_pixels_val(l->data, l->width, l->height,
+                                     image->data, image->width, image->height,
+                                     l->offset_x, l->offset_y);
+                  break;
+               case COLOR_MODE:
+                  D("COLOR\n");
+                  combine_pixels_col(l->data, l->width, l->height,
+                                     image->data, image->width, image->height,
+                                     l->offset_x, l->offset_y);
+                  break;
+               case DISSOLVE_MODE:
+                  D("DISSOLVE\n");
+                  combine_pixels_diss(l->data, l->width, l->height,
+                                      image->data, image->width, image->height,
+                                      l->offset_x, l->offset_y);
+                  break;
+
+                  /* None of the following is actually valid for layer 
blending, fall through: */
+               case BEHIND_MODE:
+               case REPLACE_MODE:
+               case ERASE_MODE:
+               case ANTI_ERASE_MODE:
+                  D("EEEEEK -- this mode shouldn't be here\n");
+                  /* FALLTHROUGH */
+
+               case NORMAL_MODE:
+                  D("NORMAL\n");
+                  combine_pixels_normal(l->data, l->width, l->height,
+                                        image->data, image->width,
+                                        image->height, l->offset_x,
+                                        l->offset_y);
+                  break;
+
+               default:
+                  D("Unknown layer mode: %i. Skipping.\n", l->mode);
+                  break;
+               }
+          }
+
+        lp = l->prev;
+        /* free the layer now, since it's not needed anymore */
+        free_layer(l);
+
+        l = lp;
+        layer_index++;
+     }
+
+   /* We've used up all the layers now, so set them to NULL in the image: */
+   image->layers = NULL;
+   image->last_layer = NULL;
+}
+
+/* ------------ code ------------ */
+
+/* stuff that was adapted from xcf.c */
+
+static void
+xcf_seek_pos(int pos)
+{
+   if (image->cp != pos)
+     {
+        image->cp = pos;
+        fseek(image->fp, image->cp, SEEK_SET);
+     }
+}
+
+static int
+xcf_read_int8(FILE * fp, DATA8 * data, int count)
+{
+   int                 total;
+   int                 bytes;
+
+   total = count;
+   while (count > 0)
+     {
+        bytes = fread(data, 1, count, fp);
+        if (bytes <= 0)         /* something bad happened */
+           break;
+        count -= bytes;
+        data += bytes;
+     }
+
+   return total;
+}
+
+static int
+xcf_read_int32(FILE * fp, DATA32 * data, int count)
+{
+   int                 total;
+
+   total = count;
+   if (count > 0)
+     {
+        xcf_read_int8(fp, (DATA8 *) data, count * 4);
+
+        while (count--)
+          {
+             *data = (DATA32) ntohl(*data);
+             data++;
+          }
+     }
+
+   return total * 4;
+}
+
+static int
+xcf_read_string(FILE * fp, char **data, int count)
+{
+   DATA32              tmp;
+   int                 total;
+   int                 i;
+
+   total = 0;
+   for (i = 0; i < count; i++)
+     {
+        total += xcf_read_int32(fp, &tmp, 1);
+        if (tmp > 0)
+          {
+             data[i] = malloc(sizeof(DATA8) * tmp);
+             total += xcf_read_int8(fp, (DATA8 *) data[i], tmp);
+          }
+        else
+          {
+             data[i] = NULL;
+          }
+     }
+
+   return total;
+}
+
+static int
+xcf_load_prop(PropType * prop_type, DATA32 * prop_size)
+{
+   image->cp += xcf_read_int32(image->fp, (DATA32 *) prop_type, 1);
+   image->cp += xcf_read_int32(image->fp, (DATA32 *) prop_size, 1);
+   return 1;
+}
+
+static int
+xcf_load_image_props(void)
+{
+   PropType            prop_type;
+   DATA32              prop_size;
+   DATA8               compression;
+
+   while (1)
+     {
+        if (!xcf_load_prop(&prop_type, &prop_size))
+           return 0;
 
         switch (prop_type)
           {
           case PROP_END:
-             {
-                D("Finished reading layer properties.\n");
-                return 1;
-             }
+             D("Finished reading image properties.\n");
+             return 1;
+
+          case PROP_COLORMAP:
+             if (image->file_version == 0)
+               {
+                  unsigned int        i;
+
+                  fprintf(stderr,
+                          "XCF warning: version 0 of XCF file format\n"
+                          "did not save indexed colormaps correctly.\n"
+                          "Substituting grayscale map.\n");
+                  image->cp += xcf_read_int32(image->fp, &image->num_cols, 1);
+                  image->cmap = malloc(sizeof(DATA8) * image->num_cols * 3);
+                  xcf_seek_pos(image->cp + image->num_cols);
+                  for (i = 0; i < image->num_cols; i++)
+                    {
+                       image->cmap[i * 3 + 0] = i;
+                       image->cmap[i * 3 + 1] = i;
+                       image->cmap[i * 3 + 2] = i;
+                    }
+               }
+             else
+               {
+                  D("Loading colormap.\n");
+                  image->cp += xcf_read_int32(image->fp, &image->num_cols, 1);
+                  image->cmap = malloc(sizeof(DATA8) * image->num_cols * 3);
+                  image->cp +=
+                     xcf_read_int8(image->fp, (DATA8 *) image->cmap,
+                                   image->num_cols * 3);
+               }
+             break;
+
+          case PROP_COMPRESSION:
+             image->cp += xcf_read_int8(image->fp, &compression, 1);
+
+             if ((compression != COMPRESS_NONE) &&
+                 (compression != COMPRESS_RLE) &&
+                 (compression != COMPRESS_ZLIB) &&
+                 (compression != COMPRESS_FRACTAL))
+               {
+                  fprintf(stderr, "unknown xcf compression type: %d\n",
+                          (int)compression);
+                  return 0;
+               }
+
+             D("Image compression type: %i\n", compression);
+
+             image->compression = compression;
+             break;
+
+             /* I threw out all of the following: --cK */
+          case PROP_TATTOO:
+          case PROP_PARASITES:
+          case PROP_UNIT:
+          case PROP_PATHS:
+          case PROP_USER_UNIT:
+          case PROP_GUIDES:
+          case PROP_RESOLUTION:
+          default:
+             D("Skipping unexpected/unknown image property: %d\n", prop_type);
+
+             while (prop_size > 0)
+               {
+                  DATA8               buf[16];
+                  int                 amount;
+
+                  amount = (16 < prop_size ? 16 : prop_size);
+                  image->cp += xcf_read_int8(image->fp, buf, amount);
+                  prop_size -= (16 < amount ? 16 : amount);
+               }
+             break;
+          }
+     }
+
+   return 0;
+}
+
+static int
+xcf_load_layer_props(Layer * layer)
+{
+   PropType            prop_type;
+   DATA32              prop_size;
+
+   while (1)
+     {
+        if (!xcf_load_prop(&prop_type, &prop_size))
+           return 0;
+
+        switch (prop_type)
+          {
+          case PROP_END:
+             D("Finished reading layer properties.\n");
+             return 1;
           case PROP_FLOATING_SELECTION:
              D("Loading floating selection.\n");
              image->floating_sel = layer;
@@ -649,20 +829,18 @@ xcf_load_layer_props(Layer * layer)
           case PROP_SHOW_MASK:
           case PROP_PARASITES:
           default:
-             {
-                DATA8               buf[16];
-                int                 amount;
-
-                D("Skipping unexpected/unknown/unneeded channel property: 
%d\n",
-                  prop_type);
-
-                while (prop_size > 0)
-                  {
-                     amount = (16 < prop_size ? 16 : prop_size);
-                     image->cp += xcf_read_int8(image->fp, buf, amount);
-                     prop_size -= (16 < amount ? 16 : amount);
-                  }
-             }
+             D("Skipping unexpected/unknown/unneeded channel property: %d\n",
+               prop_type);
+
+             while (prop_size > 0)
+               {
+                  DATA8               buf[16];
+                  int                 amount;
+
+                  amount = (16 < prop_size ? 16 : prop_size);
+                  image->cp += xcf_read_int8(image->fp, buf, amount);
+                  prop_size -= (16 < amount ? 16 : amount);
+               }
              break;
           }
      }
@@ -670,87 +848,6 @@ xcf_load_layer_props(Layer * layer)
    return 0;
 }
 
-static Layer       *
-xcf_load_layer(void)
-{
-   Layer              *layer;
-   Layer              *layer_mask;
-   DATA32              hierarchy_offset;
-   DATA32              layer_mask_offset;
-   int                 width;
-   int                 height;
-   int                 type;
-   char               *name;
-
-   D("Loading one layer ...\n");
-
-   /* read in the layer width, height and type */
-   image->cp += xcf_read_int32(image->fp, (DATA32 *) & width, 1);
-   image->cp += xcf_read_int32(image->fp, (DATA32 *) & height, 1);
-   image->cp += xcf_read_int32(image->fp, (DATA32 *) & type, 1);
-   image->cp += xcf_read_string(image->fp, &name, 1);
-
-   /* ugly, I know */
-   FREE(name);
-
-   /* create a new layer */
-   layer = new_layer(width, height, type, 255, NORMAL_MODE);
-   if (!layer)
-      return NULL;
-
-   /* read in the layer properties */
-   if (!xcf_load_layer_props(layer))
-      goto error;
-
-   D("Loading opacity: %i \n", layer->opacity);
-
-   if (!layer->visible)
-      return layer;
-
-   /* read the hierarchy and layer mask offsets */
-   image->cp += xcf_read_int32(image->fp, &hierarchy_offset, 1);
-   image->cp += xcf_read_int32(image->fp, &layer_mask_offset, 1);
-
-   /* read in the hierarchy */
-   xcf_seek_pos(hierarchy_offset);
-   if (!xcf_load_hierarchy
-       (&(layer->tiles), &(layer->num_rows), &(layer->num_cols), 
&(layer->bpp)))
-      goto error;
-
-   /* read in the layer mask */
-   if (layer_mask_offset != 0)
-     {
-        D("Loading layer mask.\n");
-        xcf_seek_pos(layer_mask_offset);
-
-        layer_mask = xcf_load_channel();
-        if (!layer_mask)
-           goto error;
-
-        /* set the offsets of the layer_mask */
-        layer_mask->offset_x = layer->offset_x;
-        layer_mask->offset_y = layer->offset_y;
-        layer->mask = layer_mask;
-     }
-
-   read_tiles_into_data(layer->tiles, layer->num_cols,
-                        layer->width, layer->height,
-                        layer->bpp, &(layer->data), 1);
-   free_tiles(layer->tiles, layer->num_rows * layer->num_cols);
-   layer->tiles = NULL;
-
-   set_layer_opacity(layer);
-
-   if (layer->mask)
-      apply_layer_mask(layer);
-
-   return layer;
-
- error:
-   free_layer(layer);
-   return NULL;
-}
-
 static void
 read_tiles_into_data(Tile * tiles, int num_cols, int width,
                      int height, int bpp, DATA8 ** data_p, int use_cmap)
@@ -762,258 +859,229 @@ read_tiles_into_data(Tile * tiles, int num_cols, int 
width,
    Tile               *t;
    int                 warned = 0;
 
-   if (tiles)
-     {
-        if (*data_p)
-           FREE(*data_p);
+   if (!tiles)
+      return;
 
-        /* Always allocate the data as 4 bytes per pixel */
-        data = (*data_p) = malloc(sizeof(DATA32) * width * height);
+   if (*data_p)
+      free(*data_p);
 
-        ptr = data;
+   /* Always allocate the data as 4 bytes per pixel */
+   data = (*data_p) = malloc(sizeof(DATA32) * width * height);
 
-        for (y = 0; y < height; y++)
+   ptr = data;
+
+   for (y = 0; y < height; y++)
+     {
+        for (x = 0; x < width; x++)
           {
-             for (x = 0; x < width; x++)
-               {
-                  tile_x = x / TILE_WIDTH;
-                  tile_y = y / TILE_HEIGHT;
-                  offset_x = x % TILE_WIDTH;
-                  offset_y = y % TILE_HEIGHT;
+             tile_x = x / TILE_WIDTH;
+             tile_y = y / TILE_HEIGHT;
+             offset_x = x % TILE_WIDTH;
+             offset_y = y % TILE_HEIGHT;
 
-                  t = &tiles[tile_y * num_cols + tile_x];
-                  ptr2 =
-                     &(t->data[offset_y * t->ewidth * bpp + offset_x * bpp]);
+             t = &tiles[tile_y * num_cols + tile_x];
+             ptr2 = &(t->data[offset_y * t->ewidth * bpp + offset_x * bpp]);
 
-                  switch (bpp)
+             switch (bpp)
+               {
+               case 1:
+                  /* use colormap if the image has one */
+                  if (image->cmap && use_cmap)
+                    {
+                       R_VAL(ptr) = image->cmap[*(ptr2) * 3];
+                       G_VAL(ptr) = image->cmap[*(ptr2) * 3 + 1];
+                       B_VAL(ptr) = image->cmap[*(ptr2) * 3 + 2];
+                       A_VAL(ptr) = 255;
+                    }
+                  /* else use colors themselves */
+                  else
+                    {
+                       R_VAL(ptr) = *(ptr2);
+                       G_VAL(ptr) = *(ptr2);
+                       B_VAL(ptr) = *(ptr2);
+                       A_VAL(ptr) = 255;
+                    }
+                  break;
+               case 2:
+                  /* use colormap if the image has one */
+                  if (image->cmap && use_cmap)
+                    {
+                       R_VAL(ptr) = image->cmap[*(ptr2) * 3];
+                       G_VAL(ptr) = image->cmap[*(ptr2) * 3 + 1];
+                       B_VAL(ptr) = image->cmap[*(ptr2) * 3 + 2];
+                       A_VAL(ptr) = *(ptr2 + 1);
+                    }
+                  /* else use colors themselves */
+                  else if (warned == 0)
+                    {
+                       warned++;
+                       fprintf(stderr,
+                               "There's nothing to see here. 2 bpp without 
colormap not implemented yet.\n");
+                    }
+                  break;
+               case 3:
+                  if (image->cmap)
+                    {
+                       if (warned == 0)
+                         {
+                            warned++;
+                            fprintf(stderr,
+                                    "There's nothing to see here. 3 bpp with 
colormap not implemented yet.\n");
+                         }
+                    }
+                  else
                     {
-                    case 1:
-                       {
-                          /* use colormap if the image has one */
-                          if (image->cmap && use_cmap)
-                            {
-                               R_VAL(ptr) = image->cmap[*(ptr2) * 3];
-                               G_VAL(ptr) = image->cmap[*(ptr2) * 3 + 1];
-                               B_VAL(ptr) = image->cmap[*(ptr2) * 3 + 2];
-                               A_VAL(ptr) = 255;
-                            }
-                          /* else use colors themselves */
-                          else
-                            {
-                               R_VAL(ptr) = *(ptr2);
-                               G_VAL(ptr) = *(ptr2);
-                               B_VAL(ptr) = *(ptr2);
-                               A_VAL(ptr) = 255;
-                            }
-                          break;
-                       }
-                    case 2:
-                       {
-                          /* use colormap if the image has one */
-                          if (image->cmap && use_cmap)
-                            {
-                               R_VAL(ptr) = image->cmap[*(ptr2) * 3];
-                               G_VAL(ptr) = image->cmap[*(ptr2) * 3 + 1];
-                               B_VAL(ptr) = image->cmap[*(ptr2) * 3 + 2];
-                               A_VAL(ptr) = *(ptr2 + 1);
-                            }
-                          /* else use colors themselves */
-                          else if (warned == 0)
-                            {
-                               warned++;
-                               fprintf(stderr,
-                                       "There's nothing to see here. 2 bpp 
without colormap not implemented yet.\n");
-                            }
-                          break;
-                       }
-                    case 3:
-                       {
-                          if (image->cmap)
-                            {
-                               if (warned == 0)
-                                 {
-                                    warned++;
-                                    fprintf(stderr,
-                                            "There's nothing to see here. 3 
bpp with colormap not implemented yet.\n");
-                                 }
-                            }
-                          else
-                            {
-                               R_VAL(ptr) = *(ptr2);
-                               G_VAL(ptr) = *(ptr2 + 1);
-                               B_VAL(ptr) = *(ptr2 + 2);
-                               A_VAL(ptr) = 255;
-                            }
-                          break;
-                       }
-                    default:
-                       {
-                          R_VAL(ptr) = *(ptr2);
-                          G_VAL(ptr) = *(ptr2 + 1);
-                          B_VAL(ptr) = *(ptr2 + 2);
-                          A_VAL(ptr) = *(ptr2 + 3);
-                          break;
-                       }
+                       R_VAL(ptr) = *(ptr2);
+                       G_VAL(ptr) = *(ptr2 + 1);
+                       B_VAL(ptr) = *(ptr2 + 2);
+                       A_VAL(ptr) = 255;
                     }
-                  ptr += 4;
+                  break;
+               default:
+                  R_VAL(ptr) = *(ptr2);
+                  G_VAL(ptr) = *(ptr2 + 1);
+                  B_VAL(ptr) = *(ptr2 + 2);
+                  A_VAL(ptr) = *(ptr2 + 3);
+                  break;
                }
+             ptr += 4;
           }
      }
 }
 
-static Layer       *
-xcf_load_channel(void)
+static int
+xcf_load_tile(Tile * tile)
 {
-   Layer              *layer;
-   DATA32              hierarchy_offset;
-   int                 width;
-   int                 height;
-   char               *name;
-
-   D("Loading channel ...\n");
-
-   /* read in the layer width, height and name */
-   image->cp += xcf_read_int32(image->fp, (DATA32 *) & width, 1);
-   image->cp += xcf_read_int32(image->fp, (DATA32 *) & height, 1);
-   image->cp += xcf_read_string(image->fp, &name, 1);
-
-   /* Yeah, still ugly :) */
-   FREE(name);
-
-   /* create a new channel */
-   layer = new_layer(width, height, GRAY, 255, NORMAL_MODE);
-   if (!layer)
-      return NULL;
-
-   /* read in the channel properties */
-   if (!xcf_load_channel_props(layer))
-      goto error;
-
-   /* read the hierarchy and layer mask offsets */
-   image->cp += xcf_read_int32(image->fp, &hierarchy_offset, 1);
+   image->cp +=
+      xcf_read_int8(image->fp, tile->data,
+                    tile->ewidth * tile->eheight * tile->bpp);
+   return 1;
+}
 
-   /* read in the hierarchy */
-   xcf_seek_pos(hierarchy_offset);
-   if (!xcf_load_hierarchy
-       (&(layer->tiles), &(layer->num_rows), &(layer->num_cols), 
&(layer->bpp)))
-      goto error;
+static int
+xcf_load_tile_rle(Tile * tile, int data_length)
+{
+   DATA8              *data;
+   DATA8               val;
+   int                 size;
+   int                 count;
+   int                 length;
+   int                 bpp;
+   int                 i, j;
+   int                 nmemb_read_successfully;
+   DATA8              *xcfdata, *xcfodata, *xcfdatalimit;
 
-   read_tiles_into_data(layer->tiles, layer->num_cols, layer->width,
-                        layer->height, layer->bpp, &(layer->data), 0);
-   free_tiles(layer->tiles, layer->num_rows * layer->num_cols);
-   layer->tiles = NULL;
+   data = tile->data;
+   bpp = tile->bpp;
 
-   D("Channel loaded successfully.\n");
+   /*printf ("Reading encrypted tile %ix%ix%i, data_length %i\n", 
tile->ewidth, tile->eheight, tile->bpp, data_length); */
 
-   return layer;
+   xcfdata = xcfodata = malloc(sizeof(DATA8) * data_length);
 
- error:
-   free_layer(layer);
-   return NULL;
-}
+   /* we have to use fread instead of xcf_read_* because we may be
+    * reading past the end of the file here */
+   nmemb_read_successfully = fread(xcfdata, 1, data_length, image->fp);
+   image->cp += nmemb_read_successfully;
 
-static char
-xcf_load_channel_props(Layer * layer)
-{
-   PropType            prop_type;
-   DATA32              prop_size;
+   xcfdatalimit = &xcfodata[nmemb_read_successfully - 1];
 
-   while (1)
+   for (i = 0; i < bpp; i++)
      {
-        if (!xcf_load_prop(&prop_type, &prop_size))
-           return 0;
+        data = (tile->data) + i;
+        size = tile->ewidth * tile->eheight;
+        count = 0;
 
-        switch (prop_type)
+        while (size > 0)
           {
-          case PROP_END:
-             {
-                D("Finished loading channel props.\n");
-                return 1;
-             }
-          case PROP_OPACITY:
-             image->cp +=
-                xcf_read_int32(image->fp, (DATA32 *) & layer->opacity, 1);
-             break;
-          case PROP_VISIBLE:
-             image->cp +=
-                xcf_read_int32(image->fp, (DATA32 *) & layer->visible, 1);
-             break;
-          case PROP_ACTIVE_CHANNEL:
-          case PROP_SHOW_MASKED:
-          case PROP_SELECTION:
-          case PROP_COLOR:
-          case PROP_TATTOO:
-          case PROP_PARASITES:
-          default:
-             {
-                DATA8               buf[16];
-                int                 amount;
-
-                D("Skipping unexpected/unknown/unneeded channel property: 
%d\n",
-                  prop_type);
-
-                while (prop_size > 0)
-                  {
-                     amount = (16 < prop_size ? 16 : prop_size);
-                     image->cp += xcf_read_int8(image->fp, buf, amount);
-                     prop_size -= (16 < amount ? 16 : amount);
-                  }
-             }
-             break;
-          }
-     }
+             if (xcfdata > xcfdatalimit)
+               {
+                  goto bogus_rle;
+               }
 
-   return 0;
-}
+             val = *xcfdata++;
 
-static char
-xcf_load_hierarchy(Tile ** tiles, int *num_rows, int *num_cols, int *bpp)
-{
-   DATA32              saved_pos;
-   DATA32              offset;
-   DATA32              junk;
-   int                 width;
-   int                 height;
+             length = val;
+             if (length >= 128)
+               {
+                  length = 255 - (length - 1);
+                  if (length == 128)
+                    {
+                       if (xcfdata >= xcfdatalimit)
+                         {
+                            goto bogus_rle;
+                         }
 
-   image->cp += xcf_read_int32(image->fp, (DATA32 *) & width, 1);
-   image->cp += xcf_read_int32(image->fp, (DATA32 *) & height, 1);
-   image->cp += xcf_read_int32(image->fp, (DATA32 *) bpp, 1);
+                       length = (*xcfdata << 8) + xcfdata[1];
+                       xcfdata += 2;
+                    }
 
-   image->cp += xcf_read_int32(image->fp, &offset, 1);  /* top level */
+                  count += length;
+                  size -= length;
 
-   D("Loading hierarchy: width %i, height %i,  bpp %i\n", width, height, *bpp);
+                  if (size < 0)
+                    {
+                       goto bogus_rle;
+                    }
 
-   /* discard offsets for layers below first, if any.
-    */
-   do
-     {
-        image->cp += xcf_read_int32(image->fp, &junk, 1);
-     }
-   while (junk != 0);
+                  if (&xcfdata[length - 1] > xcfdatalimit)
+                    {
+                       goto bogus_rle;
+                    }
 
-   /* save the current position as it is where the
-    *  next level offset is stored.
-    */
-   saved_pos = image->cp;
+                  while (length-- > 0)
+                    {
+                       *data = *xcfdata++;
+                       data += bpp;
+                    }
+               }
+             else
+               {
+                  length += 1;
+                  if (length == 128)
+                    {
+                       if (xcfdata >= xcfdatalimit)
+                         {
+                            goto bogus_rle;
+                         }
 
-   /* seek to the level offset */
-   xcf_seek_pos(offset);
+                       length = (*xcfdata << 8) + xcfdata[1];
+                       xcfdata += 2;
+                    }
 
-   /* read in the level */
-   if (!xcf_load_level(tiles, width, height, *bpp, num_rows, num_cols))
-      return 0;
+                  count += length;
+                  size -= length;
 
-   /* restore the saved position so we'll be ready to
-    *  read the next offset.
-    */
-   xcf_seek_pos(saved_pos);
+                  if (size < 0)
+                    {
+                       goto bogus_rle;
+                    }
 
-   D("Loaded hierarchy successfully.\n");
+                  if (xcfdata > xcfdatalimit)
+                    {
+                       goto bogus_rle;
+                    }
 
+                  val = *xcfdata++;
+
+                  for (j = 0; j < length; j++)
+                    {
+                       *data = val;
+                       data += bpp;
+                    }
+               }
+          }
+     }
+   free(xcfodata);
    return 1;
+
+ bogus_rle:
+   fprintf(stderr,
+           "WHOOOOOP -- bogus rle? Highly unlikely, blame cK for this one :) 
\n");
+   free(xcfodata);
+   return 0;
 }
 
-static char
+static int
 xcf_load_level(Tile ** tiles_p, int hierarchy_width, int hierarchy_height,
                int bpp, int *num_rows, int *num_cols)
 {
@@ -1120,464 +1188,323 @@ xcf_load_level(Tile ** tiles_p, int hierarchy_width, 
int hierarchy_height,
    return 1;
 }
 
-static char
-xcf_load_tile(Tile * tile)
-{
-   image->cp +=
-      xcf_read_int8(image->fp, tile->data,
-                    tile->ewidth * tile->eheight * tile->bpp);
-   return 1;
-}
-
-static char
-xcf_load_tile_rle(Tile * tile, int data_length)
+static int
+xcf_load_hierarchy(Tile ** tiles, int *num_rows, int *num_cols, int *bpp)
 {
-   DATA8              *data;
-   DATA8               val;
-   int                 size;
-   int                 count;
-   int                 length;
-   int                 bpp;
-   int                 i, j;
-   int                 nmemb_read_successfully;
-   DATA8              *xcfdata, *xcfodata, *xcfdatalimit;
-
-   data = tile->data;
-   bpp = tile->bpp;
-
-   /*printf ("Reading encrypted tile %ix%ix%i, data_length %i\n", 
tile->ewidth, tile->eheight, tile->bpp, data_length); */
-
-   xcfdata = xcfodata = malloc(sizeof(DATA8) * data_length);
-
-   /* we have to use fread instead of xcf_read_* because we may be
-    * reading past the end of the file here */
-   nmemb_read_successfully = fread((char *)xcfdata, sizeof(char),
-                                   data_length, image->fp);
-   image->cp += nmemb_read_successfully;
-
-   xcfdatalimit = &xcfodata[nmemb_read_successfully - 1];
+   DATA32              saved_pos;
+   DATA32              offset;
+   DATA32              junk;
+   int                 width;
+   int                 height;
 
-   for (i = 0; i < bpp; i++)
-     {
-        data = (tile->data) + i;
-        size = tile->ewidth * tile->eheight;
-        count = 0;
+   image->cp += xcf_read_int32(image->fp, (DATA32 *) & width, 1);
+   image->cp += xcf_read_int32(image->fp, (DATA32 *) & height, 1);
+   image->cp += xcf_read_int32(image->fp, (DATA32 *) bpp, 1);
 
-        while (size > 0)
-          {
-             if (xcfdata > xcfdatalimit)
-               {
-                  goto bogus_rle;
-               }
+   image->cp += xcf_read_int32(image->fp, &offset, 1);  /* top level */
 
-             val = *xcfdata++;
+   D("Loading hierarchy: width %i, height %i,  bpp %i\n", width, height, *bpp);
 
-             length = val;
-             if (length >= 128)
-               {
-                  length = 255 - (length - 1);
-                  if (length == 128)
-                    {
-                       if (xcfdata >= xcfdatalimit)
-                         {
-                            goto bogus_rle;
-                         }
+   /* discard offsets for layers below first, if any.
+    */
+   do
+     {
+        image->cp += xcf_read_int32(image->fp, &junk, 1);
+     }
+   while (junk != 0);
 
-                       length = (*xcfdata << 8) + xcfdata[1];
-                       xcfdata += 2;
-                    }
+   /* save the current position as it is where the
+    *  next level offset is stored.
+    */
+   saved_pos = image->cp;
 
-                  count += length;
-                  size -= length;
+   /* seek to the level offset */
+   xcf_seek_pos(offset);
 
-                  if (size < 0)
-                    {
-                       goto bogus_rle;
-                    }
+   /* read in the level */
+   if (!xcf_load_level(tiles, width, height, *bpp, num_rows, num_cols))
+      return 0;
 
-                  if (&xcfdata[length - 1] > xcfdatalimit)
-                    {
-                       goto bogus_rle;
-                    }
+   /* restore the saved position so we'll be ready to
+    *  read the next offset.
+    */
+   xcf_seek_pos(saved_pos);
 
-                  while (length-- > 0)
-                    {
-                       *data = *xcfdata++;
-                       data += bpp;
-                    }
-               }
-             else
-               {
-                  length += 1;
-                  if (length == 128)
-                    {
-                       if (xcfdata >= xcfdatalimit)
-                         {
-                            goto bogus_rle;
-                         }
+   D("Loaded hierarchy successfully.\n");
 
-                       length = (*xcfdata << 8) + xcfdata[1];
-                       xcfdata += 2;
-                    }
+   return 1;
+}
 
-                  count += length;
-                  size -= length;
+static int
+xcf_load_channel_props(Layer * layer)
+{
+   PropType            prop_type;
+   DATA32              prop_size;
 
-                  if (size < 0)
-                    {
-                       goto bogus_rle;
-                    }
+   while (1)
+     {
+        if (!xcf_load_prop(&prop_type, &prop_size))
+           return 0;
 
-                  if (xcfdata > xcfdatalimit)
-                    {
-                       goto bogus_rle;
-                    }
+        switch (prop_type)
+          {
+          case PROP_END:
+             D("Finished loading channel props.\n");
+             return 1;
+          case PROP_OPACITY:
+             image->cp +=
+                xcf_read_int32(image->fp, (DATA32 *) & layer->opacity, 1);
+             break;
+          case PROP_VISIBLE:
+             image->cp +=
+                xcf_read_int32(image->fp, (DATA32 *) & layer->visible, 1);
+             break;
+          case PROP_ACTIVE_CHANNEL:
+          case PROP_SHOW_MASKED:
+          case PROP_SELECTION:
+          case PROP_COLOR:
+          case PROP_TATTOO:
+          case PROP_PARASITES:
+          default:
+             D("Skipping unexpected/unknown/unneeded channel property: %d\n",
+               prop_type);
 
-                  val = *xcfdata++;
+             while (prop_size > 0)
+               {
+                  DATA8               buf[16];
+                  int                 amount;
 
-                  for (j = 0; j < length; j++)
-                    {
-                       *data = val;
-                       data += bpp;
-                    }
+                  amount = (16 < prop_size ? 16 : prop_size);
+                  image->cp += xcf_read_int8(image->fp, buf, amount);
+                  prop_size -= (16 < amount ? 16 : amount);
                }
+             break;
           }
      }
-   FREE(xcfodata);
-   return 1;
 
- bogus_rle:
-   fprintf(stderr,
-           "WHOOOOOP -- bogus rle? Highly unlikely, blame cK for this one :) 
\n");
-   if (xcfodata)
-      FREE(xcfodata);
    return 0;
 }
 
 static Layer       *
-new_layer(int width, int height, GimpImageType type, int opacity,
-          LayerModeEffects mode)
+xcf_load_channel(void)
 {
    Layer              *layer;
+   DATA32              hierarchy_offset;
+   int                 width;
+   int                 height;
+   char               *name;
+
+   D("Loading channel ...\n");
+
+   /* read in the layer width, height and name */
+   image->cp += xcf_read_int32(image->fp, (DATA32 *) & width, 1);
+   image->cp += xcf_read_int32(image->fp, (DATA32 *) & height, 1);
+   image->cp += xcf_read_string(image->fp, &name, 1);
+
+   /* Yeah, still ugly :) */
+   free(name);
 
-   layer = malloc(sizeof(Layer));
+   /* create a new channel */
+   layer = new_layer(width, height, GRAY, 255, NORMAL_MODE);
    if (!layer)
-     {
-        D("Couldn't allocate layer.\n");
-        return NULL;
-     }
+      return NULL;
 
-   bzero(layer, sizeof(Layer));
+   /* read in the channel properties */
+   if (!xcf_load_channel_props(layer))
+      goto error;
 
-   layer->width = width;
-   layer->height = height;
-   layer->type = type;
-   layer->opacity = opacity;
-   layer->mode = mode;
+   /* read the hierarchy and layer mask offsets */
+   image->cp += xcf_read_int32(image->fp, &hierarchy_offset, 1);
+
+   /* read in the hierarchy */
+   xcf_seek_pos(hierarchy_offset);
+   if (!xcf_load_hierarchy
+       (&(layer->tiles), &(layer->num_rows), &(layer->num_cols), 
&(layer->bpp)))
+      goto error;
 
+   read_tiles_into_data(layer->tiles, layer->num_cols, layer->width,
+                        layer->height, layer->bpp, &(layer->data), 0);
+   free_tiles(layer->tiles, layer->num_rows * layer->num_cols);
    layer->tiles = NULL;
-   layer->next = NULL;
-   layer->mask = NULL;
+
+   D("Channel loaded successfully.\n");
 
    return layer;
+
+ error:
+   free_layer(layer);
+   return NULL;
 }
 
-static void
-free_layer(Layer * layer)
+static Layer       *
+xcf_load_layer(void)
 {
-   if (layer)
-     {
-        if (layer->tiles)
-           free_tiles(layer->tiles, layer->num_rows * layer->num_cols);
+   Layer              *layer;
+   Layer              *layer_mask;
+   DATA32              hierarchy_offset;
+   DATA32              layer_mask_offset;
+   int                 width;
+   int                 height;
+   int                 type;
+   char               *name;
+
+   D("Loading one layer ...\n");
+
+   /* read in the layer width, height and type */
+   image->cp += xcf_read_int32(image->fp, (DATA32 *) & width, 1);
+   image->cp += xcf_read_int32(image->fp, (DATA32 *) & height, 1);
+   image->cp += xcf_read_int32(image->fp, (DATA32 *) & type, 1);
+   image->cp += xcf_read_string(image->fp, &name, 1);
 
-        if (layer->mask)
-           free_layer(layer->mask);
+   /* ugly, I know */
+   free(name);
 
-        if (layer->data)
-           FREE(layer->data);
+   /* create a new layer */
+   layer = new_layer(width, height, type, 255, NORMAL_MODE);
+   if (!layer)
+      return NULL;
 
-        FREE(layer);
-     }
-}
+   /* read in the layer properties */
+   if (!xcf_load_layer_props(layer))
+      goto error;
 
-static Tile        *
-allocate_tiles(int width, int height, int bpp, int *num_rows, int *num_cols)
-{
-   Tile               *tiles;
-   int                 i, j, k, right_tile, bottom_tile;
-   int                 tile_width, tile_height;
+   D("Loading opacity: %i \n", layer->opacity);
 
-   (*num_rows) = (height + TILE_HEIGHT - 1) / TILE_HEIGHT;
-   (*num_cols) = (width + TILE_WIDTH - 1) / TILE_WIDTH;
+   if (!layer->visible)
+      return layer;
 
-   tiles = malloc(sizeof(Tile) * (*num_rows) * (*num_cols));
-   if (!tiles)
-     {
-        D("Couldn't allocate tiles.\n");
-        return NULL;
-     }
+   /* read the hierarchy and layer mask offsets */
+   image->cp += xcf_read_int32(image->fp, &hierarchy_offset, 1);
+   image->cp += xcf_read_int32(image->fp, &layer_mask_offset, 1);
 
-   right_tile = width - (((*num_cols) - 1) * TILE_WIDTH);
-   bottom_tile = height - (((*num_rows) - 1) * TILE_HEIGHT);
+   /* read in the hierarchy */
+   xcf_seek_pos(hierarchy_offset);
+   if (!xcf_load_hierarchy
+       (&(layer->tiles), &(layer->num_rows), &(layer->num_cols), 
&(layer->bpp)))
+      goto error;
 
-   for (i = 0, k = 0; i < (*num_rows); i++)
+   /* read in the layer mask */
+   if (layer_mask_offset != 0)
      {
-        for (j = 0; j < (*num_cols); j++, k++)
-          {
-             tile_width = ((j == (*num_cols) - 1) ? right_tile : TILE_WIDTH);
-             tile_height = ((i == (*num_rows) - 1) ? bottom_tile : 
TILE_HEIGHT);
-             init_tile(&(tiles[k]), tile_width, tile_height, bpp);
-          }
+        D("Loading layer mask.\n");
+        xcf_seek_pos(layer_mask_offset);
+
+        layer_mask = xcf_load_channel();
+        if (!layer_mask)
+           goto error;
+
+        /* set the offsets of the layer_mask */
+        layer_mask->offset_x = layer->offset_x;
+        layer_mask->offset_y = layer->offset_y;
+        layer->mask = layer_mask;
      }
 
-   D("Allocated %ix%i tiles.\n", (*num_cols), (*num_rows));
+   read_tiles_into_data(layer->tiles, layer->num_cols,
+                        layer->width, layer->height,
+                        layer->bpp, &(layer->data), 1);
+   free_tiles(layer->tiles, layer->num_rows * layer->num_cols);
+   layer->tiles = NULL;
 
-   return tiles;
-}
+   set_layer_opacity(layer);
 
-static void
-init_tile(Tile * tile, int width, int height, int bpp)
-{
-   if (tile)
-     {
-        tile->bpp = bpp;
-        tile->ewidth = width;
-        tile->eheight = height;
-        tile->data = malloc(sizeof(DATA8) * width * height * bpp);
-        if (!tile->data)
-          {
-             D("Couldn't allocate tile.\n");
-          }
-     }
-}
+   if (layer->mask)
+      apply_layer_mask(layer);
 
-static void
-free_tiles(Tile * tiles, int num_tiles)
-{
-   int                 i;
+   return layer;
 
-   for (i = 0; i < num_tiles; i++)
-     {
-        if (tiles[i].data)
-           FREE(tiles[i].data);
-     }
-   FREE(tiles);
+ error:
+   free_layer(layer);
+   return NULL;
 }
 
 static void
-add_layer_to_image(Layer * layer)
+xcf_load_image(void)
 {
-   if (layer)
-     {
-        if (image->last_layer)
-          {
-             image->last_layer->next = layer;
-             layer->prev = image->last_layer;
-          }
-        else
-          {
-             image->layers = layer;
-             layer->prev = NULL;
-          }
-        layer->next = NULL;
-        image->last_layer = layer;
-     }
-}
+   Layer              *layer;
+   DATA32              saved_pos;
+   DATA32              offset;
+   int                 width;
+   int                 height;
+   int                 image_type;
+   int                 num_successful_elements = 0;
 
-static void
-set_layer_opacity(Layer * layer)
-{
-   int                 i;
-   DATA8              *ptr;
+   /* read in the image width, height and type */
+   image->cp += xcf_read_int32(image->fp, (DATA32 *) & width, 1);
+   image->cp += xcf_read_int32(image->fp, (DATA32 *) & height, 1);
+   image->cp += xcf_read_int32(image->fp, (DATA32 *) & image_type, 1);
 
-   if (layer)
-     {
-        if (layer->opacity != 255)
-          {
-             for (i = 0, ptr = layer->data; i < layer->width * layer->height;
-                  i++, ptr += 4)
-               {
-                  *(ptr + 3) = (*(ptr + 3) * layer->opacity) >> 8;
-               }
-          }
-     }
-}
+   image->width = width;
+   image->height = height;
+   image->base_type = image_type;
 
-static void
-apply_layer_mask(Layer * layer)
-{
-   DATA8              *ptr1;
-   DATA8              *ptr2;
-   int                 i, tmp;
+   D("Loading %ix%i image.\n", width, height);
 
-   D("Applying layer mask.\n");
+   /* read the image properties */
+   if (!xcf_load_image_props())
+      goto hard_error;
 
-   if (layer)
+   while (1)
      {
-        if (layer->mask)
-          {
-             ptr1 = layer->data;
-             ptr2 = layer->mask->data;
+        /* read in the offset of the next layer */
+        image->cp += xcf_read_int32(image->fp, &offset, 1);
 
-             for (i = 0; i < layer->width * layer->height; i++)
-               {
-                  tmp = (*(ptr1 + 3) * *(ptr2)) / 256;
-                  if (tmp > 255)
-                     tmp = 255;
+        /* if the offset is 0 then we are at the end
+         *  of the layer list.
+         */
+        if (offset == 0)
+           break;
 
-                  *(ptr1 + 3) = (DATA8) tmp;
-                  ptr1 += 4;
-                  ptr2 += 4;
-               }
-          }
-     }
-}
+        /* save the current position as it is where the
+         *  next layer offset is stored.
+         */
+        saved_pos = image->cp;
 
-static void
-flatten_image(void)
-{
-   Layer              *l = image->last_layer;
-   Layer              *lp;
-   int                 layer_index;
+        /* seek to the layer offset */
+        xcf_seek_pos(offset);
 
-   image->data = calloc(image->width * image->height, sizeof(DATA32));
-   layer_index = 0;
+        /* read in the layer */
+        layer = xcf_load_layer();
+        if (!layer)
+           goto error;
 
-   while (l)
-     {
-        /* Ok, paste each layer on top of the image, using the mode's merging 
type.
-         * We're moving upward through the layer stack.
-         * --cK.
+        num_successful_elements++;
+
+        /* add the layer to the image if it's visible */
+        if (layer->visible)
+           add_layer_to_image(layer);
+        else
+           free_layer(layer);
+
+        /* restore the saved position so we'll be ready to
+         *  read the next offset.
          */
-        if (image->single_layer_index < 0
-            || layer_index == image->single_layer_index)
-          {
-             switch (l->mode)
-               {
-               case MULTIPLY_MODE:
-                  D("MULTIPLY\n");
-                  combine_pixels_mult(l->data, l->width, l->height,
-                                      image->data, image->width, image->height,
-                                      l->offset_x, l->offset_y);
-                  break;
-               case DIVIDE_MODE:
-                  D("DIVIDE\n");
-                  combine_pixels_div(l->data, l->width, l->height,
-                                     image->data, image->width, image->height,
-                                     l->offset_x, l->offset_y);
-                  break;
-               case SCREEN_MODE:
-                  D("SCREEN\n");
-                  combine_pixels_screen(l->data, l->width, l->height,
-                                        image->data, image->width,
-                                        image->height, l->offset_x,
-                                        l->offset_y);
-                  break;
-               case OVERLAY_MODE:
-                  D("OVERLAY\n");
-                  combine_pixels_overlay(l->data, l->width, l->height,
-                                         image->data, image->width,
-                                         image->height, l->offset_x,
-                                         l->offset_y);
-                  break;
-               case DIFFERENCE_MODE:
-                  D("DIFF\n");
-                  combine_pixels_diff(l->data, l->width, l->height,
-                                      image->data, image->width, image->height,
-                                      l->offset_x, l->offset_y);
-                  break;
-               case ADDITION_MODE:
-                  D("ADD\n");
-                  combine_pixels_add(l->data, l->width, l->height,
-                                     image->data, image->width, image->height,
-                                     l->offset_x, l->offset_y);
-                  break;
-               case SUBTRACT_MODE:
-                  D("SUB\n");
-                  combine_pixels_sub(l->data, l->width, l->height,
-                                     image->data, image->width, image->height,
-                                     l->offset_x, l->offset_y);
-                  break;
-               case DARKEN_ONLY_MODE:
-                  D("DARKEN\n");
-                  combine_pixels_darken(l->data, l->width, l->height,
-                                        image->data, image->width,
-                                        image->height, l->offset_x,
-                                        l->offset_y);
-                  break;
-               case LIGHTEN_ONLY_MODE:
-                  D("LIGHTEN\n");
-                  combine_pixels_lighten(l->data, l->width, l->height,
-                                         image->data, image->width,
-                                         image->height, l->offset_x,
-                                         l->offset_y);
-                  break;
+        xcf_seek_pos(saved_pos);
 
-               case HUE_MODE:
-                  D("HUE\n");
-                  combine_pixels_hue(l->data, l->width, l->height,
-                                     image->data, image->width, image->height,
-                                     l->offset_x, l->offset_y);
-                  break;
-               case SATURATION_MODE:
-                  D("SATURATION\n");
-                  combine_pixels_sat(l->data, l->width, l->height,
-                                     image->data, image->width, image->height,
-                                     l->offset_x, l->offset_y);
-                  break;
-               case VALUE_MODE:
-                  D("VALUE\n");
-                  combine_pixels_val(l->data, l->width, l->height,
-                                     image->data, image->width, image->height,
-                                     l->offset_x, l->offset_y);
-                  break;
-               case COLOR_MODE:
-                  D("COLOR\n");
-                  combine_pixels_col(l->data, l->width, l->height,
-                                     image->data, image->width, image->height,
-                                     l->offset_x, l->offset_y);
-                  break;
-               case DISSOLVE_MODE:
-                  D("DISSOLVE\n");
-                  combine_pixels_diss(l->data, l->width, l->height,
-                                      image->data, image->width, image->height,
-                                      l->offset_x, l->offset_y);
-                  break;
+     }
 
-                  /* None of the following is actually valid for layer 
blending, fall through: */
-               case BEHIND_MODE:
-               case REPLACE_MODE:
-               case ERASE_MODE:
-               case ANTI_ERASE_MODE:
-                  D("EEEEEK -- this mode shouldn't be here\n");
+   /* If we were a Gimp we would now load the user-defined channels here ... */
 
-               case NORMAL_MODE:
-                  D("NORMAL\n");
-                  combine_pixels_normal(l->data, l->width, l->height,
-                                        image->data, image->width,
-                                        image->height, l->offset_x,
-                                        l->offset_y);
-                  break;
+   /* Flat-o-rama now :) */
+   flatten_image();
 
-               default:
-                  D("Unknown layer mode: %i. Skipping.\n", l->mode);
-               }
-          }
+   return;
 
-        lp = l->prev;
-        /* free the layer now, since it's not needed anymore */
-        free_layer(l);
+ error:
+   if (num_successful_elements == 0)
+      goto hard_error;
 
-        l = lp;
-        layer_index++;
-     }
+   fprintf(stderr,
+           "XCF: This file is corrupt!  I have loaded as much of it as I can, 
but it is incomplete.\n");
 
-   /* We've used up all the layers now, so set them to NULL in the image: */
-   image->layers = NULL;
-   image->last_layer = NULL;
+   return;
+
+ hard_error:
+   fprintf(stderr,
+           "XCF: This file is corrupt!  I could not even salvage any partial 
image data from it.\n");
+   return;
 }
 
-static char
+static int
 xcf_file_init(char *filename)
 {
    char                success = 1;
@@ -1645,7 +1572,10 @@ xcf_cleanup(void)
      }
 
    if (image->cmap)
-      FREE(image->cmap);
+     {
+        free(image->cmap);
+        image->cmap = NULL;
+     }
 }
 
 static void

-- 


Reply via email to