[Libvirt-cim] [PATCH 2 of 3] [RFC][CU] Add EI CIMXML parser

Dan Smith danms at us.ibm.com
Fri Feb 8 23:18:00 UTC 2008


# HG changeset patch
# User Dan Smith <danms at us.ibm.com>
# Date 1202512655 28800
# Node ID f6559a2f55abab85baeabd56faaf7804c3ea30f3
# Parent  03126c9af41607dcaa8b197736dd5059c108261a
[RFC][CU] Add EI CIMXML parser

This handles strings, bools, integers, and arrays of those.  It doesn't yet
handle nested objects, as we will need for RASD.HostResource[].  I need
to do some further investigation of what the XML for that will look like.

I have tested this by taking an existing XML for DefineSystem() and
changing the MemResourceAllocationSettingData field to this:

    <INSTANCE CLASSNAME="Xen_MemResourceAllocationSettingData">
    <PROPERTY NAME="CreationClassName" TYPE="string">
      <VALUE>Xen_MemResourceAllocationSettingData</VALUE>
    </PROPERTY>
    <PROPERTY NAME="InstanceID" TYPE="string">
      <VALUE>test/mem</VALUE>
    </PROPERTY>
    <PROPERTY NAME="ResourceType" TYPE="uint16">
       <VALUE>4</VALUE>
    </PROPERTY>
    <PROPERTY NAME="VirtualQuantity" TYPE="uint64">
       <VALUE>256 </VALUE>
    </PROPERTY>
    <PROPERTY.ARRAY NAME="Foo" TYPE="string">
      <VALUE.ARRAY>
        <VALUE>Bar</VALUE>
        <VALUE>Baz</VALUE>
      </VALUE.ARRAY>
    </PROPERTY.ARRAY>
  </INSTANCE>

(The Foo[] parameter in there is just for testing :)

Signed-off-by: Dan Smith <danms at us.ibm.com>

diff -r 03126c9af416 -r f6559a2f55ab Makefile.am
--- a/Makefile.am	Fri Feb 08 15:17:30 2008 -0800
+++ b/Makefile.am	Fri Feb 08 15:17:35 2008 -0800
@@ -10,6 +10,8 @@ pkgconfig_DATA = libcmpiutil.pc
 
 libcmpiutilincdir = $(includedir)/libcmpiutil
 
+noinst_HEADERS = eo_parser_xml.h
+
 libcmpiutilinc_HEADERS = libcmpiutil.h \
                   std_invokemethod.h \
                   std_association.h \
@@ -18,7 +20,7 @@ libcmpiutilinc_HEADERS = libcmpiutil.h \
 
 libcmpiutil_la_SOURCES = args_util.c instance_util.c std_invokemethod.c \
                          std_association.c inst_list.c std_indication.c \
-                         debug_util.c
+                         debug_util.c eo_parser_xml.c
 libcmpiutil_la_CFLAGS = $(CFLAGS) $(CFLAGS_STRICT)
 libcmpiutil_la_LIBADD =
 libcmpiutil_la_DEPENDENCIES =
diff -r 03126c9af416 -r f6559a2f55ab eo_parser_xml.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eo_parser_xml.c	Fri Feb 08 15:17:35 2008 -0800
@@ -0,0 +1,482 @@
+/*
+ * Copyright IBM Corp. 2007
+ *
+ * Authors:
+ *  Dan Smith <danms at us.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ */
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+#include <cmpidt.h>
+#include <cmpift.h>
+#include <cmpimacs.h>
+
+#include "libcmpiutil.h"
+
+#include "eo_parser_xml.h"
+
+static char *get_attr(xmlNode *node, const char *name)
+{
+        return (char *)xmlGetProp(node, (xmlChar *)name);
+}
+
+static char *get_content(xmlNode *node)
+{
+        return (char *)xmlNodeGetContent(node);
+}
+
+static CMPIType parse_string_property(const CMPIBroker *broker,
+                                      const char *string,
+                                      const char *type,
+                                      CMPIValue *val)
+{
+        CMPIString *str;
+        CMPIStatus s;
+
+        str = CMNewString(broker, string, &s);
+        if ((str == NULL) || (s.rc != CMPI_RC_OK))
+                return CMPI_null;
+
+        val->string = str;
+        return CMPI_string;
+}
+
+static CMPIType parse_bool_property(const char *string,
+                                    const char *type,
+                                    CMPIValue *val)
+{
+        val->boolean = STREQC(string, "true");
+
+        return CMPI_boolean;
+}
+
+static CMPIType parse_int_property(const char *string,
+                                   const char *type,
+                                   CMPIValue *val)
+{
+        int size;
+        bool sign;
+        CMPIType t;
+        int ret;
+
+        if (sscanf(type, "uint%i", &size) == 1)
+                sign = false;
+        else if (sscanf(type, "int%i", &size) == 1)
+                sign = true;
+        else {
+                printf("Unknown integer type: `%s'", type);
+                return 0;
+        }
+
+        if (sign) {
+                int64_t _val;
+                ret = sscanf(string, "%" SCNi64, &_val);
+                val->sint64 = _val;
+        } else {
+                uint64_t _val;
+                ret = sscanf(string, "%" SCNu64, &_val);
+                val->uint64 = _val;
+        }
+
+        if (ret != 1) {
+                printf("Failed to scan value `%s'\n", string);
+                return 0;
+        }
+
+        switch (size) {
+        case 8:  t = sign ? CMPI_sint8  : CMPI_uint8;  break;
+        case 16: t = sign ? CMPI_sint16 : CMPI_uint16; break;
+        case 32: t = sign ? CMPI_sint32 : CMPI_uint32; break;
+        default:
+        case 64: t = sign ? CMPI_sint64 : CMPI_uint64; break;
+        };
+
+        return t;
+}
+
+static CMPIType get_property_value(const CMPIBroker *broker,
+                                   const char *tstr,
+                                   const char *content,
+                                   CMPIValue *value)
+{
+        CMPIType type = CMPI_null;
+
+        if (STREQC(tstr, "string"))
+                type = parse_string_property(broker, content, tstr, value);
+        else if (STREQC(tstr, "boolean"))
+                type = parse_bool_property(content, tstr, value);
+        else if (strstr(tstr, "int"))
+                type = parse_int_property(content, tstr, value);
+        else {
+                printf("Unhandled type: %s\n", tstr);
+                goto out;
+        }
+
+        if (type == CMPI_null) {
+                printf("Unable to parse type %s\n", tstr);
+                goto out;
+        }
+
+ out:
+        return type;
+}
+
+static CMPIType get_node_value(const CMPIBroker *broker,
+                               xmlNode *node,
+                               const char *tstr,
+                               CMPIValue *val)
+{
+        CMPIType type = CMPI_null;
+        char *content = NULL;
+
+        if (node->type != XML_ELEMENT_NODE) {
+                CU_DEBUG("Non-element node: %s", node->name);
+                goto out;
+        }
+
+        if (!STREQC((char *)node->name, "value")) {
+                CU_DEBUG("Expected <VALUE> but got <%s>", node->name);
+                goto out;
+        }
+
+        content = get_content(node);
+        CU_DEBUG("Node content: %s", content);
+        type = get_property_value(broker, tstr, content, val);
+        free(content);
+ out:
+        return type;
+}
+
+static CMPIType parse_array(const CMPIBroker *broker,
+                            const char *tstr,
+                            xmlNode *root,
+                            CMPIArray **array)
+{
+        xmlNode *value;
+        CMPIValue *list = NULL;
+        int size = 0;
+        int cur = 0;
+        CMPIStatus s;
+        CMPIType type = CMPI_null;
+        int i;
+
+        for (value = root->children; value; value = value->next) {
+
+                if (value->type != XML_ELEMENT_NODE)
+                        continue;
+
+                if (cur == size) {
+                        CMPIValue *tmp;
+
+                        size += 4;
+                        tmp = realloc(list, sizeof(CMPIValue) * size);
+                        if (tmp == NULL) {
+                                CU_DEBUG("Failed to alloc %i",
+                                         sizeof(CMPIValue) * size);
+                                goto out;
+                        }
+
+                        list = tmp;
+                }
+
+                type = get_node_value(broker, value, tstr, &list[cur]);
+                if (type == CMPI_null) {
+                        CU_DEBUG("Got nothing from child");
+                } else {
+                        CU_DEBUG("Array value type %i", type);
+                        cur++;
+                }
+        }
+
+        if (cur == 0)
+                return CMPI_null;
+
+        *array = CMNewArray(broker, cur, type, &s);
+        if ((*array == NULL) || (s.rc != CMPI_RC_OK)) {
+                CU_DEBUG("Failed to alloc CMPIArray of %i", cur);
+                goto out;
+        }
+
+        for (i = 0; i < cur; i++)
+                CMSetArrayElementAt((*array), i, &list[i], type);
+
+ out:
+        free(list);
+
+        return type;
+}
+
+static bool parse_array_property(const CMPIBroker *broker,
+                                 xmlNode *node,
+                                 CMPIInstance *inst)
+{
+        char *name = NULL;
+        char *tstr = NULL;
+        bool ret = false;
+        xmlNode *val_arr;
+        CMPIArray *array;
+        CMPIType type;
+
+        name = get_attr(node, "NAME");
+        if (name == NULL) {
+                printf("Unnamed property\n");
+                goto out;
+        }
+
+        tstr = get_attr(node, "TYPE");
+        if (tstr == NULL) {
+                printf("No type\n");
+                goto out;
+        }
+
+        printf("Array property `%s' of type `%s'\n", name, tstr);
+
+        for (val_arr = node->children; val_arr; val_arr = val_arr->next) {
+                if (val_arr->type != XML_ELEMENT_NODE)
+                        continue;
+
+                if (!STREQC((char *)val_arr->name, "value.array")) {
+                        printf("Expected <value.array> but got <%s>",
+                               val_arr->name);
+                        goto out;
+                }
+
+                break;
+        }
+
+        type = parse_array(broker, tstr, val_arr, &array);
+        if (type != CMPI_null) {
+                CU_DEBUG("Setting array property");
+                CMSetProperty(inst, name, &array, (CMPI_ARRAY | type));
+        }
+
+ out:
+        free(name);
+        free(tstr);
+
+        return ret;
+}
+
+static bool parse_property(const CMPIBroker *broker,
+                           xmlNode *node,
+                           CMPIInstance *inst)
+{
+        char *name = NULL;
+        char *tstr = NULL;
+        CMPIValue value;
+        CMPIType type = CMPI_null;
+        xmlNode *ptr;
+
+        name = get_attr(node, "NAME");
+        if (name == NULL) {
+                printf("Unnamed property\n");
+                goto out;
+        }
+
+        tstr = get_attr(node, "TYPE");
+        if (tstr == NULL) {
+                printf("No type\n");
+                goto out;
+        }
+
+        CU_DEBUG("Property %s: %s", name, tstr);
+
+        for (ptr = node->children; ptr; ptr = ptr->next) {
+                type = get_node_value(broker, ptr, tstr, &value);
+                if (type != CMPI_null) {
+                        CMSetProperty(inst, name, &value, type);
+                        break;
+                }
+        }
+ out:
+        free(name);
+        free(tstr);
+
+        return type != CMPI_null;
+}
+
+static CMPIStatus parse_instance(const CMPIBroker *broker,
+                                 const char *ns,
+                                 xmlNode *root,
+                                 CMPIInstance **inst)
+{
+        char *class = NULL;
+        xmlNode *child;
+        CMPIStatus s;
+        CMPIObjectPath *op;
+
+        if (root->type != XML_ELEMENT_NODE) {
+                printf("First node is not <INSTANCE>\n");
+                goto out;
+        }
+
+        if (!STREQC((char *)root->name, "instance")) {
+                printf("Got node %s, expecting INSTANCE\n", root->name);
+                goto out;
+        }
+
+        class = get_attr(root, "CLASSNAME");
+        if (class == NULL) {
+                printf("No Classname\n");
+                goto out;
+        }
+
+        CU_DEBUG("Instance of %s", class);
+
+        op = CMNewObjectPath(broker, ns, class, &s);
+        if ((op == NULL) || (s.rc != CMPI_RC_OK)) {
+                CU_DEBUG("Unable to create path for %s:%s", ns, class);
+                goto out;
+        }
+
+        *inst = CMNewInstance(broker, op, &s);
+        if ((*inst == NULL) || (s.rc != CMPI_RC_OK)) {
+                CU_DEBUG("Unable to create inst for %s:%s", ns, class);
+                goto out;
+        }
+
+        for (child = root->children; child; child = child->next) {
+                if (child->type == XML_ELEMENT_NODE){
+                        if (STREQC((char *)child->name, "property"))
+                                parse_property(broker, child, *inst);
+                        else if (STREQC((char *)child->name, "property.array"))
+                                parse_array_property(broker, child, *inst);
+                        else
+                                printf("Unexpected node: %s\n", child->name);
+                }
+        }
+
+ out:
+        free(class);
+
+        return s;
+}
+
+#if 0
+
+/* This isn't currently used but I think I might need it for nested
+ * instances, depending on how they look.
+ */
+
+static char *parse_esc(const char *start, char *result)
+{
+        char *delim;
+        char *escape = NULL;
+        int len = 1;
+
+        delim = strchr(start, ';');
+        if (delim == NULL)
+                goto out;
+
+        escape = strndup(start, delim - start + 1);
+        if (escape == NULL) {
+                CU_DEBUG("Memory alloc failed (%i)", delim-start);
+                return NULL;
+        }
+
+        CU_DEBUG("Escape is: %s", escape);
+
+        if (STREQC(escape, "<"))
+                *result = '<';
+        else if (STREQC(escape, ">"))
+                *result = '>';
+        else if (STREQC(escape, """))
+                *result = '\"';
+        else
+                CU_DEBUG("Unhandled escape: `%s'", escape);
+
+        len = strlen(escape);
+
+ out:
+        free(escape);
+
+        return (char *)start + len;
+}
+
+static char *xml_decode(const char *input)
+{
+        const char *iptr = input;
+        char *optr;
+        char *res = NULL;
+
+        res = malloc(strlen(input) + 1);
+        if (res == NULL)
+                return res;
+
+        optr = res;
+
+        while (iptr && (*iptr != '\0')) {
+                if (*iptr == '&') {
+                        iptr = parse_esc(iptr, optr);
+                } else {
+                        *optr = *iptr;
+                        iptr++;
+                }
+
+                optr++;
+        }
+
+        return res;
+}
+
+#endif
+
+int cu_parse_ei_xml(const CMPIBroker *broker,
+                    const char *ns,
+                    const char *xml,
+                    CMPIInstance **instance)
+{
+        xmlDoc *doc = NULL;
+        xmlNode *root = NULL;
+        int ret = 0;
+
+        doc = xmlReadMemory(xml, strlen(xml), NULL, NULL, 0);
+        if (doc == NULL) {
+                CU_DEBUG("Error reading decoded XML from memory");
+                goto out;
+        }
+
+        root = xmlDocGetRootElement(doc);
+        if (root == NULL) {
+                CU_DEBUG("Error getting root XML node");
+                goto out;
+        }
+
+        parse_instance(broker, ns, root, instance);
+
+ out:
+        xmlFreeDoc(doc);
+
+        return ret;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-set-style: "K&R"
+ * tab-width: 8
+ * c-basic-offset: 8
+ * indent-tabs-mode: nil
+ * End:
+ */
diff -r 03126c9af416 -r f6559a2f55ab eo_parser_xml.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eo_parser_xml.h	Fri Feb 08 15:17:35 2008 -0800
@@ -0,0 +1,40 @@
+/*
+ * Copyright IBM Corp. 2007
+ *
+ * Authors:
+ *  Dan Smith <danms at us.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ */
+
+#ifndef __EO_PARSER_XML_H
+#define __EO_PARSER_XML_H
+
+int cu_parse_ei_xml(const CMPIBroker *broker,
+                    const char *ns,
+                    const char *xml,
+                    CMPIInstance **instance);
+
+#endif
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-set-style: "K&R"
+ * tab-width: 8
+ * c-basic-offset: 8
+ * indent-tabs-mode: nil
+ * End:
+ */




More information about the Libvirt-cim mailing list