提交 9428f2ce 编写于 作者: D Daniel P. Berrange

Introduce a simple API for handling JSON data

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
上级 563dc565
......@@ -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
......
......@@ -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 \
......
......@@ -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
......
......@@ -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 \
......@@ -284,8 +285,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
......@@ -829,12 +830,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
......
......@@ -270,6 +270,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;
......
/*
* json.c: JSON object parsing/formatting
*
* Copyright (C) 2009 Daniel P. Berrange
* Copyright (C) 2009 Red Hat, Inc.
*
* 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
/*
* json.h: JSON object parsing/formatting
*
* Copyright (C) 2009 Daniel P. Berrange
* Copyright (C) 2009 Red Hat, Inc.
*
* 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_ */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册