xcf_load_image (Gimp     *gimp,
                XcfInfo  *info,
                GError  **error)
{
  GimpImage          *image = NULL;
  const GimpParasite *parasite;
  guint32             saved_pos;
  guint32             offset;
  gint                width;
  gint                height;
  gint                image_type;
  gint                num_successful_elements = 0;
  guint32             retry_offset;
  gboolean            retried                 = FALSE;
  gboolean            terminate_loop            = FALSE;

  /* read in the image width, height and type */
  info->cp += xcf_read_int32 (info->fp, (guint32 *) &width, 1);
  info->cp += xcf_read_int32 (info->fp, (guint32 *) &height, 1);
  info->cp += xcf_read_int32 (info->fp, (guint32 *) &image_type, 1);
  if (image_type < GIMP_RGB || image_type > GIMP_INDEXED ||
      width <= 0 || height <= 0)
    goto hard_error;

  image = gimp_create_image (gimp, width, height, image_type, FALSE);

  gimp_image_undo_disable (image);

  xcf_progress_update (info);

  /* read the image properties */
  if (! xcf_load_image_props (info, image))
    goto hard_error;

  /* check for a GimpGrid parasite */
  parasite = gimp_image_parasite_find (GIMP_IMAGE (image),
                                       gimp_grid_parasite_name ());
  if (parasite)
    {
      GimpGrid *grid = gimp_grid_from_parasite (parasite);

      if (grid)
        {
          GimpImagePrivate *private = GIMP_IMAGE_GET_PRIVATE (image);

          gimp_parasite_list_remove (private->parasites,
                                     gimp_parasite_name (parasite));

          gimp_image_set_grid (GIMP_IMAGE (image), grid, FALSE);
          g_object_unref (grid);
        }
    }

  xcf_progress_update (info);

  retry_offset = info->cp;

  /* read in layers and channels; retry one time when they are accidently
   * shifted in the file (see bug #730211)
   */
  while (! terminate_loop)
    {
      while (TRUE)
        {
          GimpLayer *layer;
          GList     *item_path = NULL;

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

          /* if the offset is 0 then we are at the end
           *  of the layer list.
           */
          if (offset == 0)
            break;

          /* save the current position as it is where the
           *  next layer offset is stored.
           */
          saved_pos = info->cp;

          /* seek to the layer offset */
          if (! xcf_seek_pos (info, offset, NULL))
            goto error;

          /* read in the layer */
          layer = xcf_load_layer (info, image, &item_path);
          if (!layer)
            goto error;

          num_successful_elements++;

          xcf_progress_update (info);

          /* add the layer to the image if its not the floating selection */
          if (layer != info->floating_sel)
            {
              GimpContainer *layers = gimp_image_get_layers (image);
              GimpContainer *container;
              GimpLayer     *parent;

              if (item_path)
                {
                  if (info->floating_sel)
                    {
                      /* there is a floating selection, but it will get
                       * added after all layers are loaded, so toplevel
                       * layer indices are off-by-one. Adjust item paths
                       * accordingly:
                       */
                      gint toplevel_index;

                      toplevel_index = GPOINTER_TO_UINT (item_path->data);

                      toplevel_index--;

                      item_path->data = GUINT_TO_POINTER (toplevel_index);
                    }

                  parent = GIMP_LAYER
                    (gimp_item_stack_get_parent_by_path (GIMP_ITEM_STACK (layers),
                                                         item_path,
                                                         NULL));

                  container = gimp_viewable_get_children (GIMP_VIEWABLE (parent));

                  g_list_free (item_path);
                }
              else
                {
                  parent    = NULL;
                  container = layers;
                }

              gimp_image_add_layer (image, layer,
                                    parent,
                                    gimp_container_get_n_children (container),
                                    FALSE);
            }

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

      /* read channels */
      while (TRUE)
        {
          GimpChannel *channel;

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

          /* If the offset is 0, then we are at the end of the channel list. */
          if (offset == 0)
            break;

          /* save the current position as it is where the
           * next channel offset is stored.
           */
          saved_pos = info->cp;

          /* seek to the channel offset */
          if (! xcf_seek_pos (info, offset, NULL))
            goto error;

          /* read in the channel */
          channel = xcf_load_channel (info, image);
          if (!channel)
            goto error;

          num_successful_elements++;

          xcf_progress_update (info);

          /* add the channel to the image if its not the selection */
          if (channel != gimp_image_get_mask (image))
            gimp_image_add_channel (image, channel,
                                    NULL, /* FIXME tree */
                                    gimp_container_get_n_children (gimp_image_get_channels (image)),
                                    FALSE);

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

      terminate_loop =
          (num_successful_elements > 0) ||
          retried ||
          (! xcf_find_layer_offset_table (info, retry_offset));

      if (! terminate_loop)
        retried = TRUE;
/*
      if (num_successful_elements == 0 && !retried)
        {
          if (xcf_find_layer_offset_table (info, retry_offset))
            {
              retried = TRUE;
              goto retry;
            }
        }
*/
    } /* while (! terminate_loop) */

  xcf_load_add_masks (image);

  if (info->floating_sel && info->floating_sel_drawable)
    floating_sel_attach (info->floating_sel, info->floating_sel_drawable);

  if (info->active_layer)
    gimp_image_set_active_layer (image, info->active_layer);

  if (info->active_channel)
    gimp_image_set_active_channel (image, info->active_channel);

  gimp_image_set_filename (image, info->filename);

  if (info->tattoo_state > 0)
    gimp_image_set_tattoo_state (image, info->tattoo_state);

  gimp_image_undo_enable (image);

  return image;

 error:
  if (num_successful_elements == 0)
    goto hard_error;

  gimp_message_literal (gimp, G_OBJECT (info->progress), GIMP_MESSAGE_WARNING,
			_("This XCF file is corrupt!  I have loaded as much "
			  "of it as I can, but it is incomplete."));

  xcf_load_add_masks (image);

  gimp_image_undo_enable (image);

  return image;

 hard_error:
  g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
		       _("This XCF file is corrupt!  I could not even "
			 "salvage any partial image data from it."));

  if (image)
    g_object_unref (image);

  return NULL;
}
xcf_load_image (Gimp     *gimp,
                XcfInfo  *info,
                GError  **error)
{
  GimpImage          *image = NULL;
  const GimpParasite *parasite;
  guint32             saved_pos;
  guint32             offset;
  gint                width;
  gint                height;
  gint                image_type;
  gint                num_successful_elements = 0;
  guint32             retry_offset;
  gboolean            retried                 = FALSE;
  gboolean            terminate_loop            = FALSE;

   
  info->cp += xcf_read_int32 (info->fp, (guint32 *) &width, 1);
  info->cp += xcf_read_int32 (info->fp, (guint32 *) &height, 1);
  info->cp += xcf_read_int32 (info->fp, (guint32 *) &image_type, 1);
  if (image_type < GIMP_RGB || image_type > GIMP_INDEXED ||
      width <= 0 || height <= 0)
    goto hard_error;

  image = gimp_create_image (gimp, width, height, image_type, FALSE);

  gimp_image_undo_disable (image);

  xcf_progress_update (info);

   
  if (! xcf_load_image_props (info, image))
    goto hard_error;

   
  parasite = gimp_image_parasite_find (GIMP_IMAGE (image),
                                       gimp_grid_parasite_name ());
  if (parasite)
    {
      GimpGrid *grid = gimp_grid_from_parasite (parasite);

      if (grid)
        {
          GimpImagePrivate *private = GIMP_IMAGE_GET_PRIVATE (image);

          gimp_parasite_list_remove (private->parasites,
                                     gimp_parasite_name (parasite));

          gimp_image_set_grid (GIMP_IMAGE (image), grid, FALSE);
          g_object_unref (grid);
        }
    }

  xcf_progress_update (info);

  retry_offset = info->cp;

   
  while (! terminate_loop)
    {
      while (TRUE)
        {
          GimpLayer *layer;
          GList     *item_path = NULL;

           
          info->cp += xcf_read_int32 (info->fp, &offset, 1);

           
          if (offset == 0)
            break;

           
          saved_pos = info->cp;

           
          if (! xcf_seek_pos (info, offset, NULL))
            goto error;

           
          layer = xcf_load_layer (info, image, &item_path);
          if (!layer)
            goto error;

          num_successful_elements++;

          xcf_progress_update (info);

           
          if (layer != info->floating_sel)
            {
              GimpContainer *layers = gimp_image_get_layers (image);
              GimpContainer *container;
              GimpLayer     *parent;

              if (item_path)
                {
                  if (info->floating_sel)
                    {
                       
                      gint toplevel_index;

                      toplevel_index = GPOINTER_TO_UINT (item_path->data);

                      toplevel_index--;

                      item_path->data = GUINT_TO_POINTER (toplevel_index);
                    }

                  parent = GIMP_LAYER
                    (gimp_item_stack_get_parent_by_path (GIMP_ITEM_STACK (layers),
                                                         item_path,
                                                         NULL));

                  container = gimp_viewable_get_children (GIMP_VIEWABLE (parent));

                  g_list_free (item_path);
                }
              else
                {
                  parent    = NULL;
                  container = layers;
                }

              gimp_image_add_layer (image, layer,
                                    parent,
                                    gimp_container_get_n_children (container),
                                    FALSE);
            }

           
          if (! xcf_seek_pos (info, saved_pos, NULL))
            goto error;
        }  

       
      while (TRUE)
        {
          GimpChannel *channel;

           
          info->cp += xcf_read_int32 (info->fp, &offset, 1);

           
          if (offset == 0)
            break;

           
          saved_pos = info->cp;

           
          if (! xcf_seek_pos (info, offset, NULL))
            goto error;

           
          channel = xcf_load_channel (info, image);
          if (!channel)
            goto error;

          num_successful_elements++;

          xcf_progress_update (info);

           
          if (channel != gimp_image_get_mask (image))
            gimp_image_add_channel (image, channel,
                                    NULL,  
                                    gimp_container_get_n_children (gimp_image_get_channels (image)),
                                    FALSE);

           
          if (! xcf_seek_pos (info, saved_pos, NULL))
            goto error;
        }  

      terminate_loop =
          (num_successful_elements > 0) ||
          retried ||
          (! xcf_find_layer_offset_table (info, retry_offset));

      if (! terminate_loop)
        retried = TRUE;
 
    }  

  xcf_load_add_masks (image);

  if (info->floating_sel && info->floating_sel_drawable)
    floating_sel_attach (info->floating_sel, info->floating_sel_drawable);

  if (info->active_layer)
    gimp_image_set_active_layer (image, info->active_layer);

  if (info->active_channel)
    gimp_image_set_active_channel (image, info->active_channel);

  gimp_image_set_filename (image, info->filename);

  if (info->tattoo_state > 0)
    gimp_image_set_tattoo_state (image, info->tattoo_state);

  gimp_image_undo_enable (image);

  return image;

 error:
  if (num_successful_elements == 0)
    goto hard_error;

  gimp_message_literal (gimp, G_OBJECT (info->progress), GIMP_MESSAGE_WARNING,
			_("This XCF file is corrupt!  I have loaded as much "
			  "of it as I can, but it is incomplete."));

  xcf_load_add_masks (image);

  gimp_image_undo_enable (image);

  return image;

 hard_error:
  g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
		       _("This XCF file is corrupt!  I could not even "
			 "salvage any partial image data from it."));

  if (image)
    g_object_unref (image);

  return NULL;
}