Blame src/ibusxml.c

Packit Service 1d8f1c
/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
Packit Service 1d8f1c
/* vim:set et sts=4: */
Packit Service 1d8f1c
/* bus - The Input Bus
Packit Service 1d8f1c
 * Copyright (C) 2008-2015 Peng Huang <shawn.p.huang@gmail.com>
Packit Service 1d8f1c
 * Copyright (C) 2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
Packit Service 1d8f1c
 * Copyright (C) 2008-2018 Red Hat, Inc.
Packit Service 1d8f1c
 *
Packit Service 1d8f1c
 * This library is free software; you can redistribute it and/or
Packit Service 1d8f1c
 * modify it under the terms of the GNU Lesser General Public
Packit Service 1d8f1c
 * License as published by the Free Software Foundation; either
Packit Service 1d8f1c
 * version 2.1 of the License, or (at your option) any later version.
Packit Service 1d8f1c
 *
Packit Service 1d8f1c
 * This library is distributed in the hope that it will be useful,
Packit Service 1d8f1c
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 1d8f1c
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 1d8f1c
 * Lesser General Public License for more details.
Packit Service 1d8f1c
 *
Packit Service 1d8f1c
 * You should have received a copy of the GNU Lesser General Public
Packit Service 1d8f1c
 * License along with this library; if not, write to the Free Software
Packit Service 1d8f1c
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
Packit Service 1d8f1c
 * USA
Packit Service 1d8f1c
 */
Packit Service 1d8f1c
#include <stdio.h>
Packit Service 1d8f1c
#include <string.h>
Packit Service 1d8f1c
#include "ibusxml.h"
Packit Service 1d8f1c
Packit Service 1d8f1c
static GMarkupParser parser;
Packit Service 1d8f1c
Packit Service 1d8f1c
G_DEFINE_BOXED_TYPE (IBusXML, ibus_xml,
Packit Service 1d8f1c
                     ibus_xml_copy,
Packit Service 1d8f1c
                     ibus_xml_free);
Packit Service 1d8f1c
Packit Service 1d8f1c
XMLNode*
Packit Service 1d8f1c
ibus_xml_copy (const XMLNode *node)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    XMLNode *ret;
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (node == NULL)
Packit Service 1d8f1c
        return NULL;
Packit Service 1d8f1c
Packit Service 1d8f1c
    ret = g_slice_new (XMLNode);
Packit Service 1d8f1c
Packit Service 1d8f1c
    *ret = *node;
Packit Service 1d8f1c
Packit Service 1d8f1c
    return ret;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
void
Packit Service 1d8f1c
ibus_xml_free (XMLNode *node)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    g_free (node->name);
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_free (node->text);
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_strfreev (node->attributes);
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_list_free_full (node->sub_nodes, (GDestroyNotify) ibus_xml_free);
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_slice_free (XMLNode, node);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
_start_root_element_cb (GMarkupParseContext *context,
Packit Service 1d8f1c
                        const gchar         *element_name,
Packit Service 1d8f1c
                        const gchar        **attribute_names,
Packit Service 1d8f1c
                        const gchar        **attribute_values,
Packit Service 1d8f1c
                        gpointer             user_data,
Packit Service 1d8f1c
                        GError             **error)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    XMLNode **node = (XMLNode **) user_data;
Packit Service 1d8f1c
    g_assert (node != NULL);
Packit Service 1d8f1c
Packit Service 1d8f1c
    XMLNode *p = g_slice_new0 (XMLNode);
Packit Service 1d8f1c
Packit Service 1d8f1c
Packit Service 1d8f1c
    p->name = g_strdup (element_name);
Packit Service 1d8f1c
Packit Service 1d8f1c
    GArray *attributes = g_array_new (TRUE, TRUE, sizeof (gchar *));
Packit Service 1d8f1c
    while (*attribute_names != NULL && *attribute_values != NULL) {
Packit Service 1d8f1c
        gchar *p;
Packit Service 1d8f1c
        p = g_strdup (*attribute_names++);
Packit Service 1d8f1c
        g_array_append_val (attributes, p);
Packit Service 1d8f1c
        p = g_strdup (*attribute_values++);
Packit Service 1d8f1c
        g_array_append_val (attributes, p);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    p->attributes = (gchar **) g_array_free (attributes, FALSE);
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_markup_parse_context_push (context, &parser, p);
Packit Service 1d8f1c
    *node = p;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
_start_element_cb (GMarkupParseContext *context,
Packit Service 1d8f1c
                   const gchar         *element_name,
Packit Service 1d8f1c
                   const gchar        **attribute_names,
Packit Service 1d8f1c
                   const gchar        **attribute_values,
Packit Service 1d8f1c
                   gpointer             user_data,
Packit Service 1d8f1c
                   GError             **error)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    XMLNode *node = (XMLNode *) user_data;
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (node->text) {
Packit Service 1d8f1c
        g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, " ");
Packit Service 1d8f1c
        return;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    XMLNode *p = g_slice_new0 (XMLNode);
Packit Service 1d8f1c
Packit Service 1d8f1c
    node->sub_nodes = g_list_append (node->sub_nodes, p);
Packit Service 1d8f1c
    g_markup_parse_context_push (context, &parser, p);
Packit Service 1d8f1c
Packit Service 1d8f1c
    p->name = g_strdup (element_name);
Packit Service 1d8f1c
Packit Service 1d8f1c
    GArray *attributes = g_array_new (TRUE, TRUE, sizeof (gchar *));
Packit Service 1d8f1c
    while (*attribute_names != NULL && *attribute_values != NULL) {
Packit Service 1d8f1c
        gchar *p;
Packit Service 1d8f1c
        p = g_strdup (*attribute_names++);
Packit Service 1d8f1c
        g_array_append_val (attributes, p);
Packit Service 1d8f1c
        p = g_strdup (*attribute_values++);
Packit Service 1d8f1c
        g_array_append_val (attributes, p);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    p->attributes = (gchar **)g_array_free (attributes, FALSE);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
_end_element_cb (GMarkupParseContext *context,
Packit Service 1d8f1c
                 const gchar         *element_name,
Packit Service 1d8f1c
                 gpointer             user_data,
Packit Service 1d8f1c
                 GError             **error)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    XMLNode *p = (XMLNode *) g_markup_parse_context_pop (context);
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (p->text && p->sub_nodes) {
Packit Service 1d8f1c
        g_warning ("Error");
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (p->text == NULL && p->sub_nodes == NULL) {
Packit Service 1d8f1c
        p->text = g_strdup ("");
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gboolean
Packit Service 1d8f1c
_is_space (const gchar *text,
Packit Service 1d8f1c
           gsize        text_len)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    gsize i = 0;
Packit Service 1d8f1c
Packit Service 1d8f1c
    for (i = 0; text[i] != '\0' && i < text_len; i++) {
Packit Service 1d8f1c
        switch (text[i]) {
Packit Service 1d8f1c
        case '\t':
Packit Service 1d8f1c
        case ' ':
Packit Service 1d8f1c
        case '\n':
Packit Service 1d8f1c
        case '\r':
Packit Service 1d8f1c
            continue;
Packit Service 1d8f1c
        default:
Packit Service 1d8f1c
            return FALSE;
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    return TRUE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
_text_cb (GMarkupParseContext *context,
Packit Service 1d8f1c
          const gchar         *text,
Packit Service 1d8f1c
          gsize                text_len,
Packit Service 1d8f1c
          gpointer             user_data,
Packit Service 1d8f1c
          GError             **error)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    XMLNode *p = (XMLNode *)user_data;
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (_is_space (text, text_len)) {
Packit Service 1d8f1c
        return;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (p->sub_nodes || p->text) {
Packit Service 1d8f1c
        g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, " ");
Packit Service 1d8f1c
        return;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    p->text = g_strndup (text, text_len);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static GMarkupParser parser = {
Packit Service 1d8f1c
    _start_element_cb,
Packit Service 1d8f1c
    _end_element_cb,
Packit Service 1d8f1c
    _text_cb,
Packit Service 1d8f1c
    0,
Packit Service 1d8f1c
    0,
Packit Service 1d8f1c
};
Packit Service 1d8f1c
Packit Service 1d8f1c
XMLNode *
Packit Service 1d8f1c
ibus_xml_parse_file (const gchar *filename)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    gboolean retval = FALSE;
Packit Service 1d8f1c
    GError *error = NULL;
Packit Service 1d8f1c
    FILE *pf = fopen (filename, "r");
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (pf == NULL) {
Packit Service 1d8f1c
        return NULL;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    GMarkupParseContext *context;
Packit Service 1d8f1c
    XMLNode *node;
Packit Service 1d8f1c
Packit Service 1d8f1c
    const static GMarkupParser root_parser = {
Packit Service 1d8f1c
        _start_root_element_cb,
Packit Service 1d8f1c
        _end_element_cb,
Packit Service 1d8f1c
        _text_cb,
Packit Service 1d8f1c
        0,
Packit Service 1d8f1c
        0,
Packit Service 1d8f1c
    };
Packit Service 1d8f1c
Packit Service 1d8f1c
    do {
Packit Service 1d8f1c
        context = g_markup_parse_context_new (&root_parser, 0, &node, 0);
Packit Service 1d8f1c
Packit Service 1d8f1c
        while (!feof (pf)) {
Packit Service 1d8f1c
            gchar buf[1024];
Packit Service 1d8f1c
            gssize len = 0;
Packit Service 1d8f1c
Packit Service 1d8f1c
            len = fread (buf, 1, sizeof (buf), pf);
Packit Service 1d8f1c
            retval = g_markup_parse_context_parse (context, buf, len, &error);
Packit Service 1d8f1c
Packit Service 1d8f1c
            if (!retval)
Packit Service 1d8f1c
                break;
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
        fclose (pf);
Packit Service 1d8f1c
Packit Service 1d8f1c
        if (!retval)
Packit Service 1d8f1c
            break;
Packit Service 1d8f1c
Packit Service 1d8f1c
        retval = g_markup_parse_context_end_parse (context, &error);
Packit Service 1d8f1c
        if (!retval)
Packit Service 1d8f1c
            break;
Packit Service 1d8f1c
Packit Service 1d8f1c
        g_markup_parse_context_free (context);
Packit Service 1d8f1c
Packit Service 1d8f1c
        return node;
Packit Service 1d8f1c
    } while (0);
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (error) {
Packit Service 1d8f1c
        g_warning ("Parse %s failed: %s", filename, error->message);
Packit Service 1d8f1c
        g_error_free (error);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    g_markup_parse_context_free (context);
Packit Service 1d8f1c
    return NULL;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
XMLNode *
Packit Service 1d8f1c
ibus_xml_parse_buffer (const gchar *buffer)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    gboolean retval;
Packit Service 1d8f1c
    GError *error = NULL;
Packit Service 1d8f1c
Packit Service 1d8f1c
    GMarkupParseContext *context;
Packit Service 1d8f1c
    XMLNode *node;
Packit Service 1d8f1c
Packit Service 1d8f1c
    const static GMarkupParser root_parser = {
Packit Service 1d8f1c
        _start_root_element_cb,
Packit Service 1d8f1c
        _end_element_cb,
Packit Service 1d8f1c
        _text_cb,
Packit Service 1d8f1c
        0,
Packit Service 1d8f1c
        0,
Packit Service 1d8f1c
    };
Packit Service 1d8f1c
Packit Service 1d8f1c
    context = g_markup_parse_context_new (&root_parser, 0, &node, 0);
Packit Service 1d8f1c
Packit Service 1d8f1c
    do {
Packit Service 1d8f1c
        retval = g_markup_parse_context_parse (context, buffer, strlen (buffer), &error);
Packit Service 1d8f1c
        if (!retval)
Packit Service 1d8f1c
            break;
Packit Service 1d8f1c
Packit Service 1d8f1c
        retval = g_markup_parse_context_end_parse (context, &error);
Packit Service 1d8f1c
        if (!retval)
Packit Service 1d8f1c
            break;
Packit Service 1d8f1c
        g_markup_parse_context_free (context);
Packit Service 1d8f1c
        return node;
Packit Service 1d8f1c
    } while (0);
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_warning ("Parse buffer failed: %s", error->message);
Packit Service 1d8f1c
    g_error_free (error);
Packit Service 1d8f1c
    g_markup_parse_context_free (context);
Packit Service 1d8f1c
    return NULL;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
output_indent (int level, GString *output)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    gint i;
Packit Service 1d8f1c
    for (i = 0; i < level; i++) {
Packit Service 1d8f1c
        g_string_append (output, "    ");
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
xml_output_indent (const XMLNode *node, int level, GString *output)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    gchar **attrs;
Packit Service 1d8f1c
Packit Service 1d8f1c
    output_indent (level, output);
Packit Service 1d8f1c
    g_string_append_printf (output, "<%s", node->name);
Packit Service 1d8f1c
Packit Service 1d8f1c
    attrs = node->attributes;
Packit Service 1d8f1c
Packit Service 1d8f1c
    while (attrs != NULL && *attrs != NULL) {
Packit Service 1d8f1c
        g_string_append_printf (output, " %s", *(attrs++));
Packit Service 1d8f1c
        g_string_append_printf (output, "=\"%s\"", *(attrs++));
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (node->sub_nodes != NULL){
Packit Service 1d8f1c
        g_string_append (output, ">\n");
Packit Service 1d8f1c
        GList *sub_node;
Packit Service 1d8f1c
Packit Service 1d8f1c
        for (sub_node = node->sub_nodes; sub_node != NULL; sub_node = sub_node->next) {
Packit Service 1d8f1c
            xml_output_indent (sub_node->data, level + 1, output);
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
        output_indent (level, output);
Packit Service 1d8f1c
        g_string_append_printf (output, "</%s>\n",node->name);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    else if (node->text != NULL) {
Packit Service 1d8f1c
        gchar *text = g_markup_escape_text (node->text, -1);
Packit Service 1d8f1c
        g_string_append_printf (output, ">%s</%s>\n", text, node->name);
Packit Service 1d8f1c
        g_free (text);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    else {
Packit Service 1d8f1c
        g_string_append (output, "/>\n");
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
void
Packit Service 1d8f1c
ibus_xml_output (const XMLNode *node, GString *output)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    xml_output_indent (node, 0, output);
Packit Service 1d8f1c
}
Packit Service 1d8f1c