This introduces simple API for handling JSON data. There is
an internal data structure 'virJSONValuePtr' which stores a
arbitrary nested JSON value (number, string, array, object,
nul, etc). There are APIs for constructing/querying objects
and APIs for parsing/formatting string formatted JSON data.
This uses the YAJL library for parsing/formatting from
http://lloyd.github.com/yajl/
* src/util/json.h, src/util/json.c: Data structures and APIs
for representing JSON data, and parsing/formatting it
* configure.in: Add check for yajl library
* libvirt.spec.in: Add build requires for yajl
* src/Makefile.am: Add json.c/h
* src/libvirt_private.syms: Export JSON symbols to drivers
---
configure.in | 55 +++
libvirt.spec.in | 14 +
po/POTFILES.in | 1 +
src/Makefile.am | 8 +-
src/libvirt_private.syms | 47 ++
src/util/json.c | 1043 ++++++++++++++++++++++++++++++++++++++++++++++
src/util/json.h | 131 ++++++
7 files changed, 1296 insertions(+), 3 deletions(-)
create mode 100644 src/util/json.c
create mode 100644 src/util/json.h
diff --git a/configure.in b/configure.in
index f735bba..41f50fc 100644
--- a/configure.in
+++ b/configure.in
@@ -645,6 +645,56 @@ AC_SUBST([SASL_CFLAGS])
AC_SUBST([SASL_LIBS])
+dnl YAJL JSON library
http://lloyd.github.com/yajl/
+AC_ARG_WITH([yajl],
+ [ --with-yajl use YAJL for JSON parsing/formatting],
+ [],
+ [with_yajl=check])
+
+YAJL_CFLAGS=
+YAJL_LIBS=
+if test "x$with_yajl" != "xno"; then
+ if test "x$with_yajl" != "xyes" -a "x$with_yajl" !=
"xcheck"; then
+ YAJL_CFLAGS="-I$with_yajl/include"
+ YAJL_LIBS="-L$with_yajl/lib"
+ fi
+ fail=0
+ old_cppflags="$CPPFLAGS"
+ old_ldflags="$LDFLAGS"
+ CPPFLAGS="$CPPFLAGS $YAJL_CFLAGS"
+ LDFLAGS="$LDFLAGS $YAJL_LIBS"
+ AC_CHECK_HEADER([yajl/yajl_common.h],[],[
+ if test "x$with_yajl" != "xcheck" ; then
+ with_yajl=no
+ else
+ fail=1
+ fi])
+ if test "x$with_yajl" != "xno" ; then
+ AC_CHECK_LIB([yajl], [yajl_parse],[
+ YAJL_LIBS="$YAJL_LIBS -lyajl"
+ with_yajl=yes
+ ],[
+ if test "x$with_yajl" = "xcheck" ; then
+ with_yajl=no
+ else
+ fail=1
+ fi
+ ])
+ fi
+ test $fail = 1 &&
+ AC_MSG_ERROR([You must install the YAJL development package in order to compile
libvirt])
+ CPPFLAGS="$old_cppflags"
+ LDFLAGS="$old_ldflags"
+ if test "x$with_yajl" = "xyes" ; then
+ AC_DEFINE_UNQUOTED([HAVE_YAJL], 1,
+ [whether YAJL is available for JSON parsing/formatting])
+ fi
+fi
+AM_CONDITIONAL([HAVE_YAJL], [test "x$with_yajl" = "xyes"])
+AC_SUBST([YAJL_CFLAGS])
+AC_SUBST([YAJL_LIBS])
+
+
dnl PolicyKit library
POLKIT_CFLAGS=
POLKIT_LIBS=
@@ -1859,6 +1909,11 @@ AC_MSG_NOTICE([ sasl: $SASL_CFLAGS $SASL_LIBS])
else
AC_MSG_NOTICE([ sasl: no])
fi
+if test "$with_yajl" != "no" ; then
+AC_MSG_NOTICE([ yajl: $YAJL_CFLAGS $YAJL_LIBS])
+else
+AC_MSG_NOTICE([ yajl: no])
+fi
if test "$with_avahi" = "yes" ; then
AC_MSG_NOTICE([ avahi: $AVAHI_CFLAGS $AVAHI_LIBS])
else
diff --git a/libvirt.spec.in b/libvirt.spec.in
index dba14df..408ad05 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -60,6 +60,7 @@
%define with_netcf 0%{!?_without_netcf:0}
%define with_udev 0%{!?_without_udev:0}
%define with_hal 0%{!?_without_hal:0}
+%define with_yajl 0%{!?_without_yajl:0}
# Non-server/HV driver defaults which are always enabled
%define with_python 0%{!?_without_python:1}
@@ -141,6 +142,11 @@
%define with_hal 0%{!?_without_hal:%{server_drivers}}
%endif
+# Enable yajl library for JSON mode with QEMU
+%if 0%{?fedora} >= 13 || 0%{?rhel} >= 6
+%define with_yajl 0%{!?_without_yajl:%{server_drivers}}
+%endif
+
# Force QEMU to run as non-root
%if 0%{?fedora} >= 12 || 0%{?rhel} >= 6
%define qemu_user qemu
@@ -257,6 +263,9 @@ BuildRequires: hal-devel
BuildRequires: libudev-devel >= 145
BuildRequires: libpciaccess-devel >= 0.10.9
%endif
+%if %{with_yajl}
+BuildRequires: yajl-devel
+%endif
%if %{with_avahi}
BuildRequires: avahi-devel
%endif
@@ -495,6 +504,10 @@ of recent versions of Linux (and other OSes).
%define _without_udev --without-udev
%endif
+%if ! %{with_yajl}
+%define _without_yajl --without-yajl
+%endif
+
%configure %{?_without_xen} \
%{?_without_qemu} \
%{?_without_openvz} \
@@ -522,6 +535,7 @@ of recent versions of Linux (and other OSes).
%{?_without_selinux} \
%{?_without_hal} \
%{?_without_udev} \
+ %{?_without_yajl} \
--with-qemu-user=%{qemu_user} \
--with-qemu-group=%{qemu_group} \
--with-init-script=redhat \
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 116aa87..9864259 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -50,6 +50,7 @@ src/uml/uml_driver.c
src/util/bridge.c
src/util/conf.c
src/util/iptables.c
+src/util/json.c
src/util/logging.c
src/util/pci.c
src/util/processinfo.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 9a3c9c8..b0775a8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -52,6 +52,7 @@ UTIL_SOURCES = \
util/hash.c util/hash.h \
util/iptables.c util/iptables.h \
util/ebtables.c util/ebtables.h \
+ util/json.c util/json.h \
util/logging.c util/logging.h \
util/memory.c util/memory.h \
util/pci.c util/pci.h \
@@ -283,8 +284,8 @@ noinst_LTLIBRARIES = libvirt_util.la
libvirt_la_LIBADD = libvirt_util.la
libvirt_util_la_SOURCES = \
$(UTIL_SOURCES)
-libvirt_util_la_CFLAGS = $(CAPNG_CFLAGS)
-libvirt_util_la_LDFLAGS = $(CAPNG_LIBS)
+libvirt_util_la_CFLAGS = $(CAPNG_CFLAGS) $(YAJL_CFLAGS)
+libvirt_util_la_LDFLAGS = $(CAPNG_LIBS) $(YAJL_LIBS)
noinst_LTLIBRARIES += libvirt_conf.la
@@ -828,12 +829,13 @@ libvirt_lxc_SOURCES = \
$(NODE_INFO_SOURCES) \
$(ENCRYPTION_CONF_SOURCES) \
$(DOMAIN_CONF_SOURCES)
-libvirt_lxc_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_LDCFLAGS) $(CAPNG_LIBS)
+libvirt_lxc_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_LDCFLAGS) $(CAPNG_LIBS) $(YAJL_LIBS)
libvirt_lxc_LDADD = $(LIBXML_LIBS) $(NUMACTL_LIBS) ../gnulib/lib/libgnu.la
libvirt_lxc_CFLAGS = \
$(LIBPARTED_CFLAGS) \
$(NUMACTL_CFLAGS) \
$(CAPNG_CFLAGS) \
+ $(YAJL_CFLAGS) \
-I@top_srcdir@/src/conf
endif
endif
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index e880c2e..ee7f3ed 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -269,6 +269,53 @@ virRegisterDeviceMonitor;
virRegisterSecretDriver;
+# json.h
+virJSONValueFree;
+virJSONValueNewString;
+virJSONValueNewStringLen;
+virJSONValueNewNumberInt;
+virJSONValueNewNumberUint;
+virJSONValueNewNumberLong;
+virJSONValueNewNumberUlong;
+virJSONValueNewNumberDouble;
+virJSONValueNewBoolean;
+virJSONValueNewNull;
+virJSONValueNewArray;
+virJSONValueNewObject;
+virJSONValueObjectAppend;
+virJSONValueObjectAppendString;
+virJSONValueObjectAppendNumberInt;
+virJSONValueObjectAppendNumberUint;
+virJSONValueObjectAppendNumberLong;
+virJSONValueObjectAppendNumberUlong;
+virJSONValueObjectAppendNumberDouble;
+virJSONValueObjectAppendBoolean;
+virJSONValueObjectAppendNull;
+virJSONValueArrayAppend;
+virJSONValueObjectHasKey;
+virJSONValueObjectGet;
+virJSONValueArraySize;
+virJSONValueArrayGet;
+virJSONValueGetString;
+virJSONValueGetNumberInt;
+virJSONValueGetNumberUint;
+virJSONValueGetNumberLong;
+virJSONValueGetNumberUlong;
+virJSONValueGetNumberDouble;
+virJSONValueGetBoolean;
+virJSONValueIsNull;
+virJSONValueObjectGetString;
+virJSONValueObjectGetNumberInt;
+virJSONValueObjectGetNumberUint;
+virJSONValueObjectGetNumberLong;
+virJSONValueObjectGetNumberUlong;
+virJSONValueObjectGetNumberDouble;
+virJSONValueObjectGetBoolean;
+virJSONValueObjectIsNull;
+virJSONValueFromString;
+virJSONValueToString;
+
+
# logging.h
virLogMessage;
virLogGetNbFilters;
diff --git a/src/util/json.c b/src/util/json.c
new file mode 100644
index 0000000..f359b95
--- /dev/null
+++ b/src/util/json.c
@@ -0,0 +1,1043 @@
+/*
+ * json.h: JSON object parsing/formatting
+ *
+ * Copyright (C) 2008 Daniel P. Berrange
+ *
+ * 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 <config.h>
+
+#include "json.h"
+#include "memory.h"
+#include "virterror_internal.h"
+#include "logging.h"
+#include "util.h"
+
+#include <yajl/yajl_gen.h>
+#include <yajl/yajl_parse.h>
+
+/* XXX fixme */
+#define VIR_FROM_THIS VIR_FROM_NONE
+#define ReportError(conn, code, fmt...) \
+ virReportErrorHelper(conn, VIR_FROM_NONE, code, __FILE__, \
+ __FUNCTION__, __LINE__, fmt)
+
+
+typedef struct _virJSONParserState virJSONParserState;
+typedef virJSONParserState *virJSONParserStatePtr;
+struct _virJSONParserState {
+ virJSONValuePtr value;
+ char *key;
+};
+
+typedef struct _virJSONParser virJSONParser;
+typedef virJSONParser *virJSONParserPtr;
+struct _virJSONParser {
+ virJSONValuePtr head;
+ virJSONParserStatePtr state;
+ unsigned int nstate;
+};
+
+
+void virJSONValueFree(virJSONValuePtr value)
+{
+ int i;
+ if (!value)
+ return;
+
+ switch (value->type) {
+ case VIR_JSON_TYPE_OBJECT:
+ for (i = 0 ; i < value->data.array.nvalues ; i++) {
+ VIR_FREE(value->data.object.pairs[i].key);
+ virJSONValueFree(value->data.object.pairs[i].value);
+ }
+ VIR_FREE(value->data.object.pairs);
+ break;
+ case VIR_JSON_TYPE_ARRAY:
+ for (i = 0 ; i < value->data.array.nvalues ; i++)
+ virJSONValueFree(value->data.array.values[i]);
+ VIR_FREE(value->data.array.values);
+ break;
+ case VIR_JSON_TYPE_STRING:
+ VIR_FREE(value->data.string);
+ break;
+ case VIR_JSON_TYPE_NUMBER:
+ VIR_FREE(value->data.number);
+ break;
+
+ }
+}
+
+
+virJSONValuePtr virJSONValueNewString(const char *data)
+{
+ virJSONValuePtr val;
+
+ if (!data)
+ return virJSONValueNewNull();
+
+ if (VIR_ALLOC(val) < 0)
+ return NULL;
+
+ val->type = VIR_JSON_TYPE_STRING;
+ if (!(val->data.string = strdup(data))) {
+ VIR_FREE(val);
+ return NULL;
+ }
+
+ return val;
+}
+
+virJSONValuePtr virJSONValueNewStringLen(const char *data, size_t length)
+{
+ virJSONValuePtr val;
+
+ if (!data)
+ return virJSONValueNewNull();
+
+ if (VIR_ALLOC(val) < 0)
+ return NULL;
+
+ val->type = VIR_JSON_TYPE_STRING;
+ if (!(val->data.string = strndup(data, length))) {
+ VIR_FREE(val);
+ return NULL;
+ }
+
+ return val;
+}
+
+static virJSONValuePtr virJSONValueNewNumber(const char *data)
+{
+ virJSONValuePtr val;
+
+ if (VIR_ALLOC(val) < 0)
+ return NULL;
+
+ val->type = VIR_JSON_TYPE_NUMBER;
+ if (!(val->data.number = strdup(data))) {
+ VIR_FREE(val);
+ return NULL;
+ }
+
+ return val;
+}
+
+virJSONValuePtr virJSONValueNewNumberInt(int data)
+{
+ virJSONValuePtr val = NULL;
+ char *str;
+ if (virAsprintf(&str, "%i", data) < 0)
+ return NULL;
+ val = virJSONValueNewNumber(str);
+ VIR_FREE(str);
+ return val;
+}
+
+
+virJSONValuePtr virJSONValueNewNumberUint(unsigned int data)
+{
+ virJSONValuePtr val = NULL;
+ char *str;
+ if (virAsprintf(&str, "%u", data) < 0)
+ return NULL;
+ val = virJSONValueNewNumber(str);
+ VIR_FREE(str);
+ return val;
+}
+
+
+virJSONValuePtr virJSONValueNewNumberLong(long long data)
+{
+ virJSONValuePtr val = NULL;
+ char *str;
+ if (virAsprintf(&str, "%lld", data) < 0)
+ return NULL;
+ val = virJSONValueNewNumber(str);
+ VIR_FREE(str);
+ return val;
+}
+
+
+virJSONValuePtr virJSONValueNewNumberUlong(unsigned long long data)
+{
+ virJSONValuePtr val = NULL;
+ char *str;
+ if (virAsprintf(&str, "%llu", data) < 0)
+ return NULL;
+ val = virJSONValueNewNumber(str);
+ VIR_FREE(str);
+ return val;
+}
+
+
+virJSONValuePtr virJSONValueNewNumberDouble(double data)
+{
+ virJSONValuePtr val = NULL;
+ char *str;
+ if (virAsprintf(&str, "%lf", data) < 0)
+ return NULL;
+ val = virJSONValueNewNumber(str);
+ VIR_FREE(str);
+ return val;
+}
+
+
+virJSONValuePtr virJSONValueNewBoolean(int boolean)
+{
+ virJSONValuePtr val;
+
+ if (VIR_ALLOC(val) < 0)
+ return NULL;
+
+ val->type = VIR_JSON_TYPE_BOOLEAN;
+ val->data.boolean = boolean;
+
+ return val;
+}
+
+virJSONValuePtr virJSONValueNewNull(void)
+{
+ virJSONValuePtr val;
+
+ if (VIR_ALLOC(val) < 0)
+ return NULL;
+
+ val->type = VIR_JSON_TYPE_NULL;
+
+ return val;
+}
+
+virJSONValuePtr virJSONValueNewArray(void)
+{
+ virJSONValuePtr val;
+
+ if (VIR_ALLOC(val) < 0)
+ return NULL;
+
+ val->type = VIR_JSON_TYPE_ARRAY;
+
+ return val;
+}
+
+virJSONValuePtr virJSONValueNewObject(void)
+{
+ virJSONValuePtr val;
+
+ if (VIR_ALLOC(val) < 0)
+ return NULL;
+
+ val->type = VIR_JSON_TYPE_OBJECT;
+
+ return val;
+}
+
+int virJSONValueObjectAppend(virJSONValuePtr object, const char *key, virJSONValuePtr
value)
+{
+ char *newkey;
+
+ if (object->type != VIR_JSON_TYPE_OBJECT)
+ return -1;
+
+ if (virJSONValueObjectHasKey(object, key))
+ return -1;
+
+ if (!(newkey = strdup(key)))
+ return -1;
+
+ if (VIR_REALLOC_N(object->data.object.pairs,
+ object->data.object.npairs + 1) < 0) {
+ VIR_FREE(newkey);
+ return -1;
+ }
+
+ object->data.object.pairs[object->data.object.npairs].key = newkey;
+ object->data.object.pairs[object->data.object.npairs].value = value;
+ object->data.object.npairs++;
+
+ return 0;
+}
+
+
+int virJSONValueObjectAppendString(virJSONValuePtr object, const char *key, const char
*value)
+{
+ virJSONValuePtr jvalue = virJSONValueNewString(value);
+ if (!jvalue)
+ return -1;
+ if (virJSONValueObjectAppend(object, key, jvalue) < 0) {
+ virJSONValueFree(jvalue);
+ return -1;
+ }
+ return 0;
+}
+
+int virJSONValueObjectAppendNumberInt(virJSONValuePtr object, const char *key, int
number)
+{
+ virJSONValuePtr jvalue = virJSONValueNewNumberInt(number);
+ if (!jvalue)
+ return -1;
+ if (virJSONValueObjectAppend(object, key, jvalue) < 0) {
+ virJSONValueFree(jvalue);
+ return -1;
+ }
+ return 0;
+}
+
+
+int virJSONValueObjectAppendNumberUint(virJSONValuePtr object, const char *key, unsigned
int number)
+{
+ virJSONValuePtr jvalue = virJSONValueNewNumberUint(number);
+ if (!jvalue)
+ return -1;
+ if (virJSONValueObjectAppend(object, key, jvalue) < 0) {
+ virJSONValueFree(jvalue);
+ return -1;
+ }
+ return 0;
+}
+
+int virJSONValueObjectAppendNumberLong(virJSONValuePtr object, const char *key, long long
number)
+{
+ virJSONValuePtr jvalue = virJSONValueNewNumberLong(number);
+ if (!jvalue)
+ return -1;
+ if (virJSONValueObjectAppend(object, key, jvalue) < 0) {
+ virJSONValueFree(jvalue);
+ return -1;
+ }
+ return 0;
+}
+
+int virJSONValueObjectAppendNumberUlong(virJSONValuePtr object, const char *key, unsigned
long long number)
+{
+ virJSONValuePtr jvalue = virJSONValueNewNumberUlong(number);
+ if (!jvalue)
+ return -1;
+ if (virJSONValueObjectAppend(object, key, jvalue) < 0) {
+ virJSONValueFree(jvalue);
+ return -1;
+ }
+ return 0;
+}
+
+int virJSONValueObjectAppendNumberDouble(virJSONValuePtr object, const char *key, double
number)
+{
+ virJSONValuePtr jvalue = virJSONValueNewNumberDouble(number);
+ if (!jvalue)
+ return -1;
+ if (virJSONValueObjectAppend(object, key, jvalue) < 0) {
+ virJSONValueFree(jvalue);
+ return -1;
+ }
+ return 0;
+}
+
+int virJSONValueObjectAppendBoolean(virJSONValuePtr object, const char *key, int
boolean)
+{
+ virJSONValuePtr jvalue = virJSONValueNewBoolean(boolean);
+ if (!jvalue)
+ return -1;
+ if (virJSONValueObjectAppend(object, key, jvalue) < 0) {
+ virJSONValueFree(jvalue);
+ return -1;
+ }
+ return 0;
+}
+
+int virJSONValueObjectAppendNull(virJSONValuePtr object, const char *key)
+{
+ virJSONValuePtr jvalue = virJSONValueNewNull();
+ if (!jvalue)
+ return -1;
+ if (virJSONValueObjectAppend(object, key, jvalue) < 0) {
+ virJSONValueFree(jvalue);
+ return -1;
+ }
+ return 0;
+}
+
+
+int virJSONValueArrayAppend(virJSONValuePtr array, virJSONValuePtr value)
+{
+ if (array->type != VIR_JSON_TYPE_ARRAY)
+ return -1;
+
+ if (VIR_REALLOC_N(array->data.array.values,
+ array->data.array.nvalues + 1) < 0)
+ return -1;
+
+ array->data.array.values[array->data.array.nvalues] = value;
+ array->data.array.nvalues++;
+
+ return 0;
+}
+
+int virJSONValueObjectHasKey(virJSONValuePtr object, const char *key)
+{
+ int i;
+
+ if (object->type != VIR_JSON_TYPE_OBJECT)
+ return -1;
+
+ for (i = 0 ; i < object->data.object.npairs ; i++) {
+ if (STREQ(object->data.object.pairs[i].key, key))
+ return 1;
+ }
+
+ return 0;
+}
+
+virJSONValuePtr virJSONValueObjectGet(virJSONValuePtr object, const char *key)
+{
+ int i;
+
+ if (object->type != VIR_JSON_TYPE_OBJECT)
+ return NULL;
+
+ for (i = 0 ; i < object->data.object.npairs ; i++) {
+ if (STREQ(object->data.object.pairs[i].key, key))
+ return object->data.object.pairs[i].value;
+ }
+
+ return NULL;
+}
+
+int virJSONValueArraySize(virJSONValuePtr array)
+{
+ if (array->type != VIR_JSON_TYPE_ARRAY)
+ return -1;
+
+ return array->data.array.nvalues;
+}
+
+
+virJSONValuePtr virJSONValueArrayGet(virJSONValuePtr array, unsigned int element)
+{
+ if (array->type != VIR_JSON_TYPE_ARRAY)
+ return NULL;
+
+ if (element >= array->data.array.nvalues)
+ return NULL;
+
+ return array->data.array.values[element];
+}
+
+char *virJSONValueGetString(virJSONValuePtr string)
+{
+ if (string->type != VIR_JSON_TYPE_STRING)
+ return NULL;
+
+ return string->data.string;
+}
+
+
+int virJSONValueGetNumberInt(virJSONValuePtr number, int *value)
+{
+ if (number->type != VIR_JSON_TYPE_NUMBER)
+ return -1;
+
+ return virStrToLong_i(number->data.number, NULL, 10, value);
+}
+
+int virJSONValueGetNumberUint(virJSONValuePtr number, unsigned int *value)
+{
+ if (number->type != VIR_JSON_TYPE_NUMBER)
+ return -1;
+
+ return virStrToLong_ui(number->data.number, NULL, 10, value);
+}
+
+int virJSONValueGetNumberLong(virJSONValuePtr number, long long *value)
+{
+ if (number->type != VIR_JSON_TYPE_NUMBER)
+ return -1;
+
+ return virStrToLong_ll(number->data.number, NULL, 10, value);
+}
+
+int virJSONValueGetNumberUlong(virJSONValuePtr number, unsigned long long *value)
+{
+ if (number->type != VIR_JSON_TYPE_NUMBER)
+ return -1;
+
+ return virStrToLong_ull(number->data.number, NULL, 10, value);
+}
+
+int virJSONValueGetNumberDouble(virJSONValuePtr number, double *value)
+{
+ if (number->type != VIR_JSON_TYPE_NUMBER)
+ return -1;
+
+ return virStrToDouble(number->data.number, NULL, value);
+}
+
+
+int virJSONValueGetBoolean(virJSONValuePtr val)
+{
+ if (val->type != VIR_JSON_TYPE_NUMBER)
+ return -1;
+
+ return val->data.boolean;
+}
+
+
+int virJSONValueIsNull(virJSONValuePtr val)
+{
+ if (val->type != VIR_JSON_TYPE_NULL)
+ return 0;
+
+ return 1;
+}
+
+
+char *virJSONValueObjectGetString(virJSONValuePtr object, const char *key)
+{
+ virJSONValuePtr val;
+ if (object->type != VIR_JSON_TYPE_OBJECT)
+ return NULL;
+
+ val = virJSONValueObjectGet(object, key);
+ if (!val)
+ return NULL;
+
+ return virJSONValueGetString(val);
+}
+
+
+int virJSONValueObjectGetNumberInt(virJSONValuePtr object, const char *key, int *value)
+{
+ virJSONValuePtr val;
+ if (object->type != VIR_JSON_TYPE_OBJECT)
+ return -1;
+
+ val = virJSONValueObjectGet(object, key);
+ if (!val)
+ return -1;
+
+ return virJSONValueGetNumberInt(val, value);
+}
+
+
+int virJSONValueObjectGetNumberUint(virJSONValuePtr object, const char *key, unsigned int
*value)
+{
+ virJSONValuePtr val;
+ if (object->type != VIR_JSON_TYPE_OBJECT)
+ return -1;
+
+ val = virJSONValueObjectGet(object, key);
+ if (!val)
+ return -1;
+
+ return virJSONValueGetNumberUint(val, value);
+}
+
+
+int virJSONValueObjectGetNumberLong(virJSONValuePtr object, const char *key, long long
*value)
+{
+ virJSONValuePtr val;
+ if (object->type != VIR_JSON_TYPE_OBJECT)
+ return -1;
+
+ val = virJSONValueObjectGet(object, key);
+ if (!val)
+ return -1;
+
+ return virJSONValueGetNumberLong(val, value);
+}
+
+
+int virJSONValueObjectGetNumberUlong(virJSONValuePtr object, const char *key, unsigned
long long *value)
+{
+ virJSONValuePtr val;
+ if (object->type != VIR_JSON_TYPE_OBJECT)
+ return -1;
+
+ val = virJSONValueObjectGet(object, key);
+ if (!val)
+ return -1;
+
+ return virJSONValueGetNumberUlong(val, value);
+}
+
+
+int virJSONValueObjectGetNumberDouble(virJSONValuePtr object, const char *key, double
*value)
+{
+ virJSONValuePtr val;
+ if (object->type != VIR_JSON_TYPE_OBJECT)
+ return -1;
+
+ val = virJSONValueObjectGet(object, key);
+ if (!val)
+ return -1;
+
+ return virJSONValueGetNumberDouble(val, value);
+}
+
+
+int virJSONValueObjectGetBoolean(virJSONValuePtr object, const char *key)
+{
+ virJSONValuePtr val;
+ if (object->type != VIR_JSON_TYPE_OBJECT)
+ return -1;
+
+ val = virJSONValueObjectGet(object, key);
+ if (!val)
+ return -1;
+
+ return virJSONValueGetBoolean(val);
+}
+
+
+int virJSONValueObjectIsNull(virJSONValuePtr object, const char *key)
+{
+ virJSONValuePtr val;
+ if (object->type != VIR_JSON_TYPE_OBJECT)
+ return -1;
+
+ val = virJSONValueObjectGet(object, key);
+ if (!val)
+ return -1;
+
+ return virJSONValueIsNull(val);
+}
+
+
+#if HAVE_YAJL
+static int virJSONParserInsertValue(virJSONParserPtr parser,
+ virJSONValuePtr value)
+{
+ if (!parser->head) {
+ parser->head = value;
+ } else {
+ virJSONParserStatePtr state;
+ if (!parser->nstate) {
+ VIR_DEBUG0("got a value to insert without a container");
+ return -1;
+ }
+
+ state = &parser->state[parser->nstate-1];
+
+ switch (state->value->type) {
+ case VIR_JSON_TYPE_OBJECT: {
+ if (!state->key) {
+ VIR_DEBUG0("missing key when inserting object value");
+ return -1;
+ }
+
+ if (virJSONValueObjectAppend(state->value,
+ state->key,
+ value) < 0)
+ return -1;
+
+ VIR_FREE(state->key);
+ } break;
+
+ case VIR_JSON_TYPE_ARRAY: {
+ if (state->key) {
+ VIR_DEBUG0("unexpected key when inserting array value");
+ return -1;
+ }
+
+ if (virJSONValueArrayAppend(state->value,
+ value) < 0)
+ return -1;
+ } break;
+
+ default:
+ VIR_DEBUG0("unexpected value type, not a container");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int virJSONParserHandleNull(void * ctx)
+{
+ virJSONParserPtr parser = ctx;
+ virJSONValuePtr value = virJSONValueNewNull();
+
+ VIR_DEBUG("parser=%p", parser);
+
+ if (!value)
+ return 0;
+
+ if (virJSONParserInsertValue(parser, value) < 0) {
+ virJSONValueFree(value);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int virJSONParserHandleBoolean(void * ctx, int boolean)
+{
+ virJSONParserPtr parser = ctx;
+ virJSONValuePtr value = virJSONValueNewBoolean(boolean);
+
+ VIR_DEBUG("parser=%p boolean=%d", parser, boolean);
+
+ if (!value)
+ return 0;
+
+ if (virJSONParserInsertValue(parser, value) < 0) {
+ virJSONValueFree(value);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int virJSONParserHandleNumber(void * ctx,
+ const char * s,
+ unsigned int l)
+{
+ virJSONParserPtr parser = ctx;
+ char *str = strndup(s, l);
+ virJSONValuePtr value;
+
+ if (!str)
+ return -1;
+ value = virJSONValueNewNumber(str);
+ VIR_FREE(str);
+
+ VIR_DEBUG("parser=%p str=%s", parser, str);
+
+ if (!value)
+ return 0;
+
+ if (virJSONParserInsertValue(parser, value) < 0) {
+ virJSONValueFree(value);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int virJSONParserHandleString(void * ctx,
+ const unsigned char * stringVal,
+ unsigned int stringLen)
+{
+ virJSONParserPtr parser = ctx;
+ virJSONValuePtr value = virJSONValueNewStringLen((const char *)stringVal,
+ stringLen);
+
+ VIR_DEBUG("parser=%p str=%p", parser, (const char *)stringVal);
+
+ if (!value)
+ return 0;
+
+ if (virJSONParserInsertValue(parser, value) < 0) {
+ virJSONValueFree(value);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int virJSONParserHandleMapKey(void * ctx,
+ const unsigned char * stringVal,
+ unsigned int stringLen)
+{
+ virJSONParserPtr parser = ctx;
+ virJSONParserStatePtr state;
+
+ VIR_DEBUG("parser=%p key=%p", parser, (const char *)stringVal);
+
+ if (!parser->nstate)
+ return 0;
+
+ state = &parser->state[parser->nstate-1];
+ if (state->key)
+ return 0;
+ state->key = strndup((const char *)stringVal, stringLen);
+ if (!state->key)
+ return 0;
+ return 1;
+}
+
+static int virJSONParserHandleStartMap(void * ctx)
+{
+ virJSONParserPtr parser = ctx;
+ virJSONValuePtr value = virJSONValueNewObject();
+
+ VIR_DEBUG("parser=%p", parser);
+
+ if (!value)
+ return 0;
+
+ if (virJSONParserInsertValue(parser, value) < 0) {
+ virJSONValueFree(value);
+ return 0;
+ }
+
+ if (VIR_REALLOC_N(parser->state,
+ parser->nstate + 1) < 0)
+ return 0;
+
+ parser->state[parser->nstate].value = value;
+ parser->state[parser->nstate].key = NULL;
+ parser->nstate++;
+
+ return 1;
+}
+
+
+static int virJSONParserHandleEndMap(void * ctx)
+{
+ virJSONParserPtr parser = ctx;
+ virJSONParserStatePtr state;
+
+ VIR_DEBUG("parser=%p", parser);
+
+ if (!parser->nstate)
+ return 0;
+
+ state = &(parser->state[parser->nstate-1]);
+ if (state->key) {
+ VIR_FREE(state->key);
+ return 0;
+ }
+
+ if (VIR_REALLOC_N(parser->state,
+ parser->nstate - 1) < 0)
+ return 0;
+ parser->nstate--;
+
+ return 1;
+}
+
+static int virJSONParserHandleStartArray(void * ctx)
+{
+ virJSONParserPtr parser = ctx;
+ virJSONValuePtr value = virJSONValueNewArray();
+
+ VIR_DEBUG("parser=%p", parser);
+
+ if (!value)
+ return 0;
+
+ if (virJSONParserInsertValue(parser, value) < 0) {
+ virJSONValueFree(value);
+ return 0;
+ }
+
+ if (VIR_REALLOC_N(parser->state,
+ parser->nstate + 1) < 0)
+ return 0;
+
+ parser->state[parser->nstate].value = value;
+ parser->state[parser->nstate].key = NULL;
+ parser->nstate++;
+
+ return 1;
+}
+
+static int virJSONParserHandleEndArray(void * ctx)
+{
+ virJSONParserPtr parser = ctx;
+ virJSONParserStatePtr state;
+
+ VIR_DEBUG("parser=%p", parser);
+
+ if (!parser->nstate)
+ return 0;
+
+ state = &(parser->state[parser->nstate-1]);
+ if (state->key) {
+ VIR_FREE(state->key);
+ return 0;
+ }
+
+ if (VIR_REALLOC_N(parser->state,
+ parser->nstate - 1) < 0)
+ return 0;
+ parser->nstate--;
+
+ return 1;
+}
+
+static const yajl_callbacks parserCallbacks = {
+ virJSONParserHandleNull,
+ virJSONParserHandleBoolean,
+ NULL,
+ NULL,
+ virJSONParserHandleNumber,
+ virJSONParserHandleString,
+ virJSONParserHandleStartMap,
+ virJSONParserHandleMapKey,
+ virJSONParserHandleEndMap,
+ virJSONParserHandleStartArray,
+ virJSONParserHandleEndArray
+};
+
+
+/* XXX add an incremental streaming parser - yajl trivially supports it */
+virJSONValuePtr virJSONValueFromString(const char *jsonstring)
+{
+ yajl_parser_config cfg = { 1, 1 };
+ yajl_handle hand;
+ virJSONParser parser = { NULL, NULL, 0 };
+
+ VIR_DEBUG("string=%s", jsonstring);
+
+ hand = yajl_alloc(&parserCallbacks, &cfg, NULL, &parser);
+
+ if (yajl_parse(hand,
+ (const unsigned char *)jsonstring,
+ strlen(jsonstring)) != yajl_status_ok) {
+ unsigned char *errstr = yajl_get_error(hand, 1,
+ (const unsigned char*)jsonstring,
+ strlen(jsonstring));
+
+ ReportError(NULL, VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse json %s: %s"),
+ jsonstring, (const char*) errstr);
+ VIR_FREE(errstr);
+ virJSONValueFree(parser.head);
+ goto cleanup;
+ }
+
+cleanup:
+ yajl_free(hand);
+
+ if (parser.nstate) {
+ int i;
+ VIR_WARN("cleanup state %d", parser.nstate);
+ for (i = 0 ; i < parser.nstate ; i++) {
+ VIR_FREE(parser.state[i].key);
+ }
+ }
+
+ VIR_DEBUG("result=%p", parser.head);
+
+ return parser.head;
+}
+
+
+static int virJSONValueToStringOne(virJSONValuePtr object,
+ yajl_gen g)
+{
+ int i;
+
+ VIR_DEBUG("object=%p type=%d gen=%p", object, object->type, g);
+
+ switch (object->type) {
+ case VIR_JSON_TYPE_OBJECT:
+ if (yajl_gen_map_open(g) != yajl_gen_status_ok)
+ return -1;
+ for (i = 0; i < object->data.object.npairs ; i++) {
+ if (yajl_gen_string(g,
+ (unsigned char *)object->data.object.pairs[i].key,
+ strlen(object->data.object.pairs[i].key))
+ != yajl_gen_status_ok)
+ return -1;
+ if (virJSONValueToStringOne(object->data.object.pairs[i].value, g) <
0)
+ return -1;
+ }
+ if (yajl_gen_map_close(g) != yajl_gen_status_ok)
+ return -1;
+ break;
+ case VIR_JSON_TYPE_ARRAY:
+ if (yajl_gen_array_open(g) != yajl_gen_status_ok)
+ return -1;
+ for (i = 0; i < object->data.array.nvalues ; i++) {
+ if (virJSONValueToStringOne(object->data.array.values[i], g) < 0)
+ return -1;
+ }
+ if (yajl_gen_array_close(g) != yajl_gen_status_ok)
+ return -1;
+ break;
+
+ case VIR_JSON_TYPE_STRING:
+ if (yajl_gen_string(g, (unsigned char *)object->data.string,
+ strlen(object->data.string)) != yajl_gen_status_ok)
+ return -1;
+ break;
+
+ case VIR_JSON_TYPE_NUMBER:
+ if (yajl_gen_number(g, object->data.number,
+ strlen(object->data.number)) != yajl_gen_status_ok)
+ return -1;
+ break;
+
+ case VIR_JSON_TYPE_BOOLEAN:
+ if (yajl_gen_bool(g, object->data.boolean) != yajl_gen_status_ok)
+ return -1;
+ break;
+
+ case VIR_JSON_TYPE_NULL:
+ if (yajl_gen_null(g) != yajl_gen_status_ok)
+ return -1;
+ break;
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+char *virJSONValueToString(virJSONValuePtr object)
+{
+ yajl_gen_config conf = { 0, " " }; /* Turns off pretty printing since QEMU
can't cope */
+ yajl_gen g;
+ const unsigned char *str;
+ char *ret = NULL;
+ unsigned int len;
+
+ VIR_DEBUG("object=%p", object);
+
+ g = yajl_gen_alloc(&conf, NULL);
+
+ if (virJSONValueToStringOne(object, g) < 0) {
+ virReportOOMError(NULL);
+ goto cleanup;
+ }
+
+ if (yajl_gen_get_buf(g, &str, &len) != yajl_gen_status_ok) {
+ virReportOOMError(NULL);
+ goto cleanup;
+ }
+
+ if (!(ret = strdup((const char *)str)))
+ virReportOOMError(NULL);
+
+cleanup:
+ yajl_gen_free(g);
+
+ VIR_DEBUG("result=%s", NULLSTR(ret));
+
+ return ret;
+}
+
+
+#else
+virJSONValuePtr virJSONValueFromString(const char *jsonstring ATTRIBUTE_UNUSED)
+{
+ ReprotError(NULL, VIR_ERR_INTERNAL_ERROR, "%s",
+ _("No JSON parser implementation is available"));
+ return NULL;
+}
+char *virJSONValueToString(virJSONValuePtr object)
+{
+ ReprotError(NULL, VIR_ERR_INTERNAL_ERROR, "%s",
+ _("No JSON parser implementation is available"));
+ return NULL;
+}
+#endif
diff --git a/src/util/json.h b/src/util/json.h
new file mode 100644
index 0000000..bab93cf
--- /dev/null
+++ b/src/util/json.h
@@ -0,0 +1,131 @@
+/*
+ * json.h: JSON object parsing/formatting
+ *
+ * Copyright (C) 2008 Daniel P. Berrange
+ *
+ * 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 __VIR_JSON_H_
+#define __VIR_JSON_H_
+
+#include "internal.h"
+
+
+enum {
+ VIR_JSON_TYPE_OBJECT,
+ VIR_JSON_TYPE_ARRAY,
+ VIR_JSON_TYPE_STRING,
+ VIR_JSON_TYPE_NUMBER,
+ VIR_JSON_TYPE_BOOLEAN,
+ VIR_JSON_TYPE_NULL,
+};
+
+typedef struct _virJSONValue virJSONValue;
+typedef virJSONValue *virJSONValuePtr;
+
+typedef struct _virJSONObject virJSONObject;
+typedef virJSONObject *virJSONObjectPtr;
+
+typedef struct _virJSONObjectPair virJSONObjectPair;
+typedef virJSONObjectPair *virJSONObjectPairPtr;
+
+typedef struct _virJSONArray virJSONArray;
+typedef virJSONArray *virJSONArrayPtr;
+
+
+struct _virJSONObjectPair {
+ char *key;
+ virJSONValuePtr value;
+};
+
+struct _virJSONObject {
+ unsigned int npairs;
+ virJSONObjectPairPtr pairs;
+};
+
+struct _virJSONArray {
+ unsigned int nvalues;
+ virJSONValuePtr *values;
+};
+
+struct _virJSONValue {
+ int type;
+
+ union {
+ virJSONObject object;
+ virJSONArray array;
+ char *string;
+ char *number; /* int/float/etc format is context defined so we can't parse it
here :-( */
+ int boolean;
+ } data;
+};
+
+void virJSONValueFree(virJSONValuePtr value);
+
+virJSONValuePtr virJSONValueNewString(const char *data);
+virJSONValuePtr virJSONValueNewStringLen(const char *data, size_t length);
+virJSONValuePtr virJSONValueNewNumberInt(int data);
+virJSONValuePtr virJSONValueNewNumberUint(unsigned int data);
+virJSONValuePtr virJSONValueNewNumberLong(long long data);
+virJSONValuePtr virJSONValueNewNumberUlong(unsigned long long data);
+virJSONValuePtr virJSONValueNewNumberDouble(double data);
+virJSONValuePtr virJSONValueNewBoolean(int boolean);
+virJSONValuePtr virJSONValueNewNull(void);
+virJSONValuePtr virJSONValueNewArray(void);
+virJSONValuePtr virJSONValueNewObject(void);
+
+int virJSONValueObjectAppend(virJSONValuePtr object, const char *key, virJSONValuePtr
value);
+int virJSONValueArrayAppend(virJSONValuePtr object, virJSONValuePtr value);
+
+int virJSONValueObjectHasKey(virJSONValuePtr object, const char *key);
+virJSONValuePtr virJSONValueObjectGet(virJSONValuePtr object, const char *key);
+
+int virJSONValueArraySize(virJSONValuePtr object);
+virJSONValuePtr virJSONValueArrayGet(virJSONValuePtr object, unsigned int element);
+
+char *virJSONValueGetString(virJSONValuePtr object);
+int virJSONValueGetNumberInt(virJSONValuePtr object, int *value);
+int virJSONValueGetNumberUint(virJSONValuePtr object, unsigned int *value);
+int virJSONValueGetNumberLong(virJSONValuePtr object, long long *value);
+int virJSONValueGetNumberUlong(virJSONValuePtr object, unsigned long long *value);
+int virJSONValueGetNumberDouble(virJSONValuePtr object, double *value);
+int virJSONValueGetBoolean(virJSONValuePtr object);
+int virJSONValueIsNull(virJSONValuePtr object);
+
+char *virJSONValueObjectGetString(virJSONValuePtr object, const char *key);
+int virJSONValueObjectGetNumberInt(virJSONValuePtr object, const char *key, int *value);
+int virJSONValueObjectGetNumberUint(virJSONValuePtr object, const char *key, unsigned int
*value);
+int virJSONValueObjectGetNumberLong(virJSONValuePtr object, const char *key, long long
*value);
+int virJSONValueObjectGetNumberUlong(virJSONValuePtr object, const char *key, unsigned
long long *value);
+int virJSONValueObjectGetNumberDouble(virJSONValuePtr object, const char *key, double
*value);
+int virJSONValueObjectGetBoolean(virJSONValuePtr object, const char *key);
+int virJSONValueObjectIsNull(virJSONValuePtr object, const char *key);
+
+int virJSONValueObjectAppendString(virJSONValuePtr object, const char *key, const char
*value);
+int virJSONValueObjectAppendNumberInt(virJSONValuePtr object, const char *key, int
number);
+int virJSONValueObjectAppendNumberUint(virJSONValuePtr object, const char *key, unsigned
int number);
+int virJSONValueObjectAppendNumberLong(virJSONValuePtr object, const char *key, long long
number);
+int virJSONValueObjectAppendNumberUlong(virJSONValuePtr object, const char *key, unsigned
long long number);
+int virJSONValueObjectAppendNumberDouble(virJSONValuePtr object, const char *key, double
number);
+int virJSONValueObjectAppendBoolean(virJSONValuePtr object, const char *key, int
boolean);
+int virJSONValueObjectAppendNull(virJSONValuePtr object, const char *key);
+
+virJSONValuePtr virJSONValueFromString(const char *jsonstring);
+char *virJSONValueToString(virJSONValuePtr object);
+
+#endif /* __VIR_JSON_H_ */
--
1.6.5.2