From 58f61d24a46948e01771b4ec2b1eaed8d35c6bf7 Mon Sep 17 00:00:00 2001 From: Peter Krempa Date: Tue, 13 Jan 2015 15:06:16 +0100 Subject: [PATCH] util: json: Add functions to convert JSON arrays from/to virBitmaps To be able to easily represent nodesets and other data stored in virBitmaps in libvirt, this patch introduces a set of helpers that allow to convert the bitmap to and from JSON value objects. --- src/libvirt_private.syms | 2 + src/util/virjson.c | 113 +++++++++++++++++++++++++++++++++++++++ src/util/virjson.h | 4 ++ 3 files changed, 119 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 2908a1c231..499da505dd 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1516,6 +1516,7 @@ virJSONValueArrayGet; virJSONValueArraySize; virJSONValueFree; virJSONValueFromString; +virJSONValueGetArrayAsBitmap; virJSONValueGetBoolean; virJSONValueGetNumberDouble; virJSONValueGetNumberInt; @@ -1525,6 +1526,7 @@ virJSONValueGetNumberUlong; virJSONValueGetString; virJSONValueIsNull; virJSONValueNewArray; +virJSONValueNewArrayFromBitmap; virJSONValueNewBoolean; virJSONValueNewNull; virJSONValueNewNumberDouble; diff --git a/src/util/virjson.c b/src/util/virjson.c index fe3357a6e2..1bb2653581 100644 --- a/src/util/virjson.c +++ b/src/util/virjson.c @@ -99,6 +99,8 @@ struct _virJSONParser { * * a: json object, must be non-NULL * A: json object, omitted if NULL + * m: a bitmap represented as a JSON array, must be non-NULL + * M: a bitmap represented as a JSON array, omitted if NULL * * The value corresponds to the selected type. * @@ -242,6 +244,28 @@ virJSONValueObjectAddVArgs(virJSONValuePtr obj, rc = virJSONValueObjectAppend(obj, key, val); } break; + 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; + default: virReportError(VIR_ERR_INTERNAL_ERROR, _("unsupported data type '%c' for arg '%s'"), type, key - 2); @@ -943,6 +967,95 @@ virJSONValueGetBoolean(virJSONValuePtr val, } +/** + * 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) +{ + int ret = -1; + virJSONValuePtr elem; + size_t i; + unsigned long long *elems = NULL; + 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) + goto cleanup; + + if (elems[i] > maxelem) + maxelem = elems[i]; + } + + if (!(*bitmap = virBitmapNewQuiet(maxelem + 1))) + goto cleanup; + + /* second pass sets the correct bits in the map */ + for (i = 0; i < val->data.array.nvalues; i++) + ignore_value(virBitmapSetBit(*bitmap, elems[i])); + + ret = 0; + + cleanup: + VIR_FREE(elems); + + return ret; +} + + +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; +} + + int virJSONValueIsNull(virJSONValuePtr val) { diff --git a/src/util/virjson.h b/src/util/virjson.h index fc05ad9f11..57010b0106 100644 --- a/src/util/virjson.h +++ b/src/util/virjson.h @@ -25,6 +25,7 @@ # define __VIR_JSON_H_ # include "internal.h" +# include "virbitmap.h" # include @@ -102,6 +103,7 @@ virJSONValuePtr virJSONValueNewBoolean(int boolean); virJSONValuePtr virJSONValueNewNull(void); virJSONValuePtr virJSONValueNewArray(void); virJSONValuePtr virJSONValueNewObject(void); +virJSONValuePtr virJSONValueNewArrayFromBitmap(virBitmapPtr bitmap); int virJSONValueObjectAppend(virJSONValuePtr object, const char *key, virJSONValuePtr value); int virJSONValueArrayAppend(virJSONValuePtr object, virJSONValuePtr value); @@ -125,6 +127,8 @@ 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, bool *value); +int virJSONValueGetArrayAsBitmap(const virJSONValue *val, virBitmapPtr *bitmap) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); int virJSONValueIsNull(virJSONValuePtr object); const char *virJSONValueObjectGetString(virJSONValuePtr object, const char *key); -- GitLab