2009-11-03 18:59:18 +00:00
|
|
|
/*
|
2012-12-12 17:53:50 +00:00
|
|
|
* virjson.c: JSON object parsing/formatting
|
2009-11-03 18:59:18 +00:00
|
|
|
*
|
2014-08-21 10:23:41 +00:00
|
|
|
* Copyright (C) 2009-2010, 2012-2015 Red Hat, Inc.
|
2010-03-01 23:38:28 +00:00
|
|
|
* Copyright (C) 2009 Daniel P. Berrange
|
2009-11-03 18:59:18 +00:00
|
|
|
*
|
|
|
|
* 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
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 10:06:23 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2009-11-03 18:59:18 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
2012-12-12 17:53:50 +00:00
|
|
|
#include "virjson.h"
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2012-12-12 17:59:27 +00:00
|
|
|
#include "virlog.h"
|
2013-04-03 10:36:23 +00:00
|
|
|
#include "virstring.h"
|
2012-12-13 17:44:57 +00:00
|
|
|
#include "virutil.h"
|
2009-11-03 18:59:18 +00:00
|
|
|
|
|
|
|
/* XXX fixme */
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_NONE
|
|
|
|
|
2014-02-28 12:16:17 +00:00
|
|
|
VIR_LOG_INIT("util.json");
|
2009-11-03 18:59:18 +00:00
|
|
|
|
2018-03-29 18:36:56 +00:00
|
|
|
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 {
|
|
|
|
size_t npairs;
|
|
|
|
virJSONObjectPairPtr pairs;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct _virJSONArray {
|
|
|
|
size_t nvalues;
|
|
|
|
virJSONValuePtr *values;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct _virJSONValue {
|
|
|
|
int type; /* enum virJSONType */
|
|
|
|
|
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2018-03-20 13:07:26 +00:00
|
|
|
virJSONType
|
|
|
|
virJSONValueGetType(const virJSONValue *value)
|
|
|
|
{
|
|
|
|
return value->type;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-22 14:35:02 +00:00
|
|
|
/**
|
2015-01-12 15:35:17 +00:00
|
|
|
* virJSONValueObjectAddVArgs:
|
|
|
|
* @obj: JSON object to add the values to
|
|
|
|
* @args: a key-value argument pairs, terminated by NULL
|
2014-09-22 14:35:02 +00:00
|
|
|
*
|
2015-01-12 15:35:17 +00:00
|
|
|
* Adds the key-value pairs supplied as variable argument list to @obj.
|
2014-09-22 14:35:02 +00:00
|
|
|
*
|
|
|
|
* Keys look like s:name the first letter is a type code:
|
|
|
|
* Explanation of type codes:
|
|
|
|
* s: string value, must be non-null
|
|
|
|
* S: string value, omitted if null
|
|
|
|
*
|
|
|
|
* i: signed integer value
|
|
|
|
* j: signed integer value, error if negative
|
|
|
|
* z: signed integer value, omitted if zero
|
|
|
|
* y: signed integer value, omitted if zero, error if negative
|
|
|
|
*
|
|
|
|
* I: signed long integer value
|
|
|
|
* J: signed long integer value, error if negative
|
|
|
|
* Z: signed long integer value, omitted if zero
|
|
|
|
* Y: signed long integer value, omitted if zero, error if negative
|
|
|
|
*
|
|
|
|
* u: unsigned integer value
|
|
|
|
* p: unsigned integer value, omitted if zero
|
|
|
|
*
|
|
|
|
* U: unsigned long integer value (see below for quirks)
|
|
|
|
* P: unsigned long integer value, omitted if zero
|
|
|
|
*
|
|
|
|
* b: boolean value
|
|
|
|
* B: boolean value, omitted if false
|
|
|
|
*
|
|
|
|
* d: double precision floating point number
|
|
|
|
* n: json null value
|
2014-09-23 09:48:08 +00:00
|
|
|
*
|
2018-03-30 09:12:57 +00:00
|
|
|
* The following two cases take a pointer to a pointer to a virJSONValuePtr. The
|
|
|
|
* pointer is cleared when the virJSONValuePtr is stolen into the object.
|
2014-09-23 09:48:08 +00:00
|
|
|
* a: json object, must be non-NULL
|
2014-10-15 07:41:49 +00:00
|
|
|
* A: json object, omitted if NULL
|
2018-03-30 09:12:57 +00:00
|
|
|
*
|
2015-01-13 14:06:16 +00:00
|
|
|
* m: a bitmap represented as a JSON array, must be non-NULL
|
|
|
|
* M: a bitmap represented as a JSON array, omitted if NULL
|
2014-09-22 14:35:02 +00:00
|
|
|
*
|
|
|
|
* The value corresponds to the selected type.
|
|
|
|
*
|
|
|
|
* Returns -1 on error. 1 on success, if at least one key:pair was valid 0
|
2015-01-12 15:35:17 +00:00
|
|
|
* in case of no error but nothing was filled.
|
2014-09-22 14:35:02 +00:00
|
|
|
*/
|
|
|
|
int
|
2015-01-12 15:35:17 +00:00
|
|
|
virJSONValueObjectAddVArgs(virJSONValuePtr obj,
|
|
|
|
va_list args)
|
2014-09-22 14:35:02 +00:00
|
|
|
{
|
|
|
|
char type;
|
|
|
|
char *key;
|
|
|
|
int ret = -1;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
while ((key = va_arg(args, char *)) != NULL) {
|
|
|
|
|
|
|
|
if (strlen(key) < 3) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("argument key '%s' is too short, missing type prefix"),
|
|
|
|
key);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = key[0];
|
|
|
|
key += 2;
|
|
|
|
|
|
|
|
/* This doesn't support maps, but no command uses those. */
|
|
|
|
switch (type) {
|
|
|
|
case 'S':
|
|
|
|
case 's': {
|
|
|
|
char *val = va_arg(args, char *);
|
|
|
|
if (!val) {
|
|
|
|
if (type == 'S')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("argument key '%s' must not have null value"),
|
|
|
|
key);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2015-01-12 15:35:17 +00:00
|
|
|
rc = virJSONValueObjectAppendString(obj, key, val);
|
2014-09-22 14:35:02 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case 'z':
|
|
|
|
case 'y':
|
|
|
|
case 'j':
|
|
|
|
case 'i': {
|
|
|
|
int val = va_arg(args, int);
|
|
|
|
|
|
|
|
if (val < 0 && (type == 'j' || type == 'y')) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("argument key '%s' must not be negative"),
|
|
|
|
key);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!val && (type == 'z' || type == 'y'))
|
|
|
|
continue;
|
|
|
|
|
2015-01-12 15:35:17 +00:00
|
|
|
rc = virJSONValueObjectAppendNumberInt(obj, key, val);
|
2014-09-22 14:35:02 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case 'p':
|
|
|
|
case 'u': {
|
|
|
|
unsigned int val = va_arg(args, unsigned int);
|
|
|
|
|
|
|
|
if (!val && type == 'p')
|
|
|
|
continue;
|
|
|
|
|
2015-01-12 15:35:17 +00:00
|
|
|
rc = virJSONValueObjectAppendNumberUint(obj, key, val);
|
2014-09-22 14:35:02 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case 'Z':
|
|
|
|
case 'Y':
|
|
|
|
case 'J':
|
|
|
|
case 'I': {
|
|
|
|
long long val = va_arg(args, long long);
|
|
|
|
|
|
|
|
if (val < 0 && (type == 'J' || type == 'Y')) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("argument key '%s' must not be negative"),
|
|
|
|
key);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!val && (type == 'Z' || type == 'Y'))
|
|
|
|
continue;
|
|
|
|
|
2015-01-12 15:35:17 +00:00
|
|
|
rc = virJSONValueObjectAppendNumberLong(obj, key, val);
|
2014-09-22 14:35:02 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case 'P':
|
|
|
|
case 'U': {
|
|
|
|
/* qemu silently truncates numbers larger than LLONG_MAX,
|
|
|
|
* so passing the full range of unsigned 64 bit integers
|
|
|
|
* is not safe here. Pass them as signed 64 bit integers
|
|
|
|
* instead.
|
|
|
|
*/
|
|
|
|
long long val = va_arg(args, long long);
|
|
|
|
|
|
|
|
if (!val && type == 'P')
|
|
|
|
continue;
|
|
|
|
|
2015-01-12 15:35:17 +00:00
|
|
|
rc = virJSONValueObjectAppendNumberLong(obj, key, val);
|
2014-09-22 14:35:02 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case 'd': {
|
|
|
|
double val = va_arg(args, double);
|
2015-01-12 15:35:17 +00:00
|
|
|
rc = virJSONValueObjectAppendNumberDouble(obj, key, val);
|
2014-09-22 14:35:02 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case 'B':
|
|
|
|
case 'b': {
|
|
|
|
int val = va_arg(args, int);
|
|
|
|
|
|
|
|
if (!val && type == 'B')
|
|
|
|
continue;
|
|
|
|
|
2015-01-12 15:35:17 +00:00
|
|
|
rc = virJSONValueObjectAppendBoolean(obj, key, val);
|
2014-09-22 14:35:02 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case 'n': {
|
2015-01-12 15:35:17 +00:00
|
|
|
rc = virJSONValueObjectAppendNull(obj, key);
|
2014-09-22 14:35:02 +00:00
|
|
|
} break;
|
|
|
|
|
2014-10-15 07:41:49 +00:00
|
|
|
case 'A':
|
2014-09-22 14:35:02 +00:00
|
|
|
case 'a': {
|
2018-03-30 09:12:57 +00:00
|
|
|
virJSONValuePtr *val = va_arg(args, virJSONValuePtr *);
|
2014-09-23 09:48:08 +00:00
|
|
|
|
2018-03-30 09:12:57 +00:00
|
|
|
if (!(*val)) {
|
2014-10-15 07:41:49 +00:00
|
|
|
if (type == 'A')
|
|
|
|
continue;
|
|
|
|
|
2014-09-23 09:48:08 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("argument key '%s' must not have null value"),
|
|
|
|
key);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2018-03-30 09:12:57 +00:00
|
|
|
if ((rc = virJSONValueObjectAppend(obj, key, *val)) == 0)
|
|
|
|
*val = NULL;
|
2014-09-22 14:35:02 +00:00
|
|
|
} break;
|
|
|
|
|
2015-01-13 14:06:16 +00:00
|
|
|
case 'M':
|
|
|
|
case 'm': {
|
|
|
|
virBitmapPtr map = va_arg(args, virBitmapPtr);
|
|
|
|
virJSONValuePtr jsonMap;
|
|
|
|
|
|
|
|
if (!map) {
|
|
|
|
if (type == 'M')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("argument key '%s' must not have null value"),
|
|
|
|
key);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(jsonMap = virJSONValueNewArrayFromBitmap(map)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if ((rc = virJSONValueObjectAppend(obj, key, jsonMap)) < 0)
|
|
|
|
virJSONValueFree(jsonMap);
|
|
|
|
} break;
|
|
|
|
|
2014-09-22 14:35:02 +00:00
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported data type '%c' for arg '%s'"), type, key - 2);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* verify that we added at least one key-value pair */
|
2015-01-12 15:35:17 +00:00
|
|
|
if (virJSONValueObjectKeysNumber(obj) == 0) {
|
2014-09-22 14:35:02 +00:00
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 1;
|
|
|
|
|
|
|
|
cleanup:
|
2015-01-12 15:35:17 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virJSONValueObjectAdd(virJSONValuePtr obj, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
va_start(args, obj);
|
|
|
|
ret = virJSONValueObjectAddVArgs(obj, args);
|
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virJSONValueObjectCreateVArgs(virJSONValuePtr *obj,
|
|
|
|
va_list args)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!(*obj = virJSONValueNewObject()))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* free the object on error, or if no value objects were added */
|
|
|
|
if ((ret = virJSONValueObjectAddVArgs(*obj, args)) <= 0) {
|
|
|
|
virJSONValueFree(*obj);
|
|
|
|
*obj = NULL;
|
|
|
|
}
|
|
|
|
|
2014-09-22 14:35:02 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virJSONValueObjectCreate(virJSONValuePtr *obj, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
va_start(args, obj);
|
|
|
|
ret = virJSONValueObjectCreateVArgs(obj, args);
|
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
void
|
|
|
|
virJSONValueFree(virJSONValuePtr value)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/util/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2018-05-10 12:25:57 +00:00
|
|
|
if (!value)
|
2009-11-03 18:59:18 +00:00
|
|
|
return;
|
|
|
|
|
2012-04-05 19:15:03 +00:00
|
|
|
switch ((virJSONType) value->type) {
|
2009-11-03 18:59:18 +00:00
|
|
|
case VIR_JSON_TYPE_OBJECT:
|
2013-05-21 07:58:16 +00:00
|
|
|
for (i = 0; i < value->data.object.npairs; i++) {
|
2009-11-03 18:59:18 +00:00
|
|
|
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:
|
2013-05-21 07:58:16 +00:00
|
|
|
for (i = 0; i < value->data.array.nvalues; i++)
|
2009-11-03 18:59:18 +00:00
|
|
|
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;
|
2012-04-05 19:15:03 +00:00
|
|
|
case VIR_JSON_TYPE_BOOLEAN:
|
|
|
|
case VIR_JSON_TYPE_NULL:
|
|
|
|
break;
|
2009-11-03 18:59:18 +00:00
|
|
|
}
|
2010-01-27 08:58:12 +00:00
|
|
|
|
|
|
|
VIR_FREE(value);
|
2009-11-03 18:59:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-16 09:19:32 +00:00
|
|
|
void
|
|
|
|
virJSONValueHashFree(void *opaque,
|
|
|
|
const void *name ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
virJSONValueFree(opaque);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
virJSONValuePtr
|
|
|
|
virJSONValueNewString(const char *data)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
virJSONValuePtr val;
|
|
|
|
|
|
|
|
if (!data)
|
|
|
|
return virJSONValueNewNull();
|
|
|
|
|
|
|
|
if (VIR_ALLOC(val) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
val->type = VIR_JSON_TYPE_STRING;
|
2013-05-24 07:19:51 +00:00
|
|
|
if (VIR_STRDUP(val->data.string, data) < 0) {
|
2009-11-03 18:59:18 +00:00
|
|
|
VIR_FREE(val);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
|
|
|
|
static virJSONValuePtr
|
|
|
|
virJSONValueNewNumber(const char *data)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
virJSONValuePtr val;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(val) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
val->type = VIR_JSON_TYPE_NUMBER;
|
2013-05-24 07:19:51 +00:00
|
|
|
if (VIR_STRDUP(val->data.number, data) < 0) {
|
2009-11-03 18:59:18 +00:00
|
|
|
VIR_FREE(val);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
|
|
|
|
virJSONValuePtr
|
|
|
|
virJSONValueNewNumberInt(int data)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
2018-07-13 17:54:58 +00:00
|
|
|
VIR_AUTOFREE(char *) str = NULL;
|
2009-11-03 18:59:18 +00:00
|
|
|
if (virAsprintf(&str, "%i", data) < 0)
|
|
|
|
return NULL;
|
2018-07-13 17:54:58 +00:00
|
|
|
return virJSONValueNewNumber(str);
|
2009-11-03 18:59:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
virJSONValuePtr
|
|
|
|
virJSONValueNewNumberUint(unsigned int data)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
2018-07-13 17:54:58 +00:00
|
|
|
VIR_AUTOFREE(char *) str = NULL;
|
2009-11-03 18:59:18 +00:00
|
|
|
if (virAsprintf(&str, "%u", data) < 0)
|
|
|
|
return NULL;
|
2018-07-13 17:54:58 +00:00
|
|
|
return virJSONValueNewNumber(str);
|
2009-11-03 18:59:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
virJSONValuePtr
|
|
|
|
virJSONValueNewNumberLong(long long data)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
2018-07-13 17:54:58 +00:00
|
|
|
VIR_AUTOFREE(char *) str = NULL;
|
2009-11-03 18:59:18 +00:00
|
|
|
if (virAsprintf(&str, "%lld", data) < 0)
|
|
|
|
return NULL;
|
2018-07-13 17:54:58 +00:00
|
|
|
return virJSONValueNewNumber(str);
|
2009-11-03 18:59:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
virJSONValuePtr
|
|
|
|
virJSONValueNewNumberUlong(unsigned long long data)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
2018-07-13 17:54:58 +00:00
|
|
|
VIR_AUTOFREE(char *) str = NULL;
|
2009-11-03 18:59:18 +00:00
|
|
|
if (virAsprintf(&str, "%llu", data) < 0)
|
|
|
|
return NULL;
|
2018-07-13 17:54:58 +00:00
|
|
|
return virJSONValueNewNumber(str);
|
2009-11-03 18:59:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
virJSONValuePtr
|
|
|
|
virJSONValueNewNumberDouble(double data)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
2018-07-13 17:54:58 +00:00
|
|
|
VIR_AUTOFREE(char *) str = NULL;
|
2012-08-11 19:13:00 +00:00
|
|
|
if (virDoubleToStr(&str, data) < 0)
|
2009-11-03 18:59:18 +00:00
|
|
|
return NULL;
|
2018-07-13 17:54:58 +00:00
|
|
|
return virJSONValueNewNumber(str);
|
2009-11-03 18:59:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
virJSONValuePtr
|
|
|
|
virJSONValueNewBoolean(int boolean_)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
virJSONValuePtr val;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(val) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
val->type = VIR_JSON_TYPE_BOOLEAN;
|
2009-12-23 03:02:26 +00:00
|
|
|
val->data.boolean = boolean_;
|
2009-11-03 18:59:18 +00:00
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
|
|
|
|
virJSONValuePtr
|
|
|
|
virJSONValueNewNull(void)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
virJSONValuePtr val;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(val) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
val->type = VIR_JSON_TYPE_NULL;
|
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
|
|
|
|
virJSONValuePtr
|
|
|
|
virJSONValueNewArray(void)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
virJSONValuePtr val;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(val) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
val->type = VIR_JSON_TYPE_ARRAY;
|
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
|
|
|
|
virJSONValuePtr
|
|
|
|
virJSONValueNewObject(void)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
virJSONValuePtr val;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(val) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
val->type = VIR_JSON_TYPE_OBJECT;
|
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
virJSONValueObjectAppend(virJSONValuePtr object,
|
|
|
|
const char *key,
|
|
|
|
virJSONValuePtr value)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
char *newkey;
|
|
|
|
|
|
|
|
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virJSONValueObjectHasKey(object, key))
|
|
|
|
return -1;
|
|
|
|
|
2013-05-24 07:19:51 +00:00
|
|
|
if (VIR_STRDUP(newkey, key) < 0)
|
2009-11-03 18:59:18 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
int
|
|
|
|
virJSONValueObjectAppendString(virJSONValuePtr object,
|
|
|
|
const char *key,
|
|
|
|
const char *value)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
virJSONValuePtr jvalue = virJSONValueNewString(value);
|
|
|
|
if (!jvalue)
|
|
|
|
return -1;
|
|
|
|
if (virJSONValueObjectAppend(object, key, jvalue) < 0) {
|
|
|
|
virJSONValueFree(jvalue);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
virJSONValueObjectAppendNumberInt(virJSONValuePtr object,
|
|
|
|
const char *key,
|
|
|
|
int number)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
virJSONValuePtr jvalue = virJSONValueNewNumberInt(number);
|
|
|
|
if (!jvalue)
|
|
|
|
return -1;
|
|
|
|
if (virJSONValueObjectAppend(object, key, jvalue) < 0) {
|
|
|
|
virJSONValueFree(jvalue);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
int
|
|
|
|
virJSONValueObjectAppendNumberUint(virJSONValuePtr object,
|
|
|
|
const char *key,
|
|
|
|
unsigned int number)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
virJSONValuePtr jvalue = virJSONValueNewNumberUint(number);
|
|
|
|
if (!jvalue)
|
|
|
|
return -1;
|
|
|
|
if (virJSONValueObjectAppend(object, key, jvalue) < 0) {
|
|
|
|
virJSONValueFree(jvalue);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
virJSONValueObjectAppendNumberLong(virJSONValuePtr object,
|
|
|
|
const char *key,
|
|
|
|
long long number)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
virJSONValuePtr jvalue = virJSONValueNewNumberLong(number);
|
|
|
|
if (!jvalue)
|
|
|
|
return -1;
|
|
|
|
if (virJSONValueObjectAppend(object, key, jvalue) < 0) {
|
|
|
|
virJSONValueFree(jvalue);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
virJSONValueObjectAppendNumberUlong(virJSONValuePtr object,
|
|
|
|
const char *key,
|
|
|
|
unsigned long long number)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
virJSONValuePtr jvalue = virJSONValueNewNumberUlong(number);
|
|
|
|
if (!jvalue)
|
|
|
|
return -1;
|
|
|
|
if (virJSONValueObjectAppend(object, key, jvalue) < 0) {
|
|
|
|
virJSONValueFree(jvalue);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
virJSONValueObjectAppendNumberDouble(virJSONValuePtr object,
|
|
|
|
const char *key,
|
|
|
|
double number)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
virJSONValuePtr jvalue = virJSONValueNewNumberDouble(number);
|
|
|
|
if (!jvalue)
|
|
|
|
return -1;
|
|
|
|
if (virJSONValueObjectAppend(object, key, jvalue) < 0) {
|
|
|
|
virJSONValueFree(jvalue);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
virJSONValueObjectAppendBoolean(virJSONValuePtr object,
|
|
|
|
const char *key,
|
|
|
|
int boolean_)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
2009-12-23 03:02:26 +00:00
|
|
|
virJSONValuePtr jvalue = virJSONValueNewBoolean(boolean_);
|
2009-11-03 18:59:18 +00:00
|
|
|
if (!jvalue)
|
|
|
|
return -1;
|
|
|
|
if (virJSONValueObjectAppend(object, key, jvalue) < 0) {
|
|
|
|
virJSONValueFree(jvalue);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
virJSONValueObjectAppendNull(virJSONValuePtr object,
|
|
|
|
const char *key)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
virJSONValuePtr jvalue = virJSONValueNewNull();
|
|
|
|
if (!jvalue)
|
|
|
|
return -1;
|
|
|
|
if (virJSONValueObjectAppend(object, key, jvalue) < 0) {
|
|
|
|
virJSONValueFree(jvalue);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
int
|
|
|
|
virJSONValueArrayAppend(virJSONValuePtr array,
|
|
|
|
virJSONValuePtr value)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
virJSONValueObjectHasKey(virJSONValuePtr object,
|
|
|
|
const char *key)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/util/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2009-11-03 18:59:18 +00:00
|
|
|
|
|
|
|
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
|
|
return -1;
|
|
|
|
|
2013-05-21 07:58:16 +00:00
|
|
|
for (i = 0; i < object->data.object.npairs; i++) {
|
2009-11-03 18:59:18 +00:00
|
|
|
if (STREQ(object->data.object.pairs[i].key, key))
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
|
|
|
|
virJSONValuePtr
|
|
|
|
virJSONValueObjectGet(virJSONValuePtr object,
|
|
|
|
const char *key)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/util/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2009-11-03 18:59:18 +00:00
|
|
|
|
|
|
|
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
|
|
return NULL;
|
|
|
|
|
2013-05-21 07:58:16 +00:00
|
|
|
for (i = 0; i < object->data.object.npairs; i++) {
|
2009-11-03 18:59:18 +00:00
|
|
|
if (STREQ(object->data.object.pairs[i].key, key))
|
|
|
|
return object->data.object.pairs[i].value;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
|
2016-10-03 18:45:13 +00:00
|
|
|
static virJSONValuePtr
|
|
|
|
virJSONValueObjectSteal(virJSONValuePtr object,
|
|
|
|
const char *key)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
virJSONValuePtr obj = NULL;
|
|
|
|
|
|
|
|
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)) {
|
|
|
|
VIR_STEAL_PTR(obj, object->data.object.pairs[i].value);
|
|
|
|
VIR_FREE(object->data.object.pairs[i].key);
|
|
|
|
VIR_DELETE_ELEMENT(object->data.object.pairs, i,
|
|
|
|
object->data.object.npairs);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-06-19 23:13:03 +00:00
|
|
|
/* Return the value associated with KEY within OBJECT, but return NULL
|
|
|
|
* if the key is missing or if value is not the correct TYPE. */
|
|
|
|
virJSONValuePtr
|
|
|
|
virJSONValueObjectGetByType(virJSONValuePtr object,
|
|
|
|
const char *key,
|
|
|
|
virJSONType type)
|
|
|
|
{
|
|
|
|
virJSONValuePtr value = virJSONValueObjectGet(object, key);
|
|
|
|
|
|
|
|
if (value && value->type == type)
|
|
|
|
return value;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-10-03 18:45:13 +00:00
|
|
|
/* Steal the value associated with KEY within OBJECT, but return NULL
|
|
|
|
* if the key is missing or if value is not the correct TYPE. */
|
|
|
|
static virJSONValuePtr
|
|
|
|
virJSONValueObjectStealByType(virJSONValuePtr object,
|
|
|
|
const char *key,
|
|
|
|
virJSONType type)
|
|
|
|
{
|
|
|
|
virJSONValuePtr value = virJSONValueObjectSteal(object, key);
|
|
|
|
|
|
|
|
if (value && value->type == type)
|
|
|
|
return value;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
int
|
|
|
|
virJSONValueObjectKeysNumber(virJSONValuePtr object)
|
2012-05-02 18:32:37 +00:00
|
|
|
{
|
|
|
|
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return object->data.object.npairs;
|
|
|
|
}
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
|
|
|
|
const char *
|
|
|
|
virJSONValueObjectGetKey(virJSONValuePtr object,
|
|
|
|
unsigned int n)
|
2012-05-02 18:32:37 +00:00
|
|
|
{
|
|
|
|
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (n >= object->data.object.npairs)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return object->data.object.pairs[n].key;
|
|
|
|
}
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
|
2013-04-26 14:59:02 +00:00
|
|
|
/* Remove the key-value pair tied to @key out of @object. If @value is
|
|
|
|
* not NULL, the dropped value object is returned instead of freed.
|
|
|
|
* Returns 1 on success, 0 if no key was found, and -1 on error. */
|
|
|
|
int
|
2014-06-16 13:24:26 +00:00
|
|
|
virJSONValueObjectRemoveKey(virJSONValuePtr object,
|
|
|
|
const char *key,
|
2013-04-26 14:59:02 +00:00
|
|
|
virJSONValuePtr *value)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/util/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2013-04-26 14:59:02 +00:00
|
|
|
|
|
|
|
if (value)
|
|
|
|
*value = NULL;
|
|
|
|
|
|
|
|
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
|
|
return -1;
|
|
|
|
|
2013-05-21 07:58:16 +00:00
|
|
|
for (i = 0; i < object->data.object.npairs; i++) {
|
2013-04-26 14:59:02 +00:00
|
|
|
if (STREQ(object->data.object.pairs[i].key, key)) {
|
|
|
|
if (value) {
|
|
|
|
*value = object->data.object.pairs[i].value;
|
|
|
|
object->data.object.pairs[i].value = NULL;
|
|
|
|
}
|
|
|
|
VIR_FREE(object->data.object.pairs[i].key);
|
|
|
|
virJSONValueFree(object->data.object.pairs[i].value);
|
|
|
|
VIR_DELETE_ELEMENT(object->data.object.pairs, i,
|
|
|
|
object->data.object.npairs);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
|
|
|
|
virJSONValuePtr
|
|
|
|
virJSONValueObjectGetValue(virJSONValuePtr object,
|
|
|
|
unsigned int n)
|
2012-05-02 18:32:37 +00:00
|
|
|
{
|
|
|
|
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (n >= object->data.object.npairs)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return object->data.object.pairs[n].value;
|
|
|
|
}
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
|
2017-06-26 09:32:35 +00:00
|
|
|
bool
|
|
|
|
virJSONValueIsObject(virJSONValuePtr object)
|
|
|
|
{
|
|
|
|
if (object)
|
|
|
|
return object->type == VIR_JSON_TYPE_OBJECT;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 13:48:11 +00:00
|
|
|
bool
|
|
|
|
virJSONValueIsArray(virJSONValuePtr array)
|
|
|
|
{
|
|
|
|
return array->type == VIR_JSON_TYPE_ARRAY;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-19 21:29:02 +00:00
|
|
|
size_t
|
2015-01-15 13:40:48 +00:00
|
|
|
virJSONValueArraySize(const virJSONValue *array)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
return array->data.array.nvalues;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
virJSONValuePtr
|
|
|
|
virJSONValueArrayGet(virJSONValuePtr array,
|
|
|
|
unsigned int element)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
if (array->type != VIR_JSON_TYPE_ARRAY)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (element >= array->data.array.nvalues)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return array->data.array.values[element];
|
|
|
|
}
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
|
2014-06-16 13:48:11 +00:00
|
|
|
virJSONValuePtr
|
|
|
|
virJSONValueArraySteal(virJSONValuePtr array,
|
|
|
|
unsigned int element)
|
|
|
|
{
|
|
|
|
virJSONValuePtr ret = NULL;
|
|
|
|
|
|
|
|
if (array->type != VIR_JSON_TYPE_ARRAY)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (element >= array->data.array.nvalues)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ret = array->data.array.values[element];
|
|
|
|
|
|
|
|
VIR_DELETE_ELEMENT(array->data.array.values,
|
|
|
|
element,
|
|
|
|
array->data.array.nvalues);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-10-17 11:44:16 +00:00
|
|
|
/**
|
|
|
|
* virJSONValueArrayForeachSteal:
|
|
|
|
* @array: array to iterate
|
|
|
|
* @cb: callback called on every member of the array
|
|
|
|
* @opaque: custom data for the callback
|
|
|
|
*
|
|
|
|
* Iterates members of the array and calls the callback on every single member.
|
|
|
|
* The return codes of the callback are interpreted as follows:
|
|
|
|
* 0: callback claims ownership of the array element and is responsible for
|
|
|
|
* freeing it
|
|
|
|
* 1: callback doesn't claim ownership of the element
|
|
|
|
* -1: callback doesn't claim ownership of the element and iteration does not
|
|
|
|
* continue
|
|
|
|
*
|
|
|
|
* Returns 0 if all members were iterated and/or stolen by the callback; -1
|
|
|
|
* on callback failure or if the JSON value object is not an array.
|
|
|
|
* The rest of the members stay in possession of the array and it's condensed.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virJSONValueArrayForeachSteal(virJSONValuePtr array,
|
|
|
|
virJSONArrayIteratorFunc cb,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
size_t j = 0;
|
|
|
|
int ret = 0;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (array->type != VIR_JSON_TYPE_ARRAY)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
for (i = 0; i < array->data.array.nvalues; i++) {
|
|
|
|
if ((rc = cb(i, array->data.array.values[i], opaque)) < 0) {
|
|
|
|
ret = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc == 0)
|
|
|
|
array->data.array.values[i] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* condense the remaining entries at the beginning */
|
|
|
|
for (i = 0; i < array->data.array.nvalues; i++) {
|
|
|
|
if (!array->data.array.values[i])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
array->data.array.values[j++] = array->data.array.values[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
array->data.array.nvalues = j;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
const char *
|
|
|
|
virJSONValueGetString(virJSONValuePtr string)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
if (string->type != VIR_JSON_TYPE_STRING)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return string->data.string;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-29 18:38:35 +00:00
|
|
|
const char *
|
|
|
|
virJSONValueGetNumberString(virJSONValuePtr number)
|
|
|
|
{
|
|
|
|
if (number->type != VIR_JSON_TYPE_NUMBER)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return number->data.number;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
int
|
|
|
|
virJSONValueGetNumberInt(virJSONValuePtr number,
|
|
|
|
int *value)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
if (number->type != VIR_JSON_TYPE_NUMBER)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virStrToLong_i(number->data.number, NULL, 10, value);
|
|
|
|
}
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
virJSONValueGetNumberUint(virJSONValuePtr number,
|
|
|
|
unsigned int *value)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
if (number->type != VIR_JSON_TYPE_NUMBER)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virStrToLong_ui(number->data.number, NULL, 10, value);
|
|
|
|
}
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
virJSONValueGetNumberLong(virJSONValuePtr number,
|
|
|
|
long long *value)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
if (number->type != VIR_JSON_TYPE_NUMBER)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virStrToLong_ll(number->data.number, NULL, 10, value);
|
|
|
|
}
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
virJSONValueGetNumberUlong(virJSONValuePtr number,
|
|
|
|
unsigned long long *value)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
if (number->type != VIR_JSON_TYPE_NUMBER)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virStrToLong_ull(number->data.number, NULL, 10, value);
|
|
|
|
}
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
virJSONValueGetNumberDouble(virJSONValuePtr number,
|
|
|
|
double *value)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
|
|
|
if (number->type != VIR_JSON_TYPE_NUMBER)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virStrToDouble(number->data.number, NULL, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
int
|
|
|
|
virJSONValueGetBoolean(virJSONValuePtr val,
|
|
|
|
bool *value)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
2011-05-05 11:48:31 +00:00
|
|
|
if (val->type != VIR_JSON_TYPE_BOOLEAN)
|
2009-11-03 18:59:18 +00:00
|
|
|
return -1;
|
|
|
|
|
2011-05-05 11:48:31 +00:00
|
|
|
*value = val->data.boolean;
|
|
|
|
return 0;
|
2009-11-03 18:59:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-13 14:06:16 +00:00
|
|
|
/**
|
|
|
|
* virJSONValueGetArrayAsBitmap:
|
|
|
|
* @val: JSON array to convert to bitmap
|
|
|
|
* @bitmap: New bitmap is allocated filled and returned via this argument
|
|
|
|
*
|
|
|
|
* Attempts a conversion of a JSON array to a bitmap. The members of the array
|
|
|
|
* must be non-negative integers for the conversion to succeed. This function
|
|
|
|
* does not report libvirt errors so that it can be used to probe that the
|
|
|
|
* array can be represented as a bitmap.
|
|
|
|
*
|
|
|
|
* Returns 0 on success and fills @bitmap; -1 on error and @bitmap is set to
|
|
|
|
* NULL.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virJSONValueGetArrayAsBitmap(const virJSONValue *val,
|
|
|
|
virBitmapPtr *bitmap)
|
|
|
|
{
|
|
|
|
virJSONValuePtr elem;
|
|
|
|
size_t i;
|
2018-07-13 17:54:58 +00:00
|
|
|
VIR_AUTOFREE(unsigned long long *) elems = NULL;
|
2015-01-13 14:06:16 +00:00
|
|
|
unsigned long long maxelem = 0;
|
|
|
|
|
|
|
|
*bitmap = NULL;
|
|
|
|
|
|
|
|
if (val->type != VIR_JSON_TYPE_ARRAY)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (VIR_ALLOC_N_QUIET(elems, val->data.array.nvalues) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* first pass converts array members to numbers and finds the maximum */
|
|
|
|
for (i = 0; i < val->data.array.nvalues; i++) {
|
|
|
|
elem = val->data.array.values[i];
|
|
|
|
|
|
|
|
if (elem->type != VIR_JSON_TYPE_NUMBER ||
|
|
|
|
virStrToLong_ullp(elem->data.number, NULL, 10, &elems[i]) < 0)
|
2018-07-13 17:54:58 +00:00
|
|
|
return -1;
|
2015-01-13 14:06:16 +00:00
|
|
|
|
|
|
|
if (elems[i] > maxelem)
|
|
|
|
maxelem = elems[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(*bitmap = virBitmapNewQuiet(maxelem + 1)))
|
2018-07-13 17:54:58 +00:00
|
|
|
return -1;
|
2015-01-13 14:06:16 +00:00
|
|
|
|
|
|
|
/* second pass sets the correct bits in the map */
|
|
|
|
for (i = 0; i < val->data.array.nvalues; i++)
|
|
|
|
ignore_value(virBitmapSetBit(*bitmap, elems[i]));
|
|
|
|
|
2018-07-13 17:54:58 +00:00
|
|
|
return 0;
|
2015-01-13 14:06:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virJSONValuePtr
|
|
|
|
virJSONValueNewArrayFromBitmap(virBitmapPtr bitmap)
|
|
|
|
{
|
|
|
|
virJSONValuePtr ret;
|
|
|
|
ssize_t pos = -1;
|
|
|
|
|
|
|
|
if (!(ret = virJSONValueNewArray()))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!bitmap)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
while ((pos = virBitmapNextSetBit(bitmap, pos)) > -1) {
|
|
|
|
virJSONValuePtr newelem;
|
|
|
|
|
|
|
|
if (!(newelem = virJSONValueNewNumberLong(pos)) ||
|
|
|
|
virJSONValueArrayAppend(ret, newelem) < 0) {
|
|
|
|
virJSONValueFree(newelem);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virJSONValueFree(ret);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-06-19 23:13:03 +00:00
|
|
|
bool
|
2014-06-16 13:24:26 +00:00
|
|
|
virJSONValueIsNull(virJSONValuePtr val)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
2015-06-19 23:13:03 +00:00
|
|
|
return val->type == VIR_JSON_TYPE_NULL;
|
2009-11-03 18:59:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
const char *
|
|
|
|
virJSONValueObjectGetString(virJSONValuePtr object,
|
|
|
|
const char *key)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
2015-06-19 23:13:03 +00:00
|
|
|
virJSONValuePtr val = virJSONValueObjectGet(object, key);
|
2009-11-03 18:59:18 +00:00
|
|
|
|
|
|
|
if (!val)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return virJSONValueGetString(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-01-31 10:54:31 +00:00
|
|
|
/**
|
|
|
|
* virJSONValueObjectGetStringOrNumber:
|
|
|
|
* @object: JSON value object
|
|
|
|
* @key: name of the property in @object to get
|
|
|
|
*
|
|
|
|
* Gets a property named @key from the JSON object @object. The value may be
|
|
|
|
* a number or a string and is returned as a string. In cases when the property
|
|
|
|
* is not present or is not a string or number NULL is returned.
|
|
|
|
*/
|
|
|
|
const char *
|
|
|
|
virJSONValueObjectGetStringOrNumber(virJSONValuePtr object,
|
|
|
|
const char *key)
|
|
|
|
{
|
|
|
|
virJSONValuePtr val = virJSONValueObjectGet(object, key);
|
|
|
|
|
|
|
|
if (!val)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (val->type == VIR_JSON_TYPE_STRING)
|
|
|
|
return val->data.string;
|
|
|
|
else if (val->type == VIR_JSON_TYPE_NUMBER)
|
|
|
|
return val->data.number;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
int
|
|
|
|
virJSONValueObjectGetNumberInt(virJSONValuePtr object,
|
|
|
|
const char *key,
|
|
|
|
int *value)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
2015-06-19 23:13:03 +00:00
|
|
|
virJSONValuePtr val = virJSONValueObjectGet(object, key);
|
2009-11-03 18:59:18 +00:00
|
|
|
|
|
|
|
if (!val)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virJSONValueGetNumberInt(val, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
int
|
|
|
|
virJSONValueObjectGetNumberUint(virJSONValuePtr object,
|
|
|
|
const char *key,
|
|
|
|
unsigned int *value)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
2015-06-19 23:13:03 +00:00
|
|
|
virJSONValuePtr val = virJSONValueObjectGet(object, key);
|
2009-11-03 18:59:18 +00:00
|
|
|
|
|
|
|
if (!val)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virJSONValueGetNumberUint(val, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
int
|
|
|
|
virJSONValueObjectGetNumberLong(virJSONValuePtr object,
|
|
|
|
const char *key,
|
|
|
|
long long *value)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
2015-06-19 23:13:03 +00:00
|
|
|
virJSONValuePtr val = virJSONValueObjectGet(object, key);
|
2009-11-03 18:59:18 +00:00
|
|
|
|
|
|
|
if (!val)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virJSONValueGetNumberLong(val, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
int
|
|
|
|
virJSONValueObjectGetNumberUlong(virJSONValuePtr object,
|
|
|
|
const char *key,
|
|
|
|
unsigned long long *value)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
2015-06-19 23:13:03 +00:00
|
|
|
virJSONValuePtr val = virJSONValueObjectGet(object, key);
|
2009-11-03 18:59:18 +00:00
|
|
|
|
|
|
|
if (!val)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virJSONValueGetNumberUlong(val, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
int
|
|
|
|
virJSONValueObjectGetNumberDouble(virJSONValuePtr object,
|
|
|
|
const char *key,
|
|
|
|
double *value)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
2015-06-19 23:13:03 +00:00
|
|
|
virJSONValuePtr val = virJSONValueObjectGet(object, key);
|
2009-11-03 18:59:18 +00:00
|
|
|
|
|
|
|
if (!val)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virJSONValueGetNumberDouble(val, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
int
|
|
|
|
virJSONValueObjectGetBoolean(virJSONValuePtr object,
|
|
|
|
const char *key,
|
|
|
|
bool *value)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
2015-06-19 23:13:03 +00:00
|
|
|
virJSONValuePtr val = virJSONValueObjectGet(object, key);
|
2009-11-03 18:59:18 +00:00
|
|
|
|
|
|
|
if (!val)
|
|
|
|
return -1;
|
|
|
|
|
2011-05-05 11:48:31 +00:00
|
|
|
return virJSONValueGetBoolean(val, value);
|
2009-11-03 18:59:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-06-19 23:13:03 +00:00
|
|
|
virJSONValuePtr
|
|
|
|
virJSONValueObjectGetObject(virJSONValuePtr object, const char *key)
|
|
|
|
{
|
|
|
|
return virJSONValueObjectGetByType(object, key, VIR_JSON_TYPE_OBJECT);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virJSONValuePtr
|
|
|
|
virJSONValueObjectGetArray(virJSONValuePtr object, const char *key)
|
|
|
|
{
|
|
|
|
return virJSONValueObjectGetByType(object, key, VIR_JSON_TYPE_ARRAY);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-10-03 18:45:13 +00:00
|
|
|
virJSONValuePtr
|
|
|
|
virJSONValueObjectStealArray(virJSONValuePtr object, const char *key)
|
|
|
|
{
|
|
|
|
return virJSONValueObjectStealByType(object, key, VIR_JSON_TYPE_ARRAY);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-28 07:01:30 +00:00
|
|
|
virJSONValuePtr
|
|
|
|
virJSONValueObjectStealObject(virJSONValuePtr object,
|
|
|
|
const char *key)
|
|
|
|
{
|
|
|
|
return virJSONValueObjectStealByType(object, key, VIR_JSON_TYPE_OBJECT);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 13:24:26 +00:00
|
|
|
int
|
|
|
|
virJSONValueObjectIsNull(virJSONValuePtr object,
|
|
|
|
const char *key)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
2015-06-19 23:13:03 +00:00
|
|
|
virJSONValuePtr val = virJSONValueObjectGet(object, key);
|
2009-11-03 18:59:18 +00:00
|
|
|
|
|
|
|
if (!val)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virJSONValueIsNull(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-13 15:43:30 +00:00
|
|
|
/**
|
|
|
|
* virJSONValueObjectForeachKeyValue:
|
|
|
|
* @object: JSON object to iterate
|
|
|
|
* @cb: callback to call on key-value pairs contained in the object
|
|
|
|
* @opaque: generic data for the callback
|
|
|
|
*
|
|
|
|
* Iterates all key=value pairs in @object. Iteration breaks if @cb returns
|
|
|
|
* negative value.
|
|
|
|
*
|
|
|
|
* Returns 0 if all elements were iterated, -2 if @cb returned negative value
|
|
|
|
* during iteration and -1 on generic errors.
|
|
|
|
*/
|
|
|
|
int
|
2016-12-14 14:25:31 +00:00
|
|
|
virJSONValueObjectForeachKeyValue(virJSONValuePtr object,
|
2015-01-13 15:43:30 +00:00
|
|
|
virJSONValueObjectIteratorFunc cb,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
for (i = 0; i < object->data.object.npairs; i++) {
|
|
|
|
virJSONObjectPairPtr elem = object->data.object.pairs + i;
|
|
|
|
|
|
|
|
if (cb(elem->key, elem->value, opaque) < 0)
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-08-21 10:23:41 +00:00
|
|
|
virJSONValuePtr
|
2016-07-27 08:39:23 +00:00
|
|
|
virJSONValueCopy(const virJSONValue *in)
|
2014-08-21 10:23:41 +00:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
virJSONValuePtr out = NULL;
|
|
|
|
|
|
|
|
if (!in)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
switch ((virJSONType) in->type) {
|
|
|
|
case VIR_JSON_TYPE_OBJECT:
|
|
|
|
out = virJSONValueNewObject();
|
|
|
|
if (!out)
|
|
|
|
return NULL;
|
|
|
|
for (i = 0; i < in->data.object.npairs; i++) {
|
|
|
|
virJSONValuePtr val = NULL;
|
|
|
|
if (!(val = virJSONValueCopy(in->data.object.pairs[i].value)))
|
|
|
|
goto error;
|
|
|
|
if (virJSONValueObjectAppend(out, in->data.object.pairs[i].key,
|
|
|
|
val) < 0) {
|
|
|
|
virJSONValueFree(val);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case VIR_JSON_TYPE_ARRAY:
|
|
|
|
out = virJSONValueNewArray();
|
|
|
|
if (!out)
|
|
|
|
return NULL;
|
|
|
|
for (i = 0; i < in->data.array.nvalues; i++) {
|
|
|
|
virJSONValuePtr val = NULL;
|
|
|
|
if (!(val = virJSONValueCopy(in->data.array.values[i])))
|
|
|
|
goto error;
|
|
|
|
if (virJSONValueArrayAppend(out, val) < 0) {
|
|
|
|
virJSONValueFree(val);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* No need to error out in the following cases */
|
|
|
|
case VIR_JSON_TYPE_STRING:
|
|
|
|
out = virJSONValueNewString(in->data.string);
|
|
|
|
break;
|
|
|
|
case VIR_JSON_TYPE_NUMBER:
|
|
|
|
out = virJSONValueNewNumber(in->data.number);
|
|
|
|
break;
|
|
|
|
case VIR_JSON_TYPE_BOOLEAN:
|
|
|
|
out = virJSONValueNewBoolean(in->data.boolean);
|
|
|
|
break;
|
|
|
|
case VIR_JSON_TYPE_NULL:
|
|
|
|
out = virJSONValueNewNull();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return out;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virJSONValueFree(out);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-05-11 11:59:47 +00:00
|
|
|
#if WITH_JANSSON
|
2018-07-31 14:51:47 +00:00
|
|
|
|
|
|
|
# include "virjsoncompat.h"
|
2018-05-02 15:17:01 +00:00
|
|
|
|
|
|
|
static virJSONValuePtr
|
|
|
|
virJSONValueFromJansson(json_t *json)
|
|
|
|
{
|
|
|
|
virJSONValuePtr ret = NULL;
|
|
|
|
const char *key;
|
|
|
|
json_t *cur;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
switch (json_typeof(json)) {
|
|
|
|
case JSON_OBJECT:
|
|
|
|
ret = virJSONValueNewObject();
|
|
|
|
if (!ret)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
json_object_foreach(json, key, cur) {
|
|
|
|
virJSONValuePtr val = virJSONValueFromJansson(cur);
|
|
|
|
if (!val)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virJSONValueObjectAppend(ret, key, val) < 0) {
|
|
|
|
virJSONValueFree(val);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case JSON_ARRAY:
|
|
|
|
ret = virJSONValueNewArray();
|
|
|
|
if (!ret)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
json_array_foreach(json, i, cur) {
|
|
|
|
virJSONValuePtr val = virJSONValueFromJansson(cur);
|
|
|
|
if (!val)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virJSONValueArrayAppend(ret, val) < 0) {
|
|
|
|
virJSONValueFree(val);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case JSON_STRING:
|
|
|
|
ret = virJSONValueNewString(json_string_value(json));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case JSON_INTEGER:
|
|
|
|
ret = virJSONValueNewNumberLong(json_integer_value(json));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case JSON_REAL:
|
|
|
|
ret = virJSONValueNewNumberDouble(json_real_value(json));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case JSON_TRUE:
|
|
|
|
ret = virJSONValueNewBoolean(true);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case JSON_FALSE:
|
|
|
|
ret = virJSONValueNewBoolean(false);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case JSON_NULL:
|
|
|
|
ret = virJSONValueNewNull();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virJSONValueFree(ret);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
virJSONValuePtr
|
|
|
|
virJSONValueFromString(const char *jsonstring)
|
|
|
|
{
|
|
|
|
virJSONValuePtr ret = NULL;
|
|
|
|
json_t *json;
|
|
|
|
json_error_t error;
|
|
|
|
size_t flags = JSON_REJECT_DUPLICATES |
|
|
|
|
JSON_DECODE_ANY;
|
|
|
|
|
2018-07-31 14:51:47 +00:00
|
|
|
if (virJSONInitialize() < 0)
|
|
|
|
return NULL;
|
|
|
|
|
2018-05-02 15:17:01 +00:00
|
|
|
if (!(json = json_loads(jsonstring, flags, &error))) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("failed to parse JSON %d:%d: %s"),
|
|
|
|
error.line, error.column, error.text);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = virJSONValueFromJansson(json);
|
|
|
|
json_decref(json);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static json_t *
|
|
|
|
virJSONValueToJansson(virJSONValuePtr object)
|
|
|
|
{
|
|
|
|
json_t *ret = NULL;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
switch ((virJSONType)object->type) {
|
|
|
|
case VIR_JSON_TYPE_OBJECT:
|
|
|
|
ret = json_object();
|
|
|
|
if (!ret)
|
|
|
|
goto no_memory;
|
|
|
|
for (i = 0; i < object->data.object.npairs; i++) {
|
|
|
|
virJSONObjectPairPtr cur = object->data.object.pairs + i;
|
|
|
|
json_t *val = virJSONValueToJansson(cur->value);
|
|
|
|
|
|
|
|
if (!val)
|
|
|
|
goto error;
|
|
|
|
if (json_object_set_new(ret, cur->key, val) < 0) {
|
|
|
|
json_decref(val);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_JSON_TYPE_ARRAY:
|
|
|
|
ret = json_array();
|
|
|
|
if (!ret)
|
|
|
|
goto no_memory;
|
|
|
|
for (i = 0; i < object->data.array.nvalues; i++) {
|
|
|
|
virJSONValuePtr cur = object->data.array.values[i];
|
|
|
|
json_t *val = virJSONValueToJansson(cur);
|
|
|
|
|
|
|
|
if (!val)
|
|
|
|
goto error;
|
|
|
|
if (json_array_append_new(ret, val) < 0) {
|
|
|
|
json_decref(val);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_JSON_TYPE_STRING:
|
|
|
|
ret = json_string(object->data.string);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_JSON_TYPE_NUMBER: {
|
|
|
|
long long ll_val;
|
|
|
|
double d_val;
|
|
|
|
if (virStrToLong_ll(object->data.number, NULL, 10, &ll_val) < 0) {
|
|
|
|
if (virStrToDouble(object->data.number, NULL, &d_val) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("JSON value is not a number"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
ret = json_real(d_val);
|
|
|
|
} else {
|
|
|
|
ret = json_integer(ll_val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_JSON_TYPE_BOOLEAN:
|
|
|
|
ret = json_boolean(object->data.boolean);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_JSON_TYPE_NULL:
|
|
|
|
ret = json_null();
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
virReportEnumRangeError(virJSONType, object->type);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (!ret)
|
|
|
|
goto no_memory;
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
no_memory:
|
|
|
|
virReportOOMError();
|
|
|
|
error:
|
|
|
|
json_decref(ret);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
virJSONValueToString(virJSONValuePtr object,
|
|
|
|
bool pretty)
|
|
|
|
{
|
|
|
|
size_t flags = JSON_ENCODE_ANY;
|
|
|
|
json_t *json;
|
|
|
|
char *str = NULL;
|
|
|
|
|
2018-07-31 14:51:47 +00:00
|
|
|
if (virJSONInitialize() < 0)
|
|
|
|
return NULL;
|
|
|
|
|
2018-05-02 15:17:01 +00:00
|
|
|
if (pretty)
|
|
|
|
flags |= JSON_INDENT(2);
|
|
|
|
else
|
|
|
|
flags |= JSON_COMPACT;
|
|
|
|
|
|
|
|
json = virJSONValueToJansson(object);
|
|
|
|
if (!json)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
str = json_dumps(json, flags);
|
|
|
|
if (!str)
|
|
|
|
virReportOOMError();
|
|
|
|
json_decref(json);
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-11-03 18:59:18 +00:00
|
|
|
#else
|
2014-06-16 13:24:26 +00:00
|
|
|
virJSONValuePtr
|
|
|
|
virJSONValueFromString(const char *jsonstring ATTRIBUTE_UNUSED)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("No JSON parser implementation is available"));
|
2009-11-03 18:59:18 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2014-06-16 13:24:26 +00:00
|
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
virJSONValueToString(virJSONValuePtr object ATTRIBUTE_UNUSED,
|
|
|
|
bool pretty ATTRIBUTE_UNUSED)
|
2009-11-03 18:59:18 +00:00
|
|
|
{
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("No JSON parser implementation is available"));
|
2009-11-03 18:59:18 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif
|
2016-11-30 09:46:57 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virJSONStringReformat:
|
|
|
|
* @jsonstr: string to reformat
|
|
|
|
* @pretty: use the pretty formatter
|
|
|
|
*
|
|
|
|
* Reformats a JSON string by passing it to the parser and then to the
|
|
|
|
* formatter. If @pretty is true the JSON is formatted for human eye
|
|
|
|
* compatibility.
|
|
|
|
*
|
|
|
|
* Returns the reformatted JSON string on success; NULL and a libvirt error on
|
|
|
|
* failure.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
virJSONStringReformat(const char *jsonstr,
|
|
|
|
bool pretty)
|
|
|
|
{
|
2018-07-13 17:54:59 +00:00
|
|
|
VIR_AUTOPTR(virJSONValue) json = NULL;
|
2016-11-30 09:46:57 +00:00
|
|
|
|
|
|
|
if (!(json = virJSONValueFromString(jsonstr)))
|
|
|
|
return NULL;
|
|
|
|
|
2018-07-13 17:54:59 +00:00
|
|
|
return virJSONValueToString(json, pretty);
|
2016-11-30 09:46:57 +00:00
|
|
|
}
|
2017-06-26 14:29:04 +00:00
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
virJSONValueObjectDeflattenWorker(const char *key,
|
|
|
|
virJSONValuePtr value,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
virJSONValuePtr retobj = opaque;
|
|
|
|
virJSONValuePtr newval = NULL;
|
2017-06-27 11:48:56 +00:00
|
|
|
virJSONValuePtr existobj;
|
|
|
|
char **tokens = NULL;
|
|
|
|
size_t ntokens = 0;
|
|
|
|
int ret = -1;
|
2017-06-26 14:29:04 +00:00
|
|
|
|
2017-06-27 11:48:56 +00:00
|
|
|
/* non-nested keys only need to be copied */
|
|
|
|
if (!strchr(key, '.')) {
|
2017-06-26 17:37:18 +00:00
|
|
|
|
|
|
|
if (virJSONValueIsObject(value))
|
|
|
|
newval = virJSONValueObjectDeflatten(value);
|
|
|
|
else
|
|
|
|
newval = virJSONValueCopy(value);
|
|
|
|
|
|
|
|
if (!newval)
|
2017-06-27 11:48:56 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virJSONValueObjectHasKey(retobj, key)) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("can't deflatten colliding key '%s'"), key);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virJSONValueObjectAppend(retobj, key, newval) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
return 0;
|
2017-06-26 14:29:04 +00:00
|
|
|
}
|
|
|
|
|
2017-06-27 11:48:56 +00:00
|
|
|
if (!(tokens = virStringSplitCount(key, ".", 2, &ntokens)))
|
|
|
|
goto cleanup;
|
2017-06-26 14:29:04 +00:00
|
|
|
|
2017-06-27 11:48:56 +00:00
|
|
|
if (ntokens != 2) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("invalid nested value key '%s'"), key);
|
|
|
|
goto cleanup;
|
2017-06-26 14:29:04 +00:00
|
|
|
}
|
|
|
|
|
2017-06-27 11:48:56 +00:00
|
|
|
if (!(existobj = virJSONValueObjectGet(retobj, tokens[0]))) {
|
|
|
|
if (!(existobj = virJSONValueNewObject()))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virJSONValueObjectAppend(retobj, tokens[0], existobj) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if (!virJSONValueIsObject(existobj)) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
|
|
|
_("mixing nested objects and values is forbidden in "
|
|
|
|
"JSON deflattening"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = virJSONValueObjectDeflattenWorker(tokens[1], value, existobj);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virStringListFreeCount(tokens, ntokens);
|
|
|
|
virJSONValueFree(newval);
|
|
|
|
|
|
|
|
return ret;
|
2017-06-26 14:29:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virJSONValueObjectDeflatten:
|
|
|
|
*
|
|
|
|
* In some cases it's possible to nest JSON objects by prefixing object members
|
|
|
|
* with the parent object name followed by the dot and then the attribute name
|
|
|
|
* rather than directly using a nested value object (e.g qemu's JSON
|
|
|
|
* pseudo-protocol in backing file definition).
|
|
|
|
*
|
|
|
|
* This function will attempt to reverse the process and provide a nested json
|
|
|
|
* hierarchy so that the parsers can be kept simple and we still can use the
|
|
|
|
* weird syntax some users might use.
|
|
|
|
*/
|
|
|
|
virJSONValuePtr
|
|
|
|
virJSONValueObjectDeflatten(virJSONValuePtr json)
|
|
|
|
{
|
2018-07-13 17:54:59 +00:00
|
|
|
VIR_AUTOPTR(virJSONValue) deflattened = NULL;
|
2017-06-26 16:42:07 +00:00
|
|
|
virJSONValuePtr ret = NULL;
|
2017-06-26 14:29:04 +00:00
|
|
|
|
2017-06-26 16:42:07 +00:00
|
|
|
if (!(deflattened = virJSONValueNewObject()))
|
2017-06-26 14:29:04 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (virJSONValueObjectForeachKeyValue(json,
|
|
|
|
virJSONValueObjectDeflattenWorker,
|
2017-06-26 16:42:07 +00:00
|
|
|
deflattened) < 0)
|
2018-07-13 17:54:59 +00:00
|
|
|
return NULL;
|
2017-06-26 16:42:07 +00:00
|
|
|
|
2017-06-27 11:48:56 +00:00
|
|
|
VIR_STEAL_PTR(ret, deflattened);
|
2017-06-26 16:42:07 +00:00
|
|
|
|
2017-06-26 14:29:04 +00:00
|
|
|
return ret;
|
|
|
|
}
|