mirror of
https://github.com/archlinuxarm/PKGBUILDs.git
synced 2024-11-08 22:45:43 +00:00
578 lines
15 KiB
Diff
578 lines
15 KiB
Diff
From 37b2c6cd84d9c73b5b0fba789f1b808cde100b56 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?J=C3=A1n=20Tomko?= <jtomko@redhat.com>
|
|
Date: Mon, 13 Aug 2018 13:40:11 +0200
|
|
Subject: [PATCH 13/16] Revert "Remove functions using yajl"
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
This reverts commit bf114decb34f21cd225ead6dc4d929d35a8c5fe5.
|
|
|
|
Jansson cannot parse QEMU's quirky JSON.
|
|
Revert back to yajl.
|
|
|
|
https://bugzilla.redhat.com/show_bug.cgi?id=1614569
|
|
|
|
Signed-off-by: Ján Tomko <jtomko@redhat.com>
|
|
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
|
|
---
|
|
src/util/virjson.c | 529 ++++++++++++++++++++++++++++++++++++++++++++-
|
|
1 file changed, 528 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/src/util/virjson.c b/src/util/virjson.c
|
|
index 80274bc6c5..608ba85d67 100644
|
|
--- a/src/util/virjson.c
|
|
+++ b/src/util/virjson.c
|
|
@@ -29,6 +29,22 @@
|
|
#include "virstring.h"
|
|
#include "virutil.h"
|
|
|
|
+#if WITH_YAJL
|
|
+# include <yajl/yajl_gen.h>
|
|
+# include <yajl/yajl_parse.h>
|
|
+
|
|
+# ifdef WITH_YAJL2
|
|
+# define yajl_size_t size_t
|
|
+# define VIR_YAJL_STATUS_OK(status) ((status) == yajl_status_ok)
|
|
+# else
|
|
+# define yajl_size_t unsigned int
|
|
+# define yajl_complete_parse yajl_parse_complete
|
|
+# define VIR_YAJL_STATUS_OK(status) \
|
|
+ ((status) == yajl_status_ok || (status) == yajl_status_insufficient_data)
|
|
+# endif
|
|
+
|
|
+#endif
|
|
+
|
|
/* XXX fixme */
|
|
#define VIR_FROM_THIS VIR_FROM_NONE
|
|
|
|
@@ -72,6 +88,23 @@ struct _virJSONValue {
|
|
};
|
|
|
|
|
|
+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;
|
|
+ size_t nstate;
|
|
+ int wrap;
|
|
+};
|
|
+
|
|
+
|
|
virJSONType
|
|
virJSONValueGetType(const virJSONValue *value)
|
|
{
|
|
@@ -1458,7 +1491,501 @@ virJSONValueCopy(const virJSONValue *in)
|
|
}
|
|
|
|
|
|
-#if WITH_JANSSON
|
|
+#if WITH_YAJL
|
|
+static int
|
|
+virJSONParserInsertValue(virJSONParserPtr parser,
|
|
+ virJSONValuePtr value)
|
|
+{
|
|
+ if (!parser->head) {
|
|
+ parser->head = value;
|
|
+ } else {
|
|
+ virJSONParserStatePtr state;
|
|
+ if (!parser->nstate) {
|
|
+ VIR_DEBUG("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_DEBUG("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_DEBUG("unexpected key when inserting array value");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (virJSONValueArrayAppend(state->value,
|
|
+ value) < 0)
|
|
+ return -1;
|
|
+ } break;
|
|
+
|
|
+ default:
|
|
+ VIR_DEBUG("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,
|
|
+ yajl_size_t l)
|
|
+{
|
|
+ virJSONParserPtr parser = ctx;
|
|
+ char *str;
|
|
+ virJSONValuePtr value;
|
|
+
|
|
+ if (VIR_STRNDUP(str, s, l) < 0)
|
|
+ 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,
|
|
+ yajl_size_t 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,
|
|
+ yajl_size_t 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;
|
|
+ if (VIR_STRNDUP(state->key, (const char *)stringVal, stringLen) < 0)
|
|
+ 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;
|
|
+ }
|
|
+
|
|
+ VIR_DELETE_ELEMENT(parser->state, parser->nstate - 1, 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 - parser->wrap))
|
|
+ return 0;
|
|
+
|
|
+ state = &(parser->state[parser->nstate-1]);
|
|
+ if (state->key) {
|
|
+ VIR_FREE(state->key);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ VIR_DELETE_ELEMENT(parser->state, parser->nstate - 1, 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_handle hand;
|
|
+ virJSONParser parser = { NULL, NULL, 0, 0 };
|
|
+ virJSONValuePtr ret = NULL;
|
|
+ int rc;
|
|
+ size_t len = strlen(jsonstring);
|
|
+# ifndef WITH_YAJL2
|
|
+ yajl_parser_config cfg = { 0, 1 }; /* Match yajl 2 default behavior */
|
|
+ VIR_AUTOPTR(virJSONValue) tmp = NULL;
|
|
+# endif
|
|
+
|
|
+ VIR_DEBUG("string=%s", jsonstring);
|
|
+
|
|
+# ifdef WITH_YAJL2
|
|
+ hand = yajl_alloc(&parserCallbacks, NULL, &parser);
|
|
+# else
|
|
+ hand = yajl_alloc(&parserCallbacks, &cfg, NULL, &parser);
|
|
+# endif
|
|
+ if (!hand) {
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
+ _("Unable to create JSON parser"));
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
+ /* Yajl 2 is nice enough to default to rejecting trailing garbage.
|
|
+ * Yajl 1.0.12 has yajl_get_bytes_consumed to make that detection
|
|
+ * simpler. But we're stuck with yajl 1.0.7 on RHEL 6, which
|
|
+ * happily quits parsing at the end of a valid JSON construct,
|
|
+ * with no visibility into how much more input remains. Wrapping
|
|
+ * things in an array forces yajl to confess the truth. */
|
|
+# ifdef WITH_YAJL2
|
|
+ rc = yajl_parse(hand, (const unsigned char *)jsonstring, len);
|
|
+# else
|
|
+ rc = yajl_parse(hand, (const unsigned char *)"[", 1);
|
|
+ parser.wrap = 1;
|
|
+ if (VIR_YAJL_STATUS_OK(rc))
|
|
+ rc = yajl_parse(hand, (const unsigned char *)jsonstring, len);
|
|
+ parser.wrap = 0;
|
|
+ if (VIR_YAJL_STATUS_OK(rc))
|
|
+ rc = yajl_parse(hand, (const unsigned char *)"]", 1);
|
|
+# endif
|
|
+ if (!VIR_YAJL_STATUS_OK(rc) ||
|
|
+ yajl_complete_parse(hand) != yajl_status_ok) {
|
|
+ unsigned char *errstr = yajl_get_error(hand, 1,
|
|
+ (const unsigned char*)jsonstring,
|
|
+ strlen(jsonstring));
|
|
+
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
+ _("cannot parse json %s: %s"),
|
|
+ jsonstring, (const char*) errstr);
|
|
+ yajl_free_error(hand, errstr);
|
|
+ virJSONValueFree(parser.head);
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
+ if (parser.nstate != 0) {
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
+ _("cannot parse json %s: unterminated string/map/array"),
|
|
+ jsonstring);
|
|
+ virJSONValueFree(parser.head);
|
|
+ } else {
|
|
+ ret = parser.head;
|
|
+# ifndef WITH_YAJL2
|
|
+ /* Undo the array wrapping above */
|
|
+ tmp = ret;
|
|
+ ret = NULL;
|
|
+ if (virJSONValueArraySize(tmp) > 1)
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
+ _("cannot parse json %s: too many items present"),
|
|
+ jsonstring);
|
|
+ else
|
|
+ ret = virJSONValueArraySteal(tmp, 0);
|
|
+# endif
|
|
+ }
|
|
+
|
|
+ cleanup:
|
|
+ yajl_free(hand);
|
|
+
|
|
+ if (parser.nstate) {
|
|
+ size_t i;
|
|
+ for (i = 0; i < parser.nstate; i++)
|
|
+ VIR_FREE(parser.state[i].key);
|
|
+ VIR_FREE(parser.state);
|
|
+ }
|
|
+
|
|
+ VIR_DEBUG("result=%p", ret);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+
|
|
+static int
|
|
+virJSONValueToStringOne(virJSONValuePtr object,
|
|
+ yajl_gen g)
|
|
+{
|
|
+ size_t 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,
|
|
+ bool pretty)
|
|
+{
|
|
+ yajl_gen g;
|
|
+ const unsigned char *str;
|
|
+ char *ret = NULL;
|
|
+ yajl_size_t len;
|
|
+# ifndef WITH_YAJL2
|
|
+ yajl_gen_config conf = { pretty ? 1 : 0, pretty ? " " : " "};
|
|
+# endif
|
|
+
|
|
+ VIR_DEBUG("object=%p", object);
|
|
+
|
|
+# ifdef WITH_YAJL2
|
|
+ g = yajl_gen_alloc(NULL);
|
|
+ if (g) {
|
|
+ yajl_gen_config(g, yajl_gen_beautify, pretty ? 1 : 0);
|
|
+ yajl_gen_config(g, yajl_gen_indent_string, pretty ? " " : " ");
|
|
+ yajl_gen_config(g, yajl_gen_validate_utf8, 1);
|
|
+ }
|
|
+# else
|
|
+ g = yajl_gen_alloc(&conf, NULL);
|
|
+# endif
|
|
+ if (!g) {
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
+ _("Unable to create JSON formatter"));
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
+ if (virJSONValueToStringOne(object, g) < 0) {
|
|
+ virReportOOMError();
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
+ if (yajl_gen_get_buf(g, &str, &len) != yajl_gen_status_ok) {
|
|
+ virReportOOMError();
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
+ ignore_value(VIR_STRDUP(ret, (const char *)str));
|
|
+
|
|
+ cleanup:
|
|
+ yajl_gen_free(g);
|
|
+
|
|
+ VIR_DEBUG("result=%s", NULLSTR(ret));
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+
|
|
+#elif WITH_JANSSON
|
|
# include <jansson.h>
|
|
|
|
static virJSONValuePtr
|
|
--
|
|
2.18.0
|
|
|