xcf_load_channel_props (XcfInfo      *info,
                        GimpImage    *image,
                        GimpChannel **channel)
{
  PropType prop_type;
  guint32  prop_size;

  while (TRUE)
    {
      if (! xcf_load_prop (info, &prop_type, &prop_size))
        return FALSE;

      switch (prop_type)
        {
        case PROP_END:
          return TRUE;

        case PROP_ACTIVE_CHANNEL:
          info->selected_channels = g_list_prepend (info->selected_channels, *channel);
          break;

        case PROP_SELECTION:
          {
            GimpChannel *mask;
            GList       *iter;

            /* We're going to delete *channel, Don't leave its pointer
             * in @info. See bug #767873.
             */
            for (iter = info->selected_channels; iter; iter = iter->next)
              if (*channel == iter->data)
                {
                  info->selected_channels = g_list_delete_link (info->selected_channels, iter);
                  break;
                }

            mask =
              gimp_selection_new (image,
                                  gimp_item_get_width  (GIMP_ITEM (*channel)),
                                  gimp_item_get_height (GIMP_ITEM (*channel)));
            gimp_image_take_mask (image, mask);

            gimp_drawable_steal_buffer (GIMP_DRAWABLE (mask),
                                        GIMP_DRAWABLE (*channel));
            g_object_unref (*channel);
            *channel = mask;

            /* Don't restore info->selected_channels because the
             * selection can't be the active channel
             */
          }
          break;

        case PROP_OPACITY:
          {
            guint32 opacity;

            xcf_read_int32 (info, &opacity, 1);

            gimp_channel_set_opacity (*channel, opacity / 255.0, FALSE);
          }
          break;

        case PROP_FLOAT_OPACITY:
          {
            gfloat opacity;

            xcf_read_float (info, &opacity, 1);

            gimp_channel_set_opacity (*channel, opacity, FALSE);
          }
          break;

        case PROP_VISIBLE:
          {
            gboolean visible;

            xcf_read_int32 (info, (guint32 *) &visible, 1);

            gimp_item_set_visible (GIMP_ITEM (*channel), visible, FALSE);
          }
          break;

        case PROP_COLOR_TAG:
          {
            GimpColorTag color_tag;

            xcf_read_int32 (info, (guint32 *) &color_tag, 1);

            gimp_item_set_color_tag (GIMP_ITEM (*channel), color_tag, FALSE);
          }
          break;

        case PROP_LINKED:
          {
            gboolean linked;

            xcf_read_int32 (info, (guint32 *) &linked, 1);

            if (linked)
              info->linked_channels = g_list_prepend (info->linked_channels, *channel);
          }
          break;

        case PROP_LOCK_CONTENT:
          {
            gboolean lock_content;

            xcf_read_int32 (info, (guint32 *) &lock_content, 1);

            if (gimp_item_can_lock_content (GIMP_ITEM (*channel)))
              gimp_item_set_lock_content (GIMP_ITEM (*channel),
                                          lock_content, FALSE);
          }
          break;

        case PROP_LOCK_POSITION:
          {
            gboolean lock_position;

            xcf_read_int32 (info, (guint32 *) &lock_position, 1);

            if (gimp_item_can_lock_position (GIMP_ITEM (*channel)))
              gimp_item_set_lock_position (GIMP_ITEM (*channel),
                                           lock_position, FALSE);
          }
          break;

        case PROP_LOCK_VISIBILITY:
          {
            gboolean lock_visibility;

            xcf_read_int32 (info, (guint32 *) &lock_visibility, 1);

            if (gimp_item_can_lock_visibility (GIMP_ITEM (*channel)))
              gimp_item_set_lock_visibility (GIMP_ITEM (*channel),
                                             lock_visibility, FALSE);
          }
          break;

        case PROP_SHOW_MASKED:
          {
            gboolean show_masked;

            xcf_read_int32 (info, (guint32 *) &show_masked, 1);

            gimp_channel_set_show_masked (*channel, show_masked);
          }
          break;

        case PROP_COLOR:
          {
            guchar col[3];

            xcf_read_int8 (info, (guint8 *) col, 3);

            gimp_rgb_set_uchar (&(*channel)->color, col[0], col[1], col[2]);
          }
          break;

        case PROP_FLOAT_COLOR:
          {
            gfloat col[3];

            xcf_read_float (info, col, 3);

            gimp_rgb_set (&(*channel)->color, col[0], col[1], col[2]);
          }
          break;

        case PROP_TATTOO:
          {
            GimpTattoo tattoo;

            xcf_read_int32 (info, (guint32 *) &tattoo, 1);

            gimp_item_set_tattoo (GIMP_ITEM (*channel), tattoo);
          }
          break;

        case PROP_PARASITES:
          {
            goffset base = info->cp;

            while ((info->cp - base) < prop_size)
              {
                GimpParasite *p     = xcf_load_parasite (info);
                GError       *error = NULL;

                if (! p)
                  return FALSE;

                if (! gimp_item_parasite_validate (GIMP_ITEM (*channel), p,
                                                    &error))
                  {
                    gimp_message (info->gimp, G_OBJECT (info->progress),
                                  GIMP_MESSAGE_WARNING,
                                  "Warning, invalid channel parasite in XCF file: %s",
                                  error->message);
                    g_clear_error (&error);
                  }
                else
                  {
                    gimp_item_parasite_attach (GIMP_ITEM (*channel), p, FALSE);
                  }

                gimp_parasite_free (p);
              }

            if (info->cp - base != prop_size)
              gimp_message_literal (info->gimp, G_OBJECT (info->progress),
                                    GIMP_MESSAGE_WARNING,
                                    "Error while loading a channel's parasites");
          }
          break;

        case PROP_ITEM_SET_ITEM:
            {
              GimpItemList *set;
              guint32       n;

              xcf_read_int32 (info, &n, 1);
              set = g_list_nth_data (info->channel_sets, n);
              if (set == NULL)
                g_printerr ("xcf: unknown channel set: %d (skipping)\n", n);
              else if (! g_type_is_a (G_TYPE_FROM_INSTANCE (*channel),
                                      gimp_item_list_get_item_type (set)))
                g_printerr ("xcf: channel '%s' cannot be added to item set '%s' with item type %s (skipping)\n",
                            gimp_object_get_name (*channel), gimp_object_get_name (set),
                            g_type_name (gimp_item_list_get_item_type (set)));
              else
                gimp_item_list_add (set, GIMP_ITEM (*channel));
            }
          break;

        default:
#ifdef GIMP_UNSTABLE
          g_printerr ("unexpected/unknown channel property: %d (skipping)\n",
                      prop_type);
#endif
          if (! xcf_skip_unknown_prop (info, prop_size))
            return FALSE;
          break;
        }
    }

  return FALSE;
}