xcf_load_level (XcfInfo     *info,
                TileManager *tiles)
{
  guint32 saved_pos;
  guint32 offset, offset2;
  guint ntiles;
  gint  width;
  gint  height;
  gint  i;
  gint  fail;
  Tile *previous;
  Tile *tile;

  info->cp += xcf_read_int32 (info->fp, (guint32 *) &width, 1);
  info->cp += xcf_read_int32 (info->fp, (guint32 *) &height, 1);

  if (width  != tile_manager_width  (tiles) ||
      height != tile_manager_height (tiles))
    return FALSE;

  /* read in the first tile offset.
   *  if it is '0', then this tile level is empty
   *  and we can simply return.
   */
  info->cp += xcf_read_int32 (info->fp, &offset, 1);
  if (offset == 0)
    return TRUE;

  /* Initialize the reference for the in-memory tile-compression
   */
  previous = NULL;

  ntiles = tiles->ntile_rows * tiles->ntile_cols;
  for (i = 0; i < ntiles; i++)
    {
      fail = FALSE;

      if (offset == 0)
        {
          gimp_message_literal (info->gimp, G_OBJECT (info->progress),
				GIMP_MESSAGE_ERROR,
				"not enough tiles found in level");
          return FALSE;
        }

      /* save the current position as it is where the
       *  next tile offset is stored.
       */
      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->fp, &offset2, 1);

      /* if the offset is 0 then we need to read in the maximum possible
         allowing for negative compression */
      if (offset2 == 0)
        offset2 = offset + TILE_WIDTH * TILE_WIDTH * 4 * 1.5;
                                        /* 1.5 is probably more
                                           than we need to allow */

      /* seek to the tile offset */
      if (! xcf_seek_pos (info, offset, NULL))
        return FALSE;

      /* get the tile from the tile manager */
      tile = tile_manager_get (tiles, i, TRUE, TRUE);

      /* read in the tile */
      switch (info->compression)
        {
        case COMPRESS_NONE:
          if (!xcf_load_tile (info, tile))
            fail = TRUE;
          break;
        case COMPRESS_RLE:
          if (!xcf_load_tile_rle (info, tile, offset2 - offset))
            fail = TRUE;
          break;
        case COMPRESS_ZLIB:
          g_warning ("xcf: zlib compression unimplemented");
          fail = TRUE;
          break;
        case COMPRESS_FRACTAL:
          g_warning ("xcf: fractal compression unimplemented");
          fail = TRUE;
          break;
        default:
          g_warning ("xcf: unknown compression");
          fail = TRUE;
          break;
        }

      if (fail)
        {
          tile_release (tile, TRUE);
          return FALSE;
        }

      /* To potentially save memory, we compare the
       *  newly-fetched tile against the last one, and
       *  if they're the same we copy-on-write mirror one against
       *  the other.
       */
      if (previous != NULL)
        {
          tile_lock (previous);
          if (tile_ewidth (tile) == tile_ewidth (previous) &&
              tile_eheight (tile) == tile_eheight (previous) &&
              tile_bpp (tile) == tile_bpp (previous) &&
              memcmp (tile_data_pointer (tile, 0, 0),
                      tile_data_pointer (previous, 0, 0),
                      tile_size (tile)) == 0)
            tile_manager_map (tiles, i, previous);
          tile_release (previous, FALSE);
        }
      tile_release (tile, TRUE);
      previous = tile_manager_get (tiles, i, FALSE, FALSE);

      /* restore the saved position so we'll be ready to
       *  read the next offset.
       */
      if (!xcf_seek_pos (info, saved_pos, NULL))
        return FALSE;

      /* read in the offset of the next tile */
      info->cp += xcf_read_int32 (info->fp, &offset, 1);
    }

  if (offset != 0)
    {
      gimp_message (info->gimp, G_OBJECT (info->progress), GIMP_MESSAGE_ERROR,
                    "encountered garbage after reading level: %d", offset);
      return FALSE;
    }

  return TRUE;
}