Blame libvirt-gconfig/libvirt-gconfig-object.c

Packit a07778
/*
Packit a07778
 * libvirt-gconfig-object.c: base object for XML configuration
Packit a07778
 *
Packit a07778
 * Copyright (C) 2008 Daniel P. Berrange
Packit a07778
 * Copyright (C) 2010-2011 Red Hat, Inc.
Packit a07778
 *
Packit a07778
 * This library is free software; you can redistribute it and/or
Packit a07778
 * modify it under the terms of the GNU Lesser General Public
Packit a07778
 * License as published by the Free Software Foundation; either
Packit a07778
 * version 2.1 of the License, or (at your option) any later version.
Packit a07778
 *
Packit a07778
 * This library is distributed in the hope that it will be useful,
Packit a07778
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit a07778
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit a07778
 * Lesser General Public License for more details.
Packit a07778
 *
Packit a07778
 * You should have received a copy of the GNU Lesser General Public
Packit a07778
 * License along with this library. If not, see
Packit a07778
 * <http://www.gnu.org/licenses/>.
Packit a07778
 *
Packit a07778
 * Author: Daniel P. Berrange <berrange@redhat.com>
Packit a07778
 */
Packit a07778
Packit a07778
#include <config.h>
Packit a07778
Packit a07778
#include <string.h>
Packit a07778
Packit a07778
#include <libxml/relaxng.h>
Packit a07778
#include <glib/gi18n-lib.h>
Packit a07778
Packit a07778
#include "libvirt-gconfig/libvirt-gconfig.h"
Packit a07778
#include "libvirt-gconfig/libvirt-gconfig-private.h"
Packit a07778
Packit a07778
#define GVIR_CONFIG_OBJECT_GET_PRIVATE(obj)                         \
Packit a07778
        (G_TYPE_INSTANCE_GET_PRIVATE((obj), GVIR_CONFIG_TYPE_OBJECT, GVirConfigObjectPrivate))
Packit a07778
Packit a07778
struct _GVirConfigObjectPrivate
Packit a07778
{
Packit a07778
    gchar *schema;
Packit a07778
Packit a07778
    GVirConfigXmlDoc *doc;
Packit a07778
    xmlNodePtr node;
Packit a07778
};
Packit a07778
Packit a07778
G_DEFINE_TYPE_WITH_PRIVATE(GVirConfigObject, gvir_config_object, G_TYPE_OBJECT);
Packit a07778
Packit a07778
enum {
Packit a07778
    PROP_0,
Packit a07778
    PROP_SCHEMA,
Packit a07778
    PROP_NODE,
Packit a07778
    PROP_DOC
Packit a07778
};
Packit a07778
Packit a07778
Packit a07778
static void gvir_xml_generic_error_nop(void *userData G_GNUC_UNUSED,
Packit a07778
                                       const char *msg G_GNUC_UNUSED,
Packit a07778
                                       ...)
Packit a07778
{
Packit a07778
}
Packit a07778
Packit a07778
static void gvir_xml_structured_error_nop(void *userData G_GNUC_UNUSED,
Packit a07778
                                          xmlErrorPtr error G_GNUC_UNUSED)
Packit a07778
{
Packit a07778
}
Packit a07778
Packit a07778
Packit a07778
static void gvir_config_object_get_property(GObject *object,
Packit a07778
                                            guint prop_id,
Packit a07778
                                            GValue *value,
Packit a07778
                                            GParamSpec *pspec)
Packit a07778
{
Packit a07778
    GVirConfigObject *obj = GVIR_CONFIG_OBJECT(object);
Packit a07778
    GVirConfigObjectPrivate *priv = obj->priv;
Packit a07778
Packit a07778
    switch (prop_id) {
Packit a07778
    case PROP_SCHEMA:
Packit a07778
        g_value_set_string(value, priv->schema);
Packit a07778
        break;
Packit a07778
Packit a07778
    case PROP_NODE:
Packit a07778
        g_value_set_pointer(value, gvir_config_object_get_xml_node(obj));
Packit a07778
        break;
Packit a07778
Packit a07778
    case PROP_DOC:
Packit a07778
        g_value_set_object(value, obj->priv->doc);
Packit a07778
        break;
Packit a07778
Packit a07778
    default:
Packit a07778
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
Packit a07778
    }
Packit a07778
}
Packit a07778
Packit a07778
static void gvir_config_object_set_property(GObject *object,
Packit a07778
                                            guint prop_id,
Packit a07778
                                            const GValue *value,
Packit a07778
                                            GParamSpec *pspec)
Packit a07778
{
Packit a07778
    GVirConfigObject *obj = GVIR_CONFIG_OBJECT(object);
Packit a07778
    GVirConfigObjectPrivate *priv = obj->priv;
Packit a07778
Packit a07778
    switch (prop_id) {
Packit a07778
    case PROP_SCHEMA:
Packit a07778
        g_free(priv->schema);
Packit a07778
        priv->schema = g_value_dup_string(value);
Packit a07778
        break;
Packit a07778
Packit a07778
    case PROP_NODE:
Packit a07778
        priv->node =g_value_get_pointer(value);
Packit a07778
        break;
Packit a07778
Packit a07778
    case PROP_DOC:
Packit a07778
        obj->priv->doc = g_value_dup_object(value);
Packit a07778
        break;
Packit a07778
Packit a07778
    default:
Packit a07778
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
Packit a07778
    }
Packit a07778
}
Packit a07778
Packit a07778
Packit a07778
static void gvir_config_object_finalize(GObject *object)
Packit a07778
{
Packit a07778
    GVirConfigObject *gvir_object = GVIR_CONFIG_OBJECT(object);
Packit a07778
    GVirConfigObjectPrivate *priv = gvir_object->priv;
Packit a07778
Packit a07778
    g_free(priv->schema);
Packit a07778
Packit a07778
    if (priv->doc != NULL) {
Packit a07778
        g_object_unref(G_OBJECT(priv->doc));
Packit a07778
        priv->node = NULL; /* node belongs to doc, make sure not to free it */
Packit a07778
    }
Packit a07778
    if (priv->node != NULL) {
Packit a07778
        g_assert(priv->node->doc == NULL);
Packit a07778
        xmlFreeNode(priv->node);
Packit a07778
    }
Packit a07778
Packit a07778
    G_OBJECT_CLASS(gvir_config_object_parent_class)->finalize(object);
Packit a07778
}
Packit a07778
Packit a07778
Packit a07778
static void gvir_config_object_class_init(GVirConfigObjectClass *klass)
Packit a07778
{
Packit a07778
    GObjectClass *object_class = G_OBJECT_CLASS(klass);
Packit a07778
Packit a07778
    object_class->finalize = gvir_config_object_finalize;
Packit a07778
    object_class->get_property = gvir_config_object_get_property;
Packit a07778
    object_class->set_property = gvir_config_object_set_property;
Packit a07778
Packit a07778
    g_object_class_install_property(object_class,
Packit a07778
                                    PROP_SCHEMA,
Packit a07778
                                    g_param_spec_string("schema",
Packit a07778
                                                        "Schema",
Packit a07778
                                                        "The doc RNG schema",
Packit a07778
                                                        NULL,
Packit a07778
                                                        G_PARAM_READABLE |
Packit a07778
                                                        G_PARAM_WRITABLE |
Packit a07778
                                                        G_PARAM_CONSTRUCT_ONLY |
Packit a07778
                                                        G_PARAM_STATIC_STRINGS));
Packit a07778
Packit a07778
    g_object_class_install_property(object_class,
Packit a07778
                                    PROP_NODE,
Packit a07778
                                    g_param_spec_pointer("node",
Packit a07778
                                                        "XML Node",
Packit a07778
                                                        "The XML node this config object corresponds to",
Packit a07778
                                                        G_PARAM_READWRITE |
Packit a07778
                                                        G_PARAM_CONSTRUCT_ONLY |
Packit a07778
                                                        G_PARAM_STATIC_STRINGS));
Packit a07778
Packit a07778
    g_object_class_install_property(object_class,
Packit a07778
                                    PROP_DOC,
Packit a07778
                                    g_param_spec_object("doc",
Packit a07778
                                                        "XML Doc",
Packit a07778
                                                        "The XML doc this config object corresponds to",
Packit a07778
                                                        GVIR_CONFIG_TYPE_XML_DOC,
Packit a07778
                                                        G_PARAM_READWRITE |
Packit a07778
                                                        G_PARAM_CONSTRUCT_ONLY |
Packit a07778
                                                        G_PARAM_STATIC_STRINGS));
Packit a07778
}
Packit a07778
Packit a07778
Packit a07778
static void gvir_config_object_init(GVirConfigObject *object)
Packit a07778
{
Packit a07778
    object->priv = GVIR_CONFIG_OBJECT_GET_PRIVATE(object);
Packit a07778
}
Packit a07778
Packit a07778
void gvir_config_object_validate(GVirConfigObject *config,
Packit a07778
                                 GError **err)
Packit a07778
{
Packit a07778
    GVirConfigObjectPrivate *priv;
Packit a07778
    xmlRelaxNGParserCtxtPtr rngParser = NULL;
Packit a07778
    xmlRelaxNGPtr rng = NULL;
Packit a07778
    xmlRelaxNGValidCtxtPtr rngValid = NULL;
Packit a07778
Packit a07778
    g_return_if_fail(GVIR_CONFIG_IS_OBJECT(config));
Packit a07778
    g_return_if_fail(err == NULL || *err == NULL);
Packit a07778
Packit a07778
    priv = config->priv;
Packit a07778
Packit a07778
    xmlSetGenericErrorFunc(NULL, gvir_xml_generic_error_nop);
Packit a07778
    xmlSetStructuredErrorFunc(NULL, gvir_xml_structured_error_nop);
Packit a07778
Packit a07778
    if (!priv->node) {
Packit a07778
        gvir_config_set_error_literal(err,
Packit a07778
                                      GVIR_CONFIG_OBJECT_ERROR,
Packit a07778
                                      0,
Packit a07778
                                      _("No XML document associated with this config object"));
Packit a07778
        return;
Packit a07778
    }
Packit a07778
Packit a07778
    if (!priv->schema) {
Packit a07778
        gvir_config_set_error_literal(err,
Packit a07778
                                      GVIR_CONFIG_OBJECT_ERROR,
Packit a07778
                                      0,
Packit a07778
                                      _("No XML schema associated with this config object"));
Packit a07778
        return;
Packit a07778
    }
Packit a07778
Packit a07778
    rngParser = xmlRelaxNGNewParserCtxt(priv->schema);
Packit a07778
    if (!rngParser) {
Packit a07778
        gvir_config_set_error(err,
Packit a07778
                              GVIR_CONFIG_OBJECT_ERROR,
Packit a07778
                              0,
Packit a07778
                              _("Unable to create RNG parser for %s"),
Packit a07778
                              priv->schema);
Packit a07778
        return;
Packit a07778
    }
Packit a07778
Packit a07778
    rng = xmlRelaxNGParse(rngParser);
Packit a07778
    if (!rng) {
Packit a07778
        gvir_config_set_error(err,
Packit a07778
                              GVIR_CONFIG_OBJECT_ERROR,
Packit a07778
                              0,
Packit a07778
                              _("Unable to parse RNG %s"),
Packit a07778
                              priv->schema);
Packit a07778
        xmlRelaxNGFreeParserCtxt(rngParser);
Packit a07778
        return;
Packit a07778
    }
Packit a07778
    xmlRelaxNGFreeParserCtxt(rngParser);
Packit a07778
Packit a07778
    rngValid = xmlRelaxNGNewValidCtxt(rng);
Packit a07778
    if (!rngValid) {
Packit a07778
        gvir_config_set_error(err,
Packit a07778
                              GVIR_CONFIG_OBJECT_ERROR,
Packit a07778
                              0,
Packit a07778
                              _("Unable to create RNG validation context %s"),
Packit a07778
                              priv->schema);
Packit a07778
        xmlRelaxNGFree(rng);
Packit a07778
        return;
Packit a07778
    }
Packit a07778
Packit a07778
    if (xmlRelaxNGValidateDoc(rngValid, priv->node->doc) != 0) {
Packit a07778
        gvir_config_set_error_literal(err,
Packit a07778
                                      GVIR_CONFIG_OBJECT_ERROR,
Packit a07778
                                      0,
Packit a07778
                                      _("Unable to validate doc"));
Packit a07778
        xmlRelaxNGFreeValidCtxt(rngValid);
Packit a07778
        xmlRelaxNGFree(rng);
Packit a07778
        return;
Packit a07778
    }
Packit a07778
Packit a07778
    xmlRelaxNGFreeValidCtxt(rngValid);
Packit a07778
    xmlRelaxNGFree(rng);
Packit a07778
}
Packit a07778
Packit a07778
gchar *gvir_config_object_to_xml(GVirConfigObject *config)
Packit a07778
{
Packit a07778
    g_return_val_if_fail(GVIR_CONFIG_IS_OBJECT(config), NULL);
Packit a07778
Packit a07778
    return gvir_config_xml_node_to_string(config->priv->node);
Packit a07778
}
Packit a07778
Packit a07778
const gchar *gvir_config_object_get_schema(GVirConfigObject *config)
Packit a07778
{
Packit a07778
    g_return_val_if_fail(GVIR_CONFIG_IS_OBJECT(config), NULL);
Packit a07778
Packit a07778
    return config->priv->schema;
Packit a07778
}
Packit a07778
Packit a07778
Packit a07778
G_GNUC_INTERNAL GVirConfigXmlDoc *
Packit a07778
gvir_config_object_get_xml_doc(GVirConfigObject *config)
Packit a07778
{
Packit a07778
    return config->priv->doc;
Packit a07778
}
Packit a07778
Packit a07778
Packit a07778
/* FIXME: will we always have one xmlNode per GConfig object? */
Packit a07778
/* FIXME: need to return the right node from subclasses */
Packit a07778
/* NB: the xmlNodePtr must not be freed by the caller */
Packit a07778
G_GNUC_INTERNAL xmlNodePtr
Packit a07778
gvir_config_object_get_xml_node(GVirConfigObject *config)
Packit a07778
{
Packit a07778
    return config->priv->node;
Packit a07778
}
Packit a07778
Packit a07778
G_GNUC_INTERNAL const char *
Packit a07778
gvir_config_object_get_node_content(GVirConfigObject *object,
Packit a07778
                                    const char *node_name)
Packit a07778
{
Packit a07778
    xmlNodePtr node;
Packit a07778
Packit a07778
    node = gvir_config_object_get_xml_node(GVIR_CONFIG_OBJECT(object));
Packit a07778
    if (node == NULL)
Packit a07778
        return NULL;
Packit a07778
Packit a07778
    return gvir_config_xml_get_child_element_content(node, node_name);
Packit a07778
}
Packit a07778
Packit a07778
G_GNUC_INTERNAL const char *
Packit a07778
gvir_config_object_get_attribute(GVirConfigObject *object,
Packit a07778
                                 const char *node_name,
Packit a07778
                                 const char *attr_name)
Packit a07778
{
Packit a07778
    xmlNodePtr node;
Packit a07778
Packit a07778
    g_return_val_if_fail(attr_name != NULL, NULL);
Packit a07778
Packit a07778
    node = gvir_config_object_get_xml_node(GVIR_CONFIG_OBJECT(object));
Packit a07778
    if (node == NULL)
Packit a07778
        return NULL;
Packit a07778
Packit a07778
    if (node_name != NULL) {
Packit a07778
        node = gvir_config_xml_get_element(node, node_name, NULL);
Packit a07778
        if (node == NULL)
Packit a07778
            return NULL;
Packit a07778
    }
Packit a07778
Packit a07778
    return gvir_config_xml_get_attribute_content(node, attr_name);
Packit a07778
}
Packit a07778
Packit a07778
static xmlNodePtr
Packit a07778
gvir_config_object_set_child_internal(GVirConfigObject *object,
Packit a07778
                                      xmlNodePtr child,
Packit a07778
                                      gboolean overwrite)
Packit a07778
{
Packit a07778
    xmlNodePtr parent_node;
Packit a07778
    xmlNodePtr old_node;
Packit a07778
Packit a07778
    parent_node = gvir_config_object_get_xml_node(GVIR_CONFIG_OBJECT(object));
Packit a07778
    g_return_val_if_fail (parent_node != NULL, NULL);
Packit a07778
Packit a07778
    old_node = gvir_config_xml_get_element(parent_node, child->name, NULL);
Packit a07778
    /* FIXME: should we make sure there are no multiple occurrences
Packit a07778
     * of this node?
Packit a07778
     */
Packit a07778
    if (old_node) {
Packit a07778
        if (overwrite) {
Packit a07778
            old_node = xmlReplaceNode(old_node, child);
Packit a07778
            xmlFreeNode(old_node);
Packit a07778
        } else {
Packit a07778
            return old_node;
Packit a07778
        }
Packit a07778
    } else {
Packit a07778
        xmlAddChild(parent_node, child);
Packit a07778
    }
Packit a07778
Packit a07778
    return NULL;
Packit a07778
}
Packit a07778
Packit a07778
G_GNUC_INTERNAL void
Packit a07778
gvir_config_object_set_child(GVirConfigObject *object, xmlNodePtr child)
Packit a07778
{
Packit a07778
    gvir_config_object_set_child_internal(object, child, TRUE);
Packit a07778
}
Packit a07778
Packit a07778
G_GNUC_INTERNAL void
Packit a07778
gvir_config_object_foreach_child(GVirConfigObject *object,
Packit a07778
                                 const char *parent_name,
Packit a07778
                                 GVirConfigXmlNodeIterator iter_func,
Packit a07778
                                 gpointer opaque)
Packit a07778
{
Packit a07778
    xmlNodePtr root_node;
Packit a07778
    xmlNodePtr node;
Packit a07778
Packit a07778
    g_return_if_fail(GVIR_CONFIG_IS_OBJECT(object));
Packit a07778
Packit a07778
    root_node = gvir_config_object_get_xml_node(object);
Packit a07778
    g_return_if_fail(root_node != NULL);
Packit a07778
Packit a07778
    node = gvir_config_xml_get_element(root_node, parent_name, NULL);
Packit a07778
    if (node == NULL)
Packit a07778
        return;
Packit a07778
Packit a07778
    gvir_config_xml_foreach_child(node, iter_func, opaque);
Packit a07778
}
Packit a07778
Packit a07778
G_GNUC_INTERNAL GVirConfigObject *
Packit a07778
gvir_config_object_add_child(GVirConfigObject *object,
Packit a07778
                             const char *child_name)
Packit a07778
{
Packit a07778
    xmlNodePtr new_node;
Packit a07778
    xmlNodePtr old_node;
Packit a07778
Packit a07778
    g_return_val_if_fail(GVIR_CONFIG_IS_OBJECT(object), NULL);
Packit a07778
    g_return_val_if_fail(child_name != NULL, NULL);
Packit a07778
Packit a07778
    new_node = xmlNewDocNode(NULL, NULL, (xmlChar *)child_name, NULL);
Packit a07778
    old_node = gvir_config_object_set_child_internal(object, new_node,
Packit a07778
                                                     FALSE);
Packit a07778
    if (old_node != NULL) {
Packit a07778
        xmlFreeNode(new_node);
Packit a07778
        return GVIR_CONFIG_OBJECT(g_object_new(GVIR_CONFIG_TYPE_OBJECT,
Packit a07778
                                               "doc", object->priv->doc,
Packit a07778
                                               "node", old_node,
Packit a07778
                                               NULL));
Packit a07778
    }
Packit a07778
Packit a07778
    return GVIR_CONFIG_OBJECT(g_object_new(GVIR_CONFIG_TYPE_OBJECT,
Packit a07778
                                           "doc", object->priv->doc,
Packit a07778
                                           "node", new_node,
Packit a07778
                                           NULL));
Packit a07778
}
Packit a07778
Packit a07778
G_GNUC_INTERNAL void
Packit a07778
gvir_config_object_add_child_with_attribute(GVirConfigObject *object,
Packit a07778
                                            const char *child_name,
Packit a07778
                                            const char *attr_name,
Packit a07778
                                            const char *attr_value)
Packit a07778
{
Packit a07778
    GVirConfigObject *child;
Packit a07778
Packit a07778
    child = gvir_config_object_add_child(object, child_name);
Packit a07778
    gvir_config_object_set_attribute(child, attr_name, attr_value, NULL);
Packit a07778
    g_object_unref(G_OBJECT(child));
Packit a07778
}
Packit a07778
Packit a07778
Packit a07778
void gvir_config_object_add_child_with_attribute_enum(GVirConfigObject *object,
Packit a07778
                                                      const char *child_name,
Packit a07778
                                                      const char *attr_name,
Packit a07778
                                                      GType attr_type,
Packit a07778
                                                      unsigned int attr_value)
Packit a07778
{
Packit a07778
    GVirConfigObject *child;
Packit a07778
Packit a07778
    child = gvir_config_object_add_child(object, child_name);
Packit a07778
    gvir_config_object_set_attribute_with_type(child, attr_name, attr_type, attr_value, NULL);
Packit a07778
    g_object_unref(G_OBJECT(child));
Packit a07778
}
Packit a07778
Packit a07778
Packit a07778
G_GNUC_INTERNAL GVirConfigObject *
Packit a07778
gvir_config_object_replace_child(GVirConfigObject *object,
Packit a07778
                                 const char *child_name)
Packit a07778
{
Packit a07778
    xmlNodePtr new_node;
Packit a07778
Packit a07778
    g_return_val_if_fail(GVIR_CONFIG_IS_OBJECT(object), NULL);
Packit a07778
    g_return_val_if_fail(child_name != NULL, NULL);
Packit a07778
Packit a07778
    new_node = xmlNewDocNode(NULL, NULL, (xmlChar *)child_name, NULL);
Packit a07778
    gvir_config_object_set_child_internal(object, new_node, TRUE);
Packit a07778
Packit a07778
    return GVIR_CONFIG_OBJECT(g_object_new(GVIR_CONFIG_TYPE_OBJECT,
Packit a07778
                                           "doc", object->priv->doc,
Packit a07778
                                           "node", new_node,
Packit a07778
                                           NULL));
Packit a07778
}
Packit a07778
Packit a07778
G_GNUC_INTERNAL void
Packit a07778
gvir_config_object_replace_child_with_attribute(GVirConfigObject *object,
Packit a07778
                                                const char *child_name,
Packit a07778
                                                const char *attr_name,
Packit a07778
                                                const char *attr_value)
Packit a07778
{
Packit a07778
    GVirConfigObject *child;
Packit a07778
Packit a07778
    child = gvir_config_object_replace_child(object, child_name);
Packit a07778
    gvir_config_object_set_attribute(child, attr_name, attr_value, NULL);
Packit a07778
    g_object_unref(G_OBJECT(child));
Packit a07778
}
Packit a07778
Packit a07778
G_GNUC_INTERNAL void
Packit a07778
gvir_config_object_replace_child_with_attribute_enum(GVirConfigObject *object,
Packit a07778
                                                     const char *child_name,
Packit a07778
                                                     const char *attr_name,
Packit a07778
                                                     GType attr_type,
Packit a07778
                                                     unsigned int attr_value)
Packit a07778
{
Packit a07778
    GVirConfigObject *child;
Packit a07778
Packit a07778
    child = gvir_config_object_replace_child(object, child_name);
Packit a07778
    gvir_config_object_set_attribute_with_type(child, attr_name, attr_type, attr_value, NULL);
Packit a07778
    g_object_unref(G_OBJECT(child));
Packit a07778
}
Packit a07778
Packit a07778
struct NodeMatch {
Packit a07778
    const char *name;
Packit a07778
    const char *ns;
Packit a07778
};
Packit a07778
Packit a07778
static gboolean maybe_unlink_node(xmlNodePtr node, void *opaque)
Packit a07778
{
Packit a07778
    gboolean dounlink = TRUE;
Packit a07778
    struct NodeMatch *match = (struct NodeMatch *)opaque;
Packit a07778
Packit a07778
    if (match->ns != NULL) {
Packit a07778
        dounlink = dounlink && (g_strcmp0(match->ns, (char *)node->ns->href) == 0);
Packit a07778
    }
Packit a07778
Packit a07778
    if (match->name != NULL) {
Packit a07778
        dounlink = dounlink && (g_strcmp0(match->name, (char *)node->name) == 0);
Packit a07778
    }
Packit a07778
    if (dounlink) {
Packit a07778
        xmlUnlinkNode(node);
Packit a07778
        xmlFreeNode(node);
Packit a07778
    }
Packit a07778
Packit a07778
    return dounlink;
Packit a07778
}
Packit a07778
Packit a07778
static gboolean remove_oneshot(xmlNodePtr node, gpointer opaque)
Packit a07778
{
Packit a07778
    return !maybe_unlink_node(node, opaque);
Packit a07778
}
Packit a07778
Packit a07778
G_GNUC_INTERNAL void
Packit a07778
gvir_config_object_delete_child(GVirConfigObject *object,
Packit a07778
                                const char *child_name,
Packit a07778
                                const char *ns_href)
Packit a07778
{
Packit a07778
    struct NodeMatch match;
Packit a07778
Packit a07778
    g_return_if_fail(GVIR_CONFIG_IS_OBJECT(object));
Packit a07778
Packit a07778
    match.name = child_name;
Packit a07778
    match.ns = ns_href;
Packit a07778
    gvir_config_object_foreach_child(object, NULL, remove_oneshot, &match);
Packit a07778
}
Packit a07778
Packit a07778
static gboolean remove_always(xmlNodePtr node, gpointer opaque)
Packit a07778
{
Packit a07778
    maybe_unlink_node(node, opaque);
Packit a07778
Packit a07778
    return TRUE;
Packit a07778
}
Packit a07778
Packit a07778
G_GNUC_INTERNAL void
Packit a07778
gvir_config_object_delete_children(GVirConfigObject *object,
Packit a07778
                                   const char *child_name,
Packit a07778
                                   const char *ns_href)
Packit a07778
{
Packit a07778
    struct NodeMatch match;
Packit a07778
Packit a07778
    g_return_if_fail(GVIR_CONFIG_IS_OBJECT(object));
Packit a07778
Packit a07778
    match.name = child_name;
Packit a07778
    match.ns = ns_href;
Packit a07778
Packit a07778
    gvir_config_object_foreach_child(object, NULL, remove_always, &match);
Packit a07778
}
Packit a07778
Packit a07778
G_GNUC_INTERNAL void
Packit a07778
gvir_config_object_set_node_content(GVirConfigObject *object,
Packit a07778
                                    const char *node_name,
Packit a07778
                                    const char *value)
Packit a07778
{
Packit a07778
    xmlChar *encoded_data;
Packit a07778
    GVirConfigObject *node;
Packit a07778
Packit a07778
    g_return_if_fail(GVIR_CONFIG_IS_OBJECT(object));
Packit a07778
Packit a07778
    if (value == NULL) {
Packit a07778
        gvir_config_object_delete_child(object, node_name, NULL);
Packit a07778
Packit a07778
        return;
Packit a07778
    }
Packit a07778
Packit a07778
    if (node_name != NULL) {
Packit a07778
        node = gvir_config_object_replace_child(object, node_name);
Packit a07778
        g_return_if_fail(node != NULL);
Packit a07778
    } else {
Packit a07778
        node = g_object_ref(object);
Packit a07778
    }
Packit a07778
    encoded_data = xmlEncodeEntitiesReentrant(node->priv->node->doc,
Packit a07778
                                              (xmlChar *)value);
Packit a07778
    xmlNodeSetContent(node->priv->node, encoded_data);
Packit a07778
    xmlFree(encoded_data);
Packit a07778
    g_object_unref(G_OBJECT(node));
Packit a07778
}
Packit a07778
Packit a07778
G_GNUC_INTERNAL void
Packit a07778
gvir_config_object_set_node_content_uint64(GVirConfigObject *object,
Packit a07778
                                           const char *node_name,
Packit a07778
                                           guint64 value)
Packit a07778
{
Packit a07778
    char *str;
Packit a07778
Packit a07778
    g_return_if_fail(GVIR_CONFIG_IS_OBJECT(object));
Packit a07778
Packit a07778
    str = g_strdup_printf("%"G_GUINT64_FORMAT, value);
Packit a07778
    gvir_config_object_set_node_content(object, node_name, str);
Packit a07778
    g_free(str);
Packit a07778
}
Packit a07778
Packit a07778
/* FIXME: how to notify of errors/node not found? */
Packit a07778
G_GNUC_INTERNAL guint64
Packit a07778
gvir_config_object_get_node_content_uint64(GVirConfigObject *object,
Packit a07778
                                           const char *node_name)
Packit a07778
{
Packit a07778
    xmlNodePtr node;
Packit a07778
    const char *str;
Packit a07778
    guint64 value;
Packit a07778
Packit a07778
    node = gvir_config_object_get_xml_node(GVIR_CONFIG_OBJECT(object));
Packit a07778
    if (node == NULL)
Packit a07778
        return 0;
Packit a07778
Packit a07778
    str = gvir_config_xml_get_child_element_content(node, node_name);
Packit a07778
    if (!str)
Packit a07778
        return 0;
Packit a07778
Packit a07778
    value = g_ascii_strtoull(str, NULL, 0);
Packit a07778
Packit a07778
    return value;
Packit a07778
}
Packit a07778
Packit a07778
G_GNUC_INTERNAL gint
Packit a07778
gvir_config_object_get_node_content_genum(GVirConfigObject *object,
Packit a07778
                                          const char *node_name,
Packit a07778
                                          GType enum_type,
Packit a07778
                                          gint default_value)
Packit a07778
{
Packit a07778
    xmlNodePtr node;
Packit a07778
    const char *str;
Packit a07778
    gint value;
Packit a07778
Packit a07778
    node = gvir_config_object_get_xml_node(GVIR_CONFIG_OBJECT(object));
Packit a07778
    if (node == NULL)
Packit a07778
        return default_value;
Packit a07778
Packit a07778
    str = gvir_config_xml_get_child_element_content(node, node_name);
Packit a07778
    if (!str)
Packit a07778
        return default_value;
Packit a07778
Packit a07778
    value = gvir_config_genum_get_value(enum_type, str, default_value);
Packit a07778
Packit a07778
    return value;
Packit a07778
}
Packit a07778
Packit a07778
G_GNUC_INTERNAL gint
Packit a07778
gvir_config_object_get_attribute_genum(GVirConfigObject *object,
Packit a07778
                                       const char *node_name,
Packit a07778
                                       const char *attr_name,
Packit a07778
                                       GType enum_type,
Packit a07778
                                       gint default_value)
Packit a07778
{
Packit a07778
    xmlNodePtr node;
Packit a07778
    const char *attr_val;
Packit a07778
    gint value;
Packit a07778
Packit a07778
    g_return_val_if_fail(attr_name != NULL, default_value);
Packit a07778
Packit a07778
    node = gvir_config_object_get_xml_node(GVIR_CONFIG_OBJECT(object));
Packit a07778
    if (node == NULL)
Packit a07778
        return default_value;
Packit a07778
Packit a07778
    if (node_name != NULL) {
Packit a07778
        node = gvir_config_xml_get_element(node, node_name, NULL);
Packit a07778
        if (node == NULL)
Packit a07778
            return default_value;
Packit a07778
    }
Packit a07778
Packit a07778
    attr_val = gvir_config_xml_get_attribute_content(node, attr_name);
Packit a07778
    if (attr_val == NULL)
Packit a07778
        return default_value;
Packit a07778
Packit a07778
    value = gvir_config_genum_get_value(enum_type, attr_val,
Packit a07778
                                        default_value);
Packit a07778
Packit a07778
    return value;
Packit a07778
}
Packit a07778
Packit a07778
G_GNUC_INTERNAL guint64
Packit a07778
gvir_config_object_get_attribute_uint64(GVirConfigObject *object,
Packit a07778
                                        const char *node_name,
Packit a07778
                                        const char *attr_name,
Packit a07778
                                        guint64 default_value)
Packit a07778
{
Packit a07778
    const char *str;
Packit a07778
Packit a07778
    str = gvir_config_object_get_attribute(object, node_name, attr_name);
Packit a07778
    if (str == NULL)
Packit a07778
        return default_value;
Packit a07778
Packit a07778
    return g_ascii_strtoull(str, NULL, 0);
Packit a07778
}
Packit a07778
Packit a07778
Packit a07778
G_GNUC_INTERNAL gboolean
Packit a07778
gvir_config_object_get_attribute_boolean(GVirConfigObject *object,
Packit a07778
                                         const char *node_name,
Packit a07778
                                         const char *attr_name,
Packit a07778
                                         gboolean default_value)
Packit a07778
{
Packit a07778
    const char *str;
Packit a07778
Packit a07778
    str = gvir_config_object_get_attribute(object, node_name, attr_name);
Packit a07778
    if (g_strcmp0(str, "yes") == 0) {
Packit a07778
        return TRUE;
Packit a07778
    } else if (g_strcmp0(str, "no") == 0) {
Packit a07778
        return FALSE;
Packit a07778
    } else {
Packit a07778
        return default_value;
Packit a07778
    }
Packit a07778
}
Packit a07778
Packit a07778
Packit a07778
GVirConfigObject *gvir_config_object_new_from_xml(GType type,
Packit a07778
                                                  const char *root_name,
Packit a07778
                                                  const char *schema,
Packit a07778
                                                  const gchar *xml,
Packit a07778
                                                  GError **error)
Packit a07778
{
Packit a07778
    GVirConfigObject *object;
Packit a07778
    GVirConfigXmlDoc *doc;
Packit a07778
    xmlNodePtr node;
Packit a07778
    GError *tmp_error = NULL;
Packit a07778
Packit a07778
    node = gvir_config_xml_parse(xml, root_name, &tmp_error);
Packit a07778
    if (tmp_error != NULL) {
Packit a07778
        g_propagate_error(error, tmp_error);
Packit a07778
        return NULL;
Packit a07778
    }
Packit a07778
    doc = gvir_config_xml_doc_new(node->doc);
Packit a07778
    object = GVIR_CONFIG_OBJECT(g_object_new(type,
Packit a07778
                                             "doc", doc,
Packit a07778
                                             "node", node,
Packit a07778
                                             "schema", schema,
Packit a07778
                                             NULL));
Packit a07778
    g_object_unref(G_OBJECT(doc));
Packit a07778
Packit a07778
    return object;
Packit a07778
}
Packit a07778
Packit a07778
G_GNUC_INTERNAL GVirConfigObject *
Packit a07778
gvir_config_object_new_from_tree(GType type, GVirConfigXmlDoc *doc,
Packit a07778
                                 const char *schema, xmlNodePtr tree)
Packit a07778
{
Packit a07778
    g_return_val_if_fail(g_type_is_a(type, GVIR_CONFIG_TYPE_OBJECT), NULL);
Packit a07778
    g_return_val_if_fail(GVIR_CONFIG_IS_XML_DOC(doc), NULL);
Packit a07778
    g_return_val_if_fail(tree != NULL, NULL);
Packit a07778
Packit a07778
    return GVIR_CONFIG_OBJECT(g_object_new(type,
Packit a07778
                                           "doc", doc,
Packit a07778
                                           "node", tree,
Packit a07778
                                           "schema", schema,
Packit a07778
                                           NULL));
Packit a07778
}
Packit a07778
Packit a07778
GVirConfigObject *gvir_config_object_new(GType type,
Packit a07778
                                         const char *root_name,
Packit a07778
                                         const char *schema)
Packit a07778
{
Packit a07778
    GVirConfigObject *object;
Packit a07778
    GVirConfigXmlDoc *doc;
Packit a07778
    xmlDocPtr xml_doc;
Packit a07778
    xmlNodePtr node;
Packit a07778
Packit a07778
    doc = gvir_config_xml_doc_new(NULL);
Packit a07778
    g_object_get(G_OBJECT(doc), "doc", &xml_doc, NULL);
Packit a07778
    g_assert(xml_doc != NULL);
Packit a07778
    node = xmlNewDocNode(xml_doc, NULL, (xmlChar *)root_name, NULL);
Packit a07778
    xmlDocSetRootElement(xml_doc, node);
Packit a07778
    object = GVIR_CONFIG_OBJECT(g_object_new(type,
Packit a07778
                                             "doc", doc,
Packit a07778
                                             "node", node,
Packit a07778
                                             "schema", schema,
Packit a07778
                                             NULL));
Packit a07778
Packit a07778
    g_object_unref(G_OBJECT(doc));
Packit a07778
Packit a07778
    return object;
Packit a07778
}
Packit a07778
Packit a07778
G_GNUC_INTERNAL void
Packit a07778
gvir_config_object_set_attribute(GVirConfigObject *object, ...)
Packit a07778
{
Packit a07778
    xmlDocPtr doc;
Packit a07778
    va_list args;
Packit a07778
Packit a07778
    g_return_if_fail(GVIR_CONFIG_IS_OBJECT(object));
Packit a07778
Packit a07778
    g_object_get(G_OBJECT(object->priv->doc), "doc", &doc, NULL);
Packit a07778
    va_start(args, object);
Packit a07778
    while (TRUE) {
Packit a07778
        const char *name;
Packit a07778
        const char *value;
Packit a07778
Packit a07778
        name = va_arg(args, const char *);
Packit a07778
        if (name == NULL) {
Packit a07778
            break;
Packit a07778
        }
Packit a07778
        gvir_config_object_remove_attribute(object, name);
Packit a07778
        value = va_arg(args, const char *);
Packit a07778
        if (value == NULL) {
Packit a07778
            g_warn_if_reached();
Packit a07778
            break;
Packit a07778
        }
Packit a07778
        xmlNewProp(object->priv->node, (xmlChar *)name, (xmlChar *)value);
Packit a07778
    }
Packit a07778
    va_end(args);
Packit a07778
}
Packit a07778
Packit a07778
G_GNUC_INTERNAL void
Packit a07778
gvir_config_object_set_attribute_with_type(GVirConfigObject *object, ...)
Packit a07778
{
Packit a07778
    va_list args;
Packit a07778
Packit a07778
    g_return_if_fail(GVIR_CONFIG_IS_OBJECT(object));
Packit a07778
Packit a07778
    va_start(args, object);
Packit a07778
    while (TRUE) {
Packit a07778
        const char *name;
Packit a07778
        GType attr_type;
Packit a07778
        char *str;
Packit a07778
Packit a07778
Packit a07778
        name = va_arg(args, const char *);
Packit a07778
        if (name == NULL) {
Packit a07778
            break;
Packit a07778
        }
Packit a07778
        gvir_config_object_remove_attribute(object, name);
Packit a07778
Packit a07778
        attr_type = va_arg(args, GType);
Packit a07778
        if (G_TYPE_IS_ENUM(attr_type)) {
Packit a07778
            int val;
Packit a07778
            const char *enum_str;
Packit a07778
            val = va_arg(args, int);
Packit a07778
            enum_str = gvir_config_genum_get_nick(attr_type, val);
Packit a07778
            if (enum_str != NULL) {
Packit a07778
                str = g_strdup(enum_str);
Packit a07778
            } else {
Packit a07778
                str = NULL;
Packit a07778
            }
Packit a07778
        } else switch (attr_type) {
Packit a07778
            case G_TYPE_UINT64: {
Packit a07778
                guint64 val;
Packit a07778
                val = va_arg(args, guint64);
Packit a07778
                str = g_strdup_printf("%"G_GUINT64_FORMAT, val);
Packit a07778
                break;
Packit a07778
            }
Packit a07778
            case G_TYPE_UINT: {
Packit a07778
                guint val;
Packit a07778
                val = va_arg(args, guint);
Packit a07778
                str = g_strdup_printf("%u", val);
Packit a07778
                break;
Packit a07778
            }
Packit a07778
            case G_TYPE_INT: {
Packit a07778
                gint val;
Packit a07778
                val = va_arg(args, gint);
Packit a07778
                str = g_strdup_printf("%d", val);
Packit a07778
                break;
Packit a07778
            }
Packit a07778
            case G_TYPE_STRING:
Packit a07778
                str = va_arg(args, char *);
Packit a07778
                xmlNewProp(object->priv->node, (xmlChar *)name, (xmlChar *)str);
Packit a07778
                str = NULL;
Packit a07778
                break;
Packit a07778
            case G_TYPE_BOOLEAN: {
Packit a07778
                gboolean val;
Packit a07778
                val = va_arg(args, gboolean);
Packit a07778
                str = g_strdup_printf("%s", val?"yes":"no");
Packit a07778
                break;
Packit a07778
            }
Packit a07778
            default:
Packit a07778
                g_warning("Unhandled type: %s", g_type_name(attr_type));
Packit a07778
                g_assert_not_reached();
Packit a07778
        }
Packit a07778
Packit a07778
        if (str != NULL) {
Packit a07778
            xmlNewProp(object->priv->node, (xmlChar *)name, (xmlChar *)str);
Packit a07778
            g_free(str);
Packit a07778
        }
Packit a07778
    }
Packit a07778
    va_end(args);
Packit a07778
}
Packit a07778
Packit a07778
static void
Packit a07778
gvir_config_object_attach(GVirConfigObject *parent, GVirConfigObject *child, gboolean replace)
Packit a07778
{
Packit a07778
    g_return_if_fail(GVIR_CONFIG_IS_OBJECT(parent));
Packit a07778
    g_return_if_fail(GVIR_CONFIG_IS_OBJECT(child));
Packit a07778
Packit a07778
    if (replace) {
Packit a07778
        gvir_config_object_delete_children(parent,
Packit a07778
                                           (char *)child->priv->node->name,
Packit a07778
                                           NULL);
Packit a07778
    }
Packit a07778
    xmlUnlinkNode(child->priv->node);
Packit a07778
    xmlAddChild(parent->priv->node, child->priv->node);
Packit a07778
    if (child->priv->doc != NULL) {
Packit a07778
        g_object_unref(G_OBJECT(child->priv->doc));
Packit a07778
        child->priv->doc = NULL;
Packit a07778
    }
Packit a07778
    if (parent->priv->doc != NULL) {
Packit a07778
        child->priv->doc = g_object_ref(parent->priv->doc);
Packit a07778
    }
Packit a07778
}
Packit a07778
Packit a07778
G_GNUC_INTERNAL void
Packit a07778
gvir_config_object_attach_replace(GVirConfigObject *parent,
Packit a07778
                                  const char *child_name,
Packit a07778
                                  GVirConfigObject *child)
Packit a07778
{
Packit a07778
    g_return_if_fail(child_name != NULL);
Packit a07778
Packit a07778
    if (child == NULL)
Packit a07778
        gvir_config_object_delete_children(parent, child_name, NULL);
Packit a07778
    else
Packit a07778
        gvir_config_object_attach(parent, child, TRUE);
Packit a07778
}
Packit a07778
Packit a07778
G_GNUC_INTERNAL void
Packit a07778
gvir_config_object_attach_add(GVirConfigObject *parent, GVirConfigObject *child)
Packit a07778
{
Packit a07778
    gvir_config_object_attach(parent, child, FALSE);
Packit a07778
}
Packit a07778
Packit a07778
G_GNUC_INTERNAL void
Packit a07778
gvir_config_object_remove_attribute(GVirConfigObject *object,
Packit a07778
                                    const char *attr_name)
Packit a07778
{
Packit a07778
    int status;
Packit a07778
Packit a07778
    do {
Packit a07778
        status = xmlUnsetProp(object->priv->node, (xmlChar *)attr_name);
Packit a07778
    } while (status == 0);
Packit a07778
}
Packit a07778
Packit a07778
static gboolean
Packit a07778
gvir_config_object_set_xmlnode_namespace(xmlNodePtr node, const char *ns,
Packit a07778
                                         const char *ns_uri)
Packit a07778
{
Packit a07778
    xmlNsPtr namespace;
Packit a07778
Packit a07778
    namespace = xmlNewNs(node, (xmlChar *)ns_uri, (xmlChar *)ns);
Packit a07778
    if (namespace == NULL)
Packit a07778
        return FALSE;
Packit a07778
Packit a07778
    xmlSetNs(node, namespace);
Packit a07778
    return TRUE;
Packit a07778
}
Packit a07778
Packit a07778
static gboolean
Packit a07778
gvir_config_object_set_namespace_recursively(xmlNodePtr node,
Packit a07778
                                             const char *ns,
Packit a07778
                                             const char *ns_uri)
Packit a07778
{
Packit a07778
    xmlNodePtr n;
Packit a07778
Packit a07778
    for (n = node; n != NULL; n = n->next) {
Packit a07778
        if (n->type == XML_ELEMENT_NODE) {
Packit a07778
            if (!gvir_config_object_set_xmlnode_namespace(n, ns, ns_uri))
Packit a07778
                return FALSE;
Packit a07778
        }
Packit a07778
Packit a07778
        if (!gvir_config_object_set_namespace_recursively(n->children, ns, NULL))
Packit a07778
            return FALSE;
Packit a07778
    }
Packit a07778
Packit a07778
    return TRUE;
Packit a07778
}
Packit a07778
Packit a07778
G_GNUC_INTERNAL gboolean
Packit a07778
gvir_config_object_set_namespace(GVirConfigObject *object, const char *ns,
Packit a07778
                                 const char *ns_uri, gboolean ns_children)
Packit a07778
{
Packit a07778
    g_return_val_if_fail(GVIR_CONFIG_IS_OBJECT(object), FALSE);
Packit a07778
    g_return_val_if_fail(ns != NULL, FALSE);
Packit a07778
    g_return_val_if_fail(ns_uri != NULL, FALSE);
Packit a07778
Packit a07778
    if (!ns_children) {
Packit a07778
        return gvir_config_object_set_xmlnode_namespace(object->priv->node,
Packit a07778
                                                        ns, ns_uri);
Packit a07778
    }
Packit a07778
Packit a07778
    return gvir_config_object_set_namespace_recursively(object->priv->node,
Packit a07778
                                                        ns, ns_uri);
Packit a07778
}
Packit a07778
Packit a07778
G_GNUC_INTERNAL GVirConfigObject *
Packit a07778
gvir_config_object_get_child_with_type(GVirConfigObject *object,
Packit a07778
                                       const gchar *child_name,
Packit a07778
                                       GType child_type)
Packit a07778
{
Packit a07778
    xmlNodePtr node;
Packit a07778
Packit a07778
    g_return_val_if_fail(GVIR_CONFIG_IS_OBJECT(object), NULL);
Packit a07778
    g_return_val_if_fail(child_name != NULL, NULL);
Packit a07778
Packit a07778
    node = gvir_config_xml_get_element(object->priv->node, child_name, NULL);
Packit a07778
    if (node == NULL)
Packit a07778
        return NULL;
Packit a07778
Packit a07778
    return gvir_config_object_new_from_tree(child_type,
Packit a07778
                                            object->priv->doc,
Packit a07778
                                            object->priv->schema,
Packit a07778
                                            node);
Packit a07778
}
Packit a07778
Packit a07778
G_GNUC_INTERNAL GVirConfigObject *
Packit a07778
gvir_config_object_get_child(GVirConfigObject *object,
Packit a07778
                             const gchar *child_name)
Packit a07778
{
Packit a07778
    return gvir_config_object_get_child_with_type(object,
Packit a07778
                                                  child_name,
Packit a07778
                                                  GVIR_CONFIG_TYPE_OBJECT);
Packit a07778
}
Packit a07778
Packit a07778
G_GNUC_INTERNAL gboolean
Packit a07778
gvir_config_object_has_child(GVirConfigObject *object, const gchar *child_name)
Packit a07778
{
Packit a07778
    xmlNodePtr node;
Packit a07778
Packit a07778
    g_return_val_if_fail(GVIR_CONFIG_IS_OBJECT(object), FALSE);
Packit a07778
    g_return_val_if_fail(child_name != NULL, FALSE);
Packit a07778
Packit a07778
    node = gvir_config_xml_get_element(object->priv->node, child_name, NULL);
Packit a07778
Packit a07778
    return (node != NULL);
Packit a07778
}