Blame src/ibusunicode.c

Packit 3ff832
/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
Packit 3ff832
/* vim:set et sts=4: */
Packit 3ff832
/* bus - The Input Bus
Packit 3ff832
 * Copyright (C) 2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
Packit 3ff832
 * Copyright (C) 2018 Red Hat, Inc.
Packit 3ff832
 *
Packit 3ff832
 * This library is free software; you can redistribute it and/or
Packit 3ff832
 * modify it under the terms of the GNU Lesser General Public
Packit 3ff832
 * License as published by the Free Software Foundation; either
Packit 3ff832
 * version 2.1 of the License, or (at your option) any later version.
Packit 3ff832
 *
Packit 3ff832
 * This library is distributed in the hope that it will be useful,
Packit 3ff832
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 3ff832
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 3ff832
 * Lesser General Public License for more details.
Packit 3ff832
 *
Packit 3ff832
 * You should have received a copy of the GNU Lesser General Public
Packit 3ff832
 * License along with this library; if not, write to the Free Software
Packit 3ff832
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
Packit 3ff832
 * USA
Packit 3ff832
 */
Packit 3ff832
#ifdef HAVE_CONFIG_H
Packit 3ff832
#include <config.h>
Packit 3ff832
#endif
Packit 3ff832
Packit 3ff832
#include <glib.h>
Packit 3ff832
#include <glib/gstdio.h>
Packit 3ff832
#include "ibusinternal.h"
Packit 3ff832
#include "ibuserror.h"
Packit 3ff832
#include "ibusunicode.h"
Packit 3ff832
Packit 3ff832
#define IBUS_UNICODE_DATA_MAGIC "IBusUnicodeData"
Packit 3ff832
#define IBUS_UNICODE_BLOCK_MAGIC "IBusUnicodeBlock"
Packit 3ff832
#define IBUS_UNICODE_DATA_VERSION (1)
Packit 3ff832
#define IBUS_UNICODE_DESERIALIZE_SIGNALL_STR \
Packit 3ff832
        "deserialize-unicode"
Packit 3ff832
Packit 3ff832
enum {
Packit 3ff832
    PROP_0 = 0,
Packit 3ff832
    PROP_CODE,
Packit 3ff832
    PROP_NAME,
Packit 3ff832
    PROP_ALIAS,
Packit 3ff832
    PROP_BLOCK_NAME,
Packit 3ff832
    PROP_START,
Packit 3ff832
    PROP_END
Packit 3ff832
};
Packit 3ff832
Packit 3ff832
struct _IBusUnicodeDataPrivate {
Packit 3ff832
    gunichar    code;
Packit 3ff832
    gchar      *name;
Packit 3ff832
    gchar      *alias;
Packit 3ff832
    gchar      *block_name;
Packit 3ff832
};
Packit 3ff832
Packit 3ff832
struct _IBusUnicodeBlockPrivate {
Packit 3ff832
    gunichar    start;
Packit 3ff832
    gunichar    end;
Packit 3ff832
    gchar      *name;
Packit 3ff832
};
Packit 3ff832
Packit 3ff832
typedef struct {
Packit 3ff832
    IBusUnicodeDataLoadAsyncFinish callback;
Packit 3ff832
    gpointer                       user_data;
Packit 3ff832
} IBusUnicodeDataLoadData;
Packit 3ff832
Packit 3ff832
#define IBUS_UNICODE_DATA_GET_PRIVATE(o)  \
Packit 3ff832
   (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
Packit 3ff832
    IBUS_TYPE_UNICODE_DATA, \
Packit 3ff832
    IBusUnicodeDataPrivate))
Packit 3ff832
#define IBUS_UNICODE_BLOCK_GET_PRIVATE(o)  \
Packit 3ff832
   (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
Packit 3ff832
    IBUS_TYPE_UNICODE_BLOCK, \
Packit 3ff832
    IBusUnicodeBlockPrivate))
Packit 3ff832
Packit 3ff832
/* functions prototype */
Packit 3ff832
static void      ibus_unicode_data_set_property (IBusUnicodeData      *unicode,
Packit 3ff832
                                                 guint                 prop_id,
Packit 3ff832
                                                 const GValue         *value,
Packit 3ff832
                                                 GParamSpec           *pspec);
Packit 3ff832
static void      ibus_unicode_data_get_property (IBusUnicodeData      *unicode,
Packit 3ff832
                                                 guint                 prop_id,
Packit 3ff832
                                                 GValue               *value,
Packit 3ff832
                                                 GParamSpec           *pspec);
Packit 3ff832
static void      ibus_unicode_data_destroy      (IBusUnicodeData      *unicode);
Packit 3ff832
static gboolean  ibus_unicode_data_serialize    (IBusUnicodeData      *unicode,
Packit 3ff832
                                                 GVariantBuilder      *builder);
Packit 3ff832
static gint      ibus_unicode_data_deserialize  (IBusUnicodeData      *unicode,
Packit 3ff832
                                                 GVariant             *variant);
Packit 3ff832
static gboolean  ibus_unicode_data_copy         (IBusUnicodeData      *dest,
Packit 3ff832
                                                const IBusUnicodeData *src);
Packit 3ff832
static void      ibus_unicode_block_set_property
Packit 3ff832
                                                (IBusUnicodeBlock     *block,
Packit 3ff832
                                                 guint                 prop_id,
Packit 3ff832
                                                 const GValue         *value,
Packit 3ff832
                                                 GParamSpec           *pspec);
Packit 3ff832
static void      ibus_unicode_block_get_property
Packit 3ff832
                                                (IBusUnicodeBlock     *block,
Packit 3ff832
                                                 guint                 prop_id,
Packit 3ff832
                                                 GValue               *value,
Packit 3ff832
                                                 GParamSpec           *pspec);
Packit 3ff832
static void      ibus_unicode_block_destroy     (IBusUnicodeBlock     *block);
Packit 3ff832
static gboolean  ibus_unicode_block_serialize   (IBusUnicodeBlock     *block,
Packit 3ff832
                                                 GVariantBuilder      *builder);
Packit 3ff832
static gint      ibus_unicode_block_deserialize (IBusUnicodeBlock     *block,
Packit 3ff832
                                                 GVariant             *variant);
Packit 3ff832
static gboolean  ibus_unicode_block_copy        (IBusUnicodeBlock     *dest,
Packit 3ff832
                                                const IBusUnicodeBlock *src);
Packit 3ff832
Packit 3ff832
G_DEFINE_TYPE (IBusUnicodeData, ibus_unicode_data, IBUS_TYPE_SERIALIZABLE)
Packit 3ff832
G_DEFINE_TYPE (IBusUnicodeBlock, ibus_unicode_block, IBUS_TYPE_SERIALIZABLE)
Packit 3ff832
Packit 3ff832
static void
Packit 3ff832
ibus_unicode_data_class_init (IBusUnicodeDataClass *class)
Packit 3ff832
{
Packit 3ff832
    IBusObjectClass *object_class = IBUS_OBJECT_CLASS (class);
Packit 3ff832
    GObjectClass *gobject_class = G_OBJECT_CLASS (class);
Packit 3ff832
    IBusSerializableClass *serializable_class = IBUS_SERIALIZABLE_CLASS (class);
Packit 3ff832
Packit 3ff832
    object_class->destroy = (IBusObjectDestroyFunc) ibus_unicode_data_destroy;
Packit 3ff832
    gobject_class->set_property =
Packit 3ff832
            (GObjectSetPropertyFunc) ibus_unicode_data_set_property;
Packit 3ff832
    gobject_class->get_property =
Packit 3ff832
            (GObjectGetPropertyFunc) ibus_unicode_data_get_property;
Packit 3ff832
    serializable_class->serialize   =
Packit 3ff832
            (IBusSerializableSerializeFunc) ibus_unicode_data_serialize;
Packit 3ff832
    serializable_class->deserialize =
Packit 3ff832
            (IBusSerializableDeserializeFunc) ibus_unicode_data_deserialize;
Packit 3ff832
    serializable_class->copy        =
Packit 3ff832
            (IBusSerializableCopyFunc) ibus_unicode_data_copy;
Packit 3ff832
Packit 3ff832
    g_type_class_add_private (class, sizeof (IBusUnicodeDataPrivate));
Packit 3ff832
Packit 3ff832
    /* install properties */
Packit 3ff832
    /**
Packit 3ff832
     * IBusUnicodeData:code:
Packit 3ff832
     *
Packit 3ff832
     * The Uniode code point
Packit 3ff832
     */
Packit 3ff832
    g_object_class_install_property (gobject_class,
Packit 3ff832
                    PROP_CODE,
Packit 3ff832
                    g_param_spec_unichar ("code",
Packit 3ff832
                        "code point",
Packit 3ff832
                        "The Unicode code point",
Packit 3ff832
                        0,
Packit 3ff832
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
Packit 3ff832
Packit 3ff832
Packit 3ff832
    /**
Packit 3ff832
     * IBusUnicodeData:name:
Packit 3ff832
     *
Packit 3ff832
     * The Uniode name
Packit 3ff832
     */
Packit 3ff832
    g_object_class_install_property (gobject_class,
Packit 3ff832
                    PROP_NAME,
Packit 3ff832
                    g_param_spec_string ("name",
Packit 3ff832
                        "name",
Packit 3ff832
                        "The Unicode name",
Packit 3ff832
                        "",
Packit 3ff832
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
Packit 3ff832
Packit 3ff832
    /**
Packit 3ff832
     * IBusUnicodeData:alias:
Packit 3ff832
     *
Packit 3ff832
     * The Uniode alias name
Packit 3ff832
     */
Packit 3ff832
    g_object_class_install_property (gobject_class,
Packit 3ff832
                    PROP_ALIAS,
Packit 3ff832
                    g_param_spec_string ("alias",
Packit 3ff832
                        "alias name",
Packit 3ff832
                        "The Unicode alias name",
Packit 3ff832
                        "",
Packit 3ff832
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
Packit 3ff832
Packit 3ff832
    /**
Packit 3ff832
     * IBusUnicodeData:block-name:
Packit 3ff832
     *
Packit 3ff832
     * The Uniode block name
Packit 3ff832
     */
Packit 3ff832
    g_object_class_install_property (gobject_class,
Packit 3ff832
                    PROP_BLOCK_NAME,
Packit 3ff832
                    g_param_spec_string ("block-name",
Packit 3ff832
                        "block name",
Packit 3ff832
                        "The Unicode block name",
Packit 3ff832
                        "",
Packit 3ff832
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static void
Packit 3ff832
ibus_unicode_data_init (IBusUnicodeData *unicode)
Packit 3ff832
{
Packit 3ff832
    unicode->priv = IBUS_UNICODE_DATA_GET_PRIVATE (unicode);
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static void
Packit 3ff832
ibus_unicode_data_destroy (IBusUnicodeData *unicode)
Packit 3ff832
{
Packit 3ff832
    g_clear_pointer (&unicode->priv->name, g_free);
Packit 3ff832
    g_clear_pointer (&unicode->priv->alias, g_free);
Packit 3ff832
    g_clear_pointer (&unicode->priv->block_name, g_free);
Packit 3ff832
Packit 3ff832
    IBUS_OBJECT_CLASS (ibus_unicode_data_parent_class)->
Packit 3ff832
            destroy (IBUS_OBJECT (unicode));
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static void
Packit 3ff832
ibus_unicode_data_set_property (IBusUnicodeData *unicode,
Packit 3ff832
                                guint            prop_id,
Packit 3ff832
                                const GValue    *value,
Packit 3ff832
                                GParamSpec      *pspec)
Packit 3ff832
{
Packit 3ff832
    switch (prop_id) {
Packit 3ff832
    case PROP_CODE:
Packit 3ff832
        g_assert (unicode->priv->code == 0);
Packit 3ff832
        unicode->priv->code = g_value_get_uint (value);
Packit 3ff832
        break;
Packit 3ff832
    case PROP_NAME:
Packit 3ff832
        g_assert (unicode->priv->name == NULL);
Packit 3ff832
        unicode->priv->name = g_value_dup_string (value);
Packit 3ff832
        break;
Packit 3ff832
    case PROP_ALIAS:
Packit 3ff832
        g_assert (unicode->priv->alias == NULL);
Packit 3ff832
        unicode->priv->alias = g_value_dup_string (value);
Packit 3ff832
        break;
Packit 3ff832
    case PROP_BLOCK_NAME:
Packit 3ff832
        g_free (unicode->priv->block_name);
Packit 3ff832
        unicode->priv->block_name = g_value_dup_string (value);
Packit 3ff832
        break;
Packit 3ff832
    default:
Packit 3ff832
        G_OBJECT_WARN_INVALID_PROPERTY_ID (unicode, prop_id, pspec);
Packit 3ff832
    }
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static void
Packit 3ff832
ibus_unicode_data_get_property (IBusUnicodeData *unicode,
Packit 3ff832
                                guint            prop_id,
Packit 3ff832
                                GValue          *value,
Packit 3ff832
                                GParamSpec      *pspec)
Packit 3ff832
{
Packit 3ff832
    switch (prop_id) {
Packit 3ff832
    case PROP_CODE:
Packit 3ff832
        g_value_set_uint (value, ibus_unicode_data_get_code (unicode));
Packit 3ff832
        break;
Packit 3ff832
    case PROP_NAME:
Packit 3ff832
        g_value_set_string (value, ibus_unicode_data_get_name (unicode));
Packit 3ff832
        break;
Packit 3ff832
    case PROP_ALIAS:
Packit 3ff832
        g_value_set_string (value, ibus_unicode_data_get_alias (unicode));
Packit 3ff832
        break;
Packit 3ff832
    case PROP_BLOCK_NAME:
Packit 3ff832
        g_value_set_string (value, ibus_unicode_data_get_block_name (unicode));
Packit 3ff832
        break;
Packit 3ff832
    default:
Packit 3ff832
        G_OBJECT_WARN_INVALID_PROPERTY_ID (unicode, prop_id, pspec);
Packit 3ff832
    }
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static gboolean
Packit 3ff832
ibus_unicode_data_serialize (IBusUnicodeData   *unicode,
Packit 3ff832
                             GVariantBuilder   *builder)
Packit 3ff832
{
Packit 3ff832
    gboolean retval = IBUS_SERIALIZABLE_CLASS (ibus_unicode_data_parent_class)->
Packit 3ff832
            serialize ((IBusSerializable *)unicode, builder);
Packit 3ff832
    g_return_val_if_fail (retval, FALSE);
Packit 3ff832
Packit 3ff832
#define NOTNULL(s) ((s) != NULL ? (s) : "")
Packit 3ff832
    /* If you will add a new property, you can append it at the end and
Packit 3ff832
     * you should not change the serialized order of name, longname,
Packit 3ff832
     * description, ... because the order is also used in other applications
Packit 3ff832
     * likes ibus-qt. */
Packit 3ff832
    g_variant_builder_add (builder, "u", unicode->priv->code);
Packit 3ff832
    g_variant_builder_add (builder, "s", NOTNULL (unicode->priv->name));
Packit 3ff832
    g_variant_builder_add (builder, "s", NOTNULL (unicode->priv->alias));
Packit 3ff832
    /* Use IBusUnicodeBlock for memory usage.
Packit 3ff832
    g_variant_builder_add (builder, "s", NOTNULL (unicode->priv->block_name));
Packit 3ff832
     */
Packit 3ff832
#undef NOTNULL
Packit 3ff832
    return TRUE;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static gint
Packit 3ff832
ibus_unicode_data_deserialize (IBusUnicodeData *unicode,
Packit 3ff832
                               GVariant        *variant)
Packit 3ff832
{
Packit 3ff832
    gint retval = IBUS_SERIALIZABLE_CLASS (ibus_unicode_data_parent_class)->
Packit 3ff832
            deserialize ((IBusSerializable *)unicode, variant);
Packit 3ff832
    g_return_val_if_fail (retval, 0);
Packit 3ff832
Packit 3ff832
    /* If you will add a new property, you can append it at the end and
Packit 3ff832
     * you should not change the serialized order of name, longname,
Packit 3ff832
     * description, ... because the order is also used in other applications
Packit 3ff832
     * likes ibus-qt. */
Packit 3ff832
    g_variant_get_child (variant, retval++, "u", &unicode->priv->code);
Packit 3ff832
    ibus_g_variant_get_child_string (variant, retval++,
Packit 3ff832
                                     &unicode->priv->name);
Packit 3ff832
    ibus_g_variant_get_child_string (variant, retval++,
Packit 3ff832
                                     &unicode->priv->alias);
Packit 3ff832
    /* Use IBusUnicodeBlock for memory usage.
Packit 3ff832
    ibus_g_variant_get_child_string (variant, retval++,
Packit 3ff832
                                     &unicode->priv->block_name);
Packit 3ff832
     */
Packit 3ff832
    return retval;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static gboolean
Packit 3ff832
ibus_unicode_data_copy (IBusUnicodeData       *dest,
Packit 3ff832
                        const IBusUnicodeData *src)
Packit 3ff832
{
Packit 3ff832
    gboolean retval = IBUS_SERIALIZABLE_CLASS (ibus_unicode_data_parent_class)->
Packit 3ff832
            copy ((IBusSerializable *)dest,
Packit 3ff832
                  (IBusSerializable *)src);
Packit 3ff832
    g_return_val_if_fail (retval, FALSE);
Packit 3ff832
Packit 3ff832
    dest->priv->code             = src->priv->code;
Packit 3ff832
    dest->priv->name             = g_strdup (src->priv->name);
Packit 3ff832
    dest->priv->alias            = g_strdup (src->priv->alias);
Packit 3ff832
    dest->priv->block_name       = g_strdup (src->priv->block_name);
Packit 3ff832
    return TRUE;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
IBusUnicodeData *
Packit 3ff832
ibus_unicode_data_new (const gchar *first_property_name, ...)
Packit 3ff832
{
Packit 3ff832
    va_list var_args;
Packit 3ff832
    IBusUnicodeData *unicode;
Packit 3ff832
Packit 3ff832
    g_assert (first_property_name != NULL);
Packit 3ff832
    va_start (var_args, first_property_name);
Packit 3ff832
    unicode = (IBusUnicodeData *) g_object_new_valist (IBUS_TYPE_UNICODE_DATA,
Packit 3ff832
                                                       first_property_name,
Packit 3ff832
                                                       var_args);
Packit 3ff832
    va_end (var_args);
Packit 3ff832
    /* code is required. Other properties are set in class_init by default. */
Packit 3ff832
    g_assert (unicode->priv->name != NULL);
Packit 3ff832
    g_assert (unicode->priv->alias != NULL);
Packit 3ff832
    g_assert (unicode->priv->block_name != NULL);
Packit 3ff832
    return unicode;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
gunichar
Packit 3ff832
ibus_unicode_data_get_code (IBusUnicodeData *unicode)
Packit 3ff832
{
Packit 3ff832
    g_return_val_if_fail (IBUS_IS_UNICODE_DATA (unicode), G_MAXUINT32);
Packit 3ff832
Packit 3ff832
    return unicode->priv->code;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
const gchar *
Packit 3ff832
ibus_unicode_data_get_name (IBusUnicodeData *unicode)
Packit 3ff832
{
Packit 3ff832
    g_return_val_if_fail (IBUS_IS_UNICODE_DATA (unicode), "");
Packit 3ff832
Packit 3ff832
    return unicode->priv->name;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
const gchar *
Packit 3ff832
ibus_unicode_data_get_alias (IBusUnicodeData *unicode)
Packit 3ff832
{
Packit 3ff832
    g_return_val_if_fail (IBUS_IS_UNICODE_DATA (unicode), "");
Packit 3ff832
Packit 3ff832
    return unicode->priv->alias;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
const gchar *
Packit 3ff832
ibus_unicode_data_get_block_name (IBusUnicodeData *unicode)
Packit 3ff832
{
Packit 3ff832
    g_return_val_if_fail (IBUS_IS_UNICODE_DATA (unicode), "");
Packit 3ff832
Packit 3ff832
    return unicode->priv->block_name;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
void
Packit 3ff832
ibus_unicode_data_set_block_name (IBusUnicodeData *unicode,
Packit 3ff832
                                  const gchar     *block_name)
Packit 3ff832
{
Packit 3ff832
    g_return_if_fail (IBUS_IS_UNICODE_DATA (unicode));
Packit 3ff832
Packit 3ff832
    g_free (unicode->priv->block_name);
Packit 3ff832
    unicode->priv->block_name = g_strdup (block_name);
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static void
Packit 3ff832
variant_foreach_add_unicode (IBusUnicodeData *unicode,
Packit 3ff832
                             GVariantBuilder *builder)
Packit 3ff832
{
Packit 3ff832
    g_variant_builder_add (
Packit 3ff832
            builder, "v",
Packit 3ff832
            ibus_serializable_serialize (IBUS_SERIALIZABLE (unicode)));
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static GVariant *
Packit 3ff832
ibus_unicode_data_list_serialize (GSList *list)
Packit 3ff832
{
Packit 3ff832
    GVariantBuilder builder;
Packit 3ff832
Packit 3ff832
    g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
Packit 3ff832
    g_slist_foreach (list,  (GFunc) variant_foreach_add_unicode, &builder);
Packit 3ff832
    return g_variant_builder_end (&builder);
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static GSList *
Packit 3ff832
ibus_unicode_data_list_deserialize (GVariant *variant,
Packit 3ff832
                                    GObject  *source_object)
Packit 3ff832
{
Packit 3ff832
    GSList *list = NULL;
Packit 3ff832
    GVariantIter iter;
Packit 3ff832
    GVariant *unicode_variant = NULL;
Packit 3ff832
    gsize i, size;
Packit 3ff832
    gboolean has_signal = FALSE;
Packit 3ff832
Packit 3ff832
    if (G_IS_OBJECT (source_object)) {
Packit 3ff832
        has_signal = g_signal_lookup (
Packit 3ff832
                IBUS_UNICODE_DESERIALIZE_SIGNALL_STR,
Packit 3ff832
                G_OBJECT_TYPE (source_object));
Packit 3ff832
        if (!has_signal) {
Packit 3ff832
            const gchar *type_name =
Packit 3ff832
                    g_type_name (G_OBJECT_TYPE (source_object));
Packit 3ff832
            g_warning ("GObject %s does not have the signal \"%s\"",
Packit 3ff832
                       type_name ? type_name : "(null)",
Packit 3ff832
                       IBUS_UNICODE_DESERIALIZE_SIGNALL_STR);
Packit 3ff832
        }
Packit 3ff832
    }
Packit 3ff832
    g_variant_iter_init (&iter, variant);
Packit 3ff832
    size = g_variant_iter_n_children (&iter);
Packit 3ff832
    i = 0;
Packit 3ff832
    while (g_variant_iter_loop (&iter, "v", &unicode_variant)) {
Packit 3ff832
        IBusUnicodeData *data =
Packit 3ff832
                IBUS_UNICODE_DATA (ibus_serializable_deserialize (
Packit 3ff832
                        unicode_variant));
Packit 3ff832
        list = g_slist_append (list, data);
Packit 3ff832
        g_clear_pointer (&unicode_variant, g_variant_unref);
Packit 3ff832
        if (has_signal && (i == 0 || ((i + 1) % 100) == 0)) {
Packit 3ff832
            g_signal_emit_by_name (source_object,
Packit 3ff832
                                   IBUS_UNICODE_DESERIALIZE_SIGNALL_STR,
Packit 3ff832
                                   i + 1, size);
Packit 3ff832
        }
Packit 3ff832
        i++;
Packit 3ff832
    }
Packit 3ff832
    if (has_signal && (i != 1 && (i % 100) != 0)) {
Packit 3ff832
        g_signal_emit_by_name (source_object,
Packit 3ff832
                               IBUS_UNICODE_DESERIALIZE_SIGNALL_STR,
Packit 3ff832
                               i, size);
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    return list;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
void
Packit 3ff832
ibus_unicode_data_save (const gchar *path,
Packit 3ff832
                        GSList      *list)
Packit 3ff832
{
Packit 3ff832
    GVariant *variant;
Packit 3ff832
    const gchar *header = IBUS_UNICODE_DATA_MAGIC;
Packit 3ff832
    const guint16 version = IBUS_UNICODE_DATA_VERSION;
Packit 3ff832
    const gchar *contents;
Packit 3ff832
    gsize length;
Packit 3ff832
    gchar *dir;
Packit 3ff832
    GStatBuf buf = { 0, };
Packit 3ff832
    GError *error = NULL;
Packit 3ff832
Packit 3ff832
    g_return_if_fail (path != NULL);
Packit 3ff832
    g_return_if_fail (list != NULL);
Packit 3ff832
    if (list->data == NULL) {
Packit 3ff832
        g_warning ("Failed to save IBus Unicode data: Need a list data.");
Packit 3ff832
        return;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    variant = g_variant_new ("(sqv)",
Packit 3ff832
                             header,
Packit 3ff832
                             version,
Packit 3ff832
                             ibus_unicode_data_list_serialize (list));
Packit 3ff832
Packit 3ff832
    contents =  g_variant_get_data (variant);
Packit 3ff832
    length =  g_variant_get_size (variant);
Packit 3ff832
Packit 3ff832
    dir = g_path_get_dirname (path);
Packit 3ff832
    if (g_strcmp0 (dir, ".") != 0 && g_stat (dir, &buf) != 0) {
Packit 3ff832
        g_mkdir_with_parents (dir, 0777);
Packit 3ff832
    }
Packit 3ff832
    g_free (dir);
Packit 3ff832
    if (!g_file_set_contents (path, contents, length, &error)) {
Packit 3ff832
        g_warning ("Failed to save Unicode dict %s: %s", path, error->message);
Packit 3ff832
        g_error_free (error);
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    g_variant_unref (variant);
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static GSList *
Packit 3ff832
ibus_unicode_data_load_with_error (const gchar *path,
Packit 3ff832
                                   GObject     *source_object,
Packit 3ff832
                                   GError     **error)
Packit 3ff832
{
Packit 3ff832
    gchar *contents = NULL;
Packit 3ff832
    gsize length = 0;
Packit 3ff832
    GVariant *variant_table = NULL;
Packit 3ff832
    GVariant *variant = NULL;
Packit 3ff832
    const gchar *header = NULL;
Packit 3ff832
    guint16 version = 0;
Packit 3ff832
    GSList *retval = NULL;
Packit 3ff832
Packit 3ff832
    if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
Packit 3ff832
        g_set_error (error,
Packit 3ff832
                     IBUS_ERROR,
Packit 3ff832
                     IBUS_ERROR_FAILED,
Packit 3ff832
                     "Unicode dict does not exist: %s", path);
Packit 3ff832
        goto out_load_cache;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    if (!g_file_get_contents (path, &contents, &length, error)) {
Packit 3ff832
        goto out_load_cache;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    variant_table = g_variant_new_from_data (G_VARIANT_TYPE ("(sq)"),
Packit 3ff832
                                             contents,
Packit 3ff832
                                             length,
Packit 3ff832
                                             FALSE,
Packit 3ff832
                                             NULL,
Packit 3ff832
                                             NULL);
Packit 3ff832
Packit 3ff832
    if (variant_table == NULL) {
Packit 3ff832
        g_set_error (error,
Packit 3ff832
                     IBUS_ERROR,
Packit 3ff832
                     IBUS_ERROR_FAILED,
Packit 3ff832
                     "cache table is broken.");
Packit 3ff832
        goto out_load_cache;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    g_variant_get (variant_table, "(&sq)", &header, &version);
Packit 3ff832
Packit 3ff832
    if (g_strcmp0 (header, IBUS_UNICODE_DATA_MAGIC) != 0) {
Packit 3ff832
        g_set_error (error,
Packit 3ff832
                     IBUS_ERROR,
Packit 3ff832
                     IBUS_ERROR_FAILED,
Packit 3ff832
                     "cache is not IBusUnicodeData.");
Packit 3ff832
        goto out_load_cache;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    if (version > IBUS_UNICODE_DATA_VERSION) {
Packit 3ff832
        g_set_error (error,
Packit 3ff832
                     IBUS_ERROR,
Packit 3ff832
                     IBUS_ERROR_FAILED,
Packit 3ff832
                     "cache version is different: %u != %u",
Packit 3ff832
                     version, IBUS_UNICODE_DATA_VERSION);
Packit 3ff832
        goto out_load_cache;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    version = 0;
Packit 3ff832
    header = NULL;
Packit 3ff832
    g_variant_unref (variant_table);
Packit 3ff832
Packit 3ff832
    variant_table = g_variant_new_from_data (G_VARIANT_TYPE ("(sqv)"),
Packit 3ff832
                                             contents,
Packit 3ff832
                                             length,
Packit 3ff832
                                             FALSE,
Packit 3ff832
                                             NULL,
Packit 3ff832
                                             NULL);
Packit 3ff832
Packit 3ff832
    if (variant_table == NULL) {
Packit 3ff832
        g_set_error (error,
Packit 3ff832
                     IBUS_ERROR,
Packit 3ff832
                     IBUS_ERROR_FAILED,
Packit 3ff832
                     "cache table is broken.");
Packit 3ff832
        goto out_load_cache;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    g_variant_get (variant_table, "(&sqv)",
Packit 3ff832
                   NULL,
Packit 3ff832
                   NULL,
Packit 3ff832
                   &variant);
Packit 3ff832
Packit 3ff832
    if (variant == NULL) {
Packit 3ff832
        g_set_error (error,
Packit 3ff832
                     IBUS_ERROR,
Packit 3ff832
                     IBUS_ERROR_FAILED,
Packit 3ff832
                     "cache dict is broken.");
Packit 3ff832
        goto out_load_cache;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    retval = ibus_unicode_data_list_deserialize (variant, source_object);
Packit 3ff832
Packit 3ff832
out_load_cache:
Packit 3ff832
    if (variant)
Packit 3ff832
        g_variant_unref (variant);
Packit 3ff832
    if (variant_table)
Packit 3ff832
        g_variant_unref (variant_table);
Packit 3ff832
    g_free (contents);
Packit 3ff832
Packit 3ff832
    return retval;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
GSList *
Packit 3ff832
ibus_unicode_data_load (const gchar *path,
Packit 3ff832
                        GObject     *source_object)
Packit 3ff832
{
Packit 3ff832
    GError *error = NULL;
Packit 3ff832
    GSList *retval = ibus_unicode_data_load_with_error (path,
Packit 3ff832
                                                        source_object,
Packit 3ff832
                                                        &error);
Packit 3ff832
Packit 3ff832
    if (retval == NULL) {
Packit 3ff832
        g_warning ("%s", error->message);
Packit 3ff832
        g_error_free (error);
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    return retval;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static void
Packit 3ff832
ibus_unicode_data_load_async_thread (GTask        *task,
Packit 3ff832
                                     gpointer      source_object,
Packit 3ff832
                                     gpointer      task_data,
Packit 3ff832
                                     GCancellable *cancellable)
Packit 3ff832
{
Packit 3ff832
    GSList *retval;
Packit 3ff832
    gchar *path = (gchar *)task_data;
Packit 3ff832
    GError *error = NULL;
Packit 3ff832
Packit 3ff832
    g_assert (path != NULL);
Packit 3ff832
Packit 3ff832
    retval = ibus_unicode_data_load_with_error (path, source_object, &error);
Packit 3ff832
    g_free (path);
Packit 3ff832
    if (retval == NULL)
Packit 3ff832
        g_task_return_error (task, error);
Packit 3ff832
    else
Packit 3ff832
        g_task_return_pointer (task, retval, NULL);
Packit 3ff832
    g_object_unref (task);
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static void
Packit 3ff832
ibus_unicode_data_load_async_done (GObject *source_object,
Packit 3ff832
                                   GAsyncResult *res,
Packit 3ff832
                                   gpointer user_data)
Packit 3ff832
{
Packit 3ff832
    IBusUnicodeDataLoadData *data = (IBusUnicodeDataLoadData*)user_data;
Packit 3ff832
    GSList *list;
Packit 3ff832
    GError *error = NULL;
Packit 3ff832
    g_assert (data != NULL);
Packit 3ff832
    list = g_task_propagate_pointer (G_TASK (res), &error);
Packit 3ff832
    if (error) {
Packit 3ff832
        g_warning ("%s", error->message);
Packit 3ff832
        g_error_free (error);
Packit 3ff832
        data->callback (NULL, data->user_data);
Packit 3ff832
    } else {
Packit 3ff832
        data->callback (list, data->user_data);
Packit 3ff832
    }
Packit 3ff832
    g_slice_free (IBusUnicodeDataLoadData, data);
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
void
Packit 3ff832
ibus_unicode_data_load_async (const gchar        *path,
Packit 3ff832
                              GObject            *source_object,
Packit 3ff832
                              GCancellable       *cancellable,
Packit 3ff832
                              IBusUnicodeDataLoadAsyncFinish
Packit 3ff832
                                                  callback,
Packit 3ff832
                              gpointer            user_data)
Packit 3ff832
{
Packit 3ff832
    GTask *task;
Packit 3ff832
    IBusUnicodeDataLoadData *data;
Packit 3ff832
Packit 3ff832
    g_return_if_fail (path != NULL);
Packit 3ff832
Packit 3ff832
    data = g_slice_new0 (IBusUnicodeDataLoadData);
Packit 3ff832
    data->callback = callback;
Packit 3ff832
    data->user_data = user_data;
Packit 3ff832
    task = g_task_new (source_object,
Packit 3ff832
                       cancellable,
Packit 3ff832
                       ibus_unicode_data_load_async_done,
Packit 3ff832
                       data);
Packit 3ff832
    g_task_set_source_tag (task, ibus_unicode_data_load_async);
Packit 3ff832
    g_task_set_task_data (task, g_strdup (path), NULL);
Packit 3ff832
    g_task_run_in_thread (task, ibus_unicode_data_load_async_thread);
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static void
Packit 3ff832
ibus_unicode_block_class_init (IBusUnicodeBlockClass *class)
Packit 3ff832
{
Packit 3ff832
    IBusObjectClass *object_class = IBUS_OBJECT_CLASS (class);
Packit 3ff832
    GObjectClass *gobject_class = G_OBJECT_CLASS (class);
Packit 3ff832
    IBusSerializableClass *serializable_class = IBUS_SERIALIZABLE_CLASS (class);
Packit 3ff832
Packit 3ff832
    object_class->destroy = (IBusObjectDestroyFunc) ibus_unicode_block_destroy;
Packit 3ff832
    gobject_class->set_property =
Packit 3ff832
            (GObjectSetPropertyFunc) ibus_unicode_block_set_property;
Packit 3ff832
    gobject_class->get_property =
Packit 3ff832
            (GObjectGetPropertyFunc) ibus_unicode_block_get_property;
Packit 3ff832
    serializable_class->serialize   =
Packit 3ff832
            (IBusSerializableSerializeFunc) ibus_unicode_block_serialize;
Packit 3ff832
    serializable_class->deserialize =
Packit 3ff832
            (IBusSerializableDeserializeFunc) ibus_unicode_block_deserialize;
Packit 3ff832
    serializable_class->copy        =
Packit 3ff832
            (IBusSerializableCopyFunc) ibus_unicode_block_copy;
Packit 3ff832
Packit 3ff832
    g_type_class_add_private (class, sizeof (IBusUnicodeBlockPrivate));
Packit 3ff832
Packit 3ff832
    /* install properties */
Packit 3ff832
    /**
Packit 3ff832
     * IBusUnicodeBlock:start:
Packit 3ff832
     *
Packit 3ff832
     * The Uniode start code point
Packit 3ff832
     */
Packit 3ff832
    g_object_class_install_property (gobject_class,
Packit 3ff832
                    PROP_START,
Packit 3ff832
                    /* Cannot use g_param_spec_unichar() for the Unicode
Packit 3ff832
                     * boundary values because the function checks
Packit 3ff832
                     * if the value is a valid Unicode besides MAXUINT.
Packit 3ff832
                     */
Packit 3ff832
                    g_param_spec_uint ("start",
Packit 3ff832
                        "start code point",
Packit 3ff832
                        "The Unicode start code point",
Packit 3ff832
                        0,
Packit 3ff832
                        G_MAXUINT,
Packit 3ff832
                        0,
Packit 3ff832
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
Packit 3ff832
Packit 3ff832
Packit 3ff832
    /**
Packit 3ff832
     * IBusUnicodeBlock:end:
Packit 3ff832
     *
Packit 3ff832
     * The Uniode end code point
Packit 3ff832
     */
Packit 3ff832
    g_object_class_install_property (gobject_class,
Packit 3ff832
                    PROP_END,
Packit 3ff832
                    /* Cannot use g_param_spec_unichar() for the Unicode
Packit 3ff832
                     * boundary values because the function checks
Packit 3ff832
                     * if the value is a valid Unicode besides MAXUINT.
Packit 3ff832
                     */
Packit 3ff832
                    g_param_spec_uint ("end",
Packit 3ff832
                        "end code point",
Packit 3ff832
                        "The Unicode end code point",
Packit 3ff832
                        0,
Packit 3ff832
                        G_MAXUINT,
Packit 3ff832
                        0,
Packit 3ff832
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
Packit 3ff832
Packit 3ff832
Packit 3ff832
    /**
Packit 3ff832
     * IBusUnicodeBlock:name:
Packit 3ff832
     *
Packit 3ff832
     * The Uniode block name
Packit 3ff832
     */
Packit 3ff832
    g_object_class_install_property (gobject_class,
Packit 3ff832
                    PROP_NAME,
Packit 3ff832
                    g_param_spec_string ("name",
Packit 3ff832
                        "name",
Packit 3ff832
                        "The Unicode name",
Packit 3ff832
                        "",
Packit 3ff832
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static void
Packit 3ff832
ibus_unicode_block_init (IBusUnicodeBlock *block)
Packit 3ff832
{
Packit 3ff832
    block->priv = IBUS_UNICODE_BLOCK_GET_PRIVATE (block);
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static void
Packit 3ff832
ibus_unicode_block_destroy (IBusUnicodeBlock *block)
Packit 3ff832
{
Packit 3ff832
    g_clear_pointer (&block->priv->name, g_free);
Packit 3ff832
Packit 3ff832
    IBUS_OBJECT_CLASS (ibus_unicode_data_parent_class)->
Packit 3ff832
            destroy (IBUS_OBJECT (block));
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static void
Packit 3ff832
ibus_unicode_block_set_property (IBusUnicodeBlock *block,
Packit 3ff832
                                 guint             prop_id,
Packit 3ff832
                                 const GValue     *value,
Packit 3ff832
                                 GParamSpec       *pspec)
Packit 3ff832
{
Packit 3ff832
    switch (prop_id) {
Packit 3ff832
    case PROP_START:
Packit 3ff832
        g_assert (block->priv->start == 0);
Packit 3ff832
        block->priv->start = g_value_get_uint (value);
Packit 3ff832
        break;
Packit 3ff832
    case PROP_END:
Packit 3ff832
        g_assert (block->priv->end == 0);
Packit 3ff832
        block->priv->end = g_value_get_uint (value);
Packit 3ff832
        break;
Packit 3ff832
    case PROP_NAME:
Packit 3ff832
        g_assert (block->priv->name == NULL);
Packit 3ff832
        block->priv->name = g_value_dup_string (value);
Packit 3ff832
        break;
Packit 3ff832
    default:
Packit 3ff832
        G_OBJECT_WARN_INVALID_PROPERTY_ID (block, prop_id, pspec);
Packit 3ff832
    }
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static void
Packit 3ff832
ibus_unicode_block_get_property (IBusUnicodeBlock *block,
Packit 3ff832
                                 guint             prop_id,
Packit 3ff832
                                 GValue           *value,
Packit 3ff832
                                 GParamSpec       *pspec)
Packit 3ff832
{
Packit 3ff832
    switch (prop_id) {
Packit 3ff832
    case PROP_START:
Packit 3ff832
        g_value_set_uint (value, ibus_unicode_block_get_start (block));
Packit 3ff832
        break;
Packit 3ff832
    case PROP_END:
Packit 3ff832
        g_value_set_uint (value, ibus_unicode_block_get_end (block));
Packit 3ff832
        break;
Packit 3ff832
    case PROP_NAME:
Packit 3ff832
        g_value_set_string (value, ibus_unicode_block_get_name (block));
Packit 3ff832
        break;
Packit 3ff832
    default:
Packit 3ff832
        G_OBJECT_WARN_INVALID_PROPERTY_ID (block, prop_id, pspec);
Packit 3ff832
    }
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static gboolean
Packit 3ff832
ibus_unicode_block_serialize (IBusUnicodeBlock *block,
Packit 3ff832
                              GVariantBuilder  *builder)
Packit 3ff832
{
Packit 3ff832
    gboolean retval = IBUS_SERIALIZABLE_CLASS (ibus_unicode_block_parent_class)->
Packit 3ff832
            serialize ((IBusSerializable *)block, builder);
Packit 3ff832
    g_return_val_if_fail (retval, FALSE);
Packit 3ff832
Packit 3ff832
#define NOTNULL(s) ((s) != NULL ? (s) : "")
Packit 3ff832
    /* If you will add a new property, you can append it at the end and
Packit 3ff832
     * you should not change the serialized order of name, longname,
Packit 3ff832
     * description, ... because the order is also used in other applications
Packit 3ff832
     * likes ibus-qt. */
Packit 3ff832
    g_variant_builder_add (builder, "u", block->priv->start);
Packit 3ff832
    g_variant_builder_add (builder, "u", block->priv->end);
Packit 3ff832
    g_variant_builder_add (builder, "s", NOTNULL (block->priv->name));
Packit 3ff832
#undef NOTNULL
Packit 3ff832
    return TRUE;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static gint
Packit 3ff832
ibus_unicode_block_deserialize (IBusUnicodeBlock *block,
Packit 3ff832
                                GVariant        *variant)
Packit 3ff832
{
Packit 3ff832
    gint retval = IBUS_SERIALIZABLE_CLASS (ibus_unicode_block_parent_class)->
Packit 3ff832
            deserialize ((IBusSerializable *)block, variant);
Packit 3ff832
    g_return_val_if_fail (retval, 0);
Packit 3ff832
Packit 3ff832
    /* If you will add a new property, you can append it at the end and
Packit 3ff832
     * you should not change the serialized order of name, longname,
Packit 3ff832
     * description, ... because the order is also used in other applications
Packit 3ff832
     * likes ibus-qt. */
Packit 3ff832
    g_variant_get_child (variant, retval++, "u", &block->priv->start);
Packit 3ff832
    g_variant_get_child (variant, retval++, "u", &block->priv->end);
Packit 3ff832
    ibus_g_variant_get_child_string (variant, retval++,
Packit 3ff832
                                     &block->priv->name);
Packit 3ff832
    return retval;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static gboolean
Packit 3ff832
ibus_unicode_block_copy (IBusUnicodeBlock       *dest,
Packit 3ff832
                         const IBusUnicodeBlock *src)
Packit 3ff832
{
Packit 3ff832
    gboolean retval = IBUS_SERIALIZABLE_CLASS (ibus_unicode_block_parent_class)->
Packit 3ff832
            copy ((IBusSerializable *)dest,
Packit 3ff832
                  (IBusSerializable *)src);
Packit 3ff832
    g_return_val_if_fail (retval, FALSE);
Packit 3ff832
Packit 3ff832
    dest->priv->start            = src->priv->start;
Packit 3ff832
    dest->priv->end              = src->priv->end;
Packit 3ff832
    dest->priv->name             = g_strdup (src->priv->name);
Packit 3ff832
    return TRUE;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
IBusUnicodeBlock *
Packit 3ff832
ibus_unicode_block_new (const gchar *first_property_name, ...)
Packit 3ff832
{
Packit 3ff832
    va_list var_args;
Packit 3ff832
    IBusUnicodeBlock *block;
Packit 3ff832
Packit 3ff832
    g_assert (first_property_name != NULL);
Packit 3ff832
    va_start (var_args, first_property_name);
Packit 3ff832
    block = (IBusUnicodeBlock *) g_object_new_valist (IBUS_TYPE_UNICODE_BLOCK,
Packit 3ff832
                                                     first_property_name,
Packit 3ff832
                                                     var_args);
Packit 3ff832
    va_end (var_args);
Packit 3ff832
    /* end is required. Other properties are set in class_init by default. */
Packit 3ff832
    g_assert (block->priv->start != block->priv->end);
Packit 3ff832
    g_assert (block->priv->name != NULL);
Packit 3ff832
    return block;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
gunichar
Packit 3ff832
ibus_unicode_block_get_start (IBusUnicodeBlock *block)
Packit 3ff832
{
Packit 3ff832
    g_return_val_if_fail (IBUS_IS_UNICODE_BLOCK (block), G_MAXUINT32);
Packit 3ff832
Packit 3ff832
    return block->priv->start;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
gunichar
Packit 3ff832
ibus_unicode_block_get_end (IBusUnicodeBlock *block)
Packit 3ff832
{
Packit 3ff832
    g_return_val_if_fail (IBUS_IS_UNICODE_BLOCK (block), G_MAXUINT32);
Packit 3ff832
Packit 3ff832
    return block->priv->end;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
const gchar *
Packit 3ff832
ibus_unicode_block_get_name (IBusUnicodeBlock *block)
Packit 3ff832
{
Packit 3ff832
    g_return_val_if_fail (IBUS_IS_UNICODE_BLOCK (block), "");
Packit 3ff832
Packit 3ff832
    return block->priv->name;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static void
Packit 3ff832
variant_foreach_add_block (IBusUnicodeBlock *block,
Packit 3ff832
                           GVariantBuilder *builder)
Packit 3ff832
{
Packit 3ff832
    g_variant_builder_add (
Packit 3ff832
            builder, "v",
Packit 3ff832
            ibus_serializable_serialize (IBUS_SERIALIZABLE (block)));
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static GVariant *
Packit 3ff832
ibus_unicode_block_list_serialize (GSList *list)
Packit 3ff832
{
Packit 3ff832
    GVariantBuilder builder;
Packit 3ff832
Packit 3ff832
    g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
Packit 3ff832
    g_slist_foreach (list,  (GFunc) variant_foreach_add_block, &builder);
Packit 3ff832
    return g_variant_builder_end (&builder);
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
static GSList *
Packit 3ff832
ibus_unicode_block_list_deserialize (GVariant *variant)
Packit 3ff832
{
Packit 3ff832
    GSList *list = NULL;
Packit 3ff832
    GVariantIter iter;
Packit 3ff832
    GVariant *unicode_variant = NULL;
Packit 3ff832
Packit 3ff832
    g_variant_iter_init (&iter, variant);
Packit 3ff832
    while (g_variant_iter_loop (&iter, "v", &unicode_variant)) {
Packit 3ff832
        IBusUnicodeBlock *data =
Packit 3ff832
                IBUS_UNICODE_BLOCK (ibus_serializable_deserialize (
Packit 3ff832
                        unicode_variant));
Packit 3ff832
        list = g_slist_append (list, data);
Packit 3ff832
        g_clear_pointer (&unicode_variant, g_variant_unref);
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    return list;
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
void
Packit 3ff832
ibus_unicode_block_save (const gchar *path,
Packit 3ff832
                         GSList      *list)
Packit 3ff832
{
Packit 3ff832
    GVariant *variant;
Packit 3ff832
    const gchar *header = IBUS_UNICODE_BLOCK_MAGIC;
Packit 3ff832
    const guint16 version = IBUS_UNICODE_DATA_VERSION;
Packit 3ff832
    const gchar *contents;
Packit 3ff832
    gsize length;
Packit 3ff832
    gchar *dir;
Packit 3ff832
    GStatBuf buf = { 0, };
Packit 3ff832
    GError *error = NULL;
Packit 3ff832
Packit 3ff832
    g_return_if_fail (path != NULL);
Packit 3ff832
    g_return_if_fail (list != NULL);
Packit 3ff832
    if (list->data == NULL) {
Packit 3ff832
        g_warning ("Failed to save IBus Unicode block: Need a list data.");
Packit 3ff832
        return;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    variant = g_variant_new ("(sqv)",
Packit 3ff832
                             header,
Packit 3ff832
                             version,
Packit 3ff832
                             ibus_unicode_block_list_serialize (list));
Packit 3ff832
Packit 3ff832
    contents =  g_variant_get_data (variant);
Packit 3ff832
    length =  g_variant_get_size (variant);
Packit 3ff832
Packit 3ff832
    dir = g_path_get_dirname (path);
Packit 3ff832
    if (g_strcmp0 (dir, ".") != 0 && g_stat (dir, &buf) != 0) {
Packit 3ff832
        g_mkdir_with_parents (dir, 0777);
Packit 3ff832
    }
Packit 3ff832
    g_free (dir);
Packit 3ff832
    if (!g_file_set_contents (path, contents, length, &error)) {
Packit 3ff832
        g_warning ("Failed to save Unicode dict %s: %s", path, error->message);
Packit 3ff832
        g_error_free (error);
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    g_variant_unref (variant);
Packit 3ff832
}
Packit 3ff832
Packit 3ff832
GSList *
Packit 3ff832
ibus_unicode_block_load (const gchar *path)
Packit 3ff832
{
Packit 3ff832
    gchar *contents = NULL;
Packit 3ff832
    gsize length = 0;
Packit 3ff832
    GError *error = NULL;
Packit 3ff832
    GVariant *variant_table = NULL;
Packit 3ff832
    GVariant *variant = NULL;
Packit 3ff832
    const gchar *header = NULL;
Packit 3ff832
    guint16 version = 0;
Packit 3ff832
    GSList *retval = NULL;
Packit 3ff832
Packit 3ff832
    if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
Packit 3ff832
        g_warning ("Unicode dict does not exist: %s", path);
Packit 3ff832
        goto out_load_cache;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    if (!g_file_get_contents (path, &contents, &length, &error)) {
Packit 3ff832
        g_warning ("Failed to get dict content %s: %s", path, error->message);
Packit 3ff832
        g_error_free (error);
Packit 3ff832
        goto out_load_cache;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    variant_table = g_variant_new_from_data (G_VARIANT_TYPE ("(sq)"),
Packit 3ff832
                                             contents,
Packit 3ff832
                                             length,
Packit 3ff832
                                             FALSE,
Packit 3ff832
                                             NULL,
Packit 3ff832
                                             NULL);
Packit 3ff832
Packit 3ff832
    if (variant_table == NULL) {
Packit 3ff832
        g_warning ("cache table is broken.");
Packit 3ff832
        goto out_load_cache;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    g_variant_get (variant_table, "(&sq)", &header, &version);
Packit 3ff832
Packit 3ff832
    if (g_strcmp0 (header, IBUS_UNICODE_BLOCK_MAGIC) != 0) {
Packit 3ff832
        g_warning ("cache is not IBusUnicodeBlock.");
Packit 3ff832
        goto out_load_cache;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    if (version > IBUS_UNICODE_DATA_VERSION) {
Packit 3ff832
        g_warning ("cache version is different: %u != %u",
Packit 3ff832
                   version, IBUS_UNICODE_DATA_VERSION);
Packit 3ff832
        goto out_load_cache;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    version = 0;
Packit 3ff832
    header = NULL;
Packit 3ff832
    g_variant_unref (variant_table);
Packit 3ff832
Packit 3ff832
    variant_table = g_variant_new_from_data (G_VARIANT_TYPE ("(sqv)"),
Packit 3ff832
                                             contents,
Packit 3ff832
                                             length,
Packit 3ff832
                                             FALSE,
Packit 3ff832
                                             NULL,
Packit 3ff832
                                             NULL);
Packit 3ff832
Packit 3ff832
    if (variant_table == NULL) {
Packit 3ff832
        g_warning ("cache table is broken.");
Packit 3ff832
        goto out_load_cache;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    g_variant_get (variant_table, "(&sqv)",
Packit 3ff832
                   NULL,
Packit 3ff832
                   NULL,
Packit 3ff832
                   &variant);
Packit 3ff832
Packit 3ff832
    if (variant == NULL) {
Packit 3ff832
        g_warning ("cache dict is broken.");
Packit 3ff832
        goto out_load_cache;
Packit 3ff832
    }
Packit 3ff832
Packit 3ff832
    retval = ibus_unicode_block_list_deserialize (variant);
Packit 3ff832
Packit 3ff832
out_load_cache:
Packit 3ff832
    if (variant)
Packit 3ff832
        g_variant_unref (variant);
Packit 3ff832
    if (variant_table)
Packit 3ff832
        g_variant_unref (variant_table);
Packit 3ff832
    g_free (contents);
Packit 3ff832
Packit 3ff832
    return retval;
Packit 3ff832
}
Packit 3ff832