aboutsummaryrefslogtreecommitdiffstats
path: root/qobject
diff options
context:
space:
mode:
authorTimos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>2023-10-10 11:40:56 +0000
committerTimos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>2023-10-10 11:40:56 +0000
commite02cda008591317b1625707ff8e115a4841aa889 (patch)
treeaee302e3cf8b59ec2d32ec481be3d1afddfc8968 /qobject
parentcc668e6b7e0ffd8c9d130513d12053cf5eda1d3b (diff)
Introduce Virtio-loopback epsilon release:
Epsilon release introduces a new compatibility layer which make virtio-loopback design to work with QEMU and rust-vmm vhost-user backend without require any changes. Signed-off-by: Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com> Change-Id: I52e57563e08a7d0bdc002f8e928ee61ba0c53dd9
Diffstat (limited to 'qobject')
-rw-r--r--qobject/block-qdict.c738
-rw-r--r--qobject/json-lexer.c365
-rw-r--r--qobject/json-parser-int.h54
-rw-r--r--qobject/json-parser.c590
-rw-r--r--qobject/json-streamer.c134
-rw-r--r--qobject/json-writer.c247
-rw-r--r--qobject/meson.build4
-rw-r--r--qobject/qbool.c58
-rw-r--r--qobject/qdict.c444
-rw-r--r--qobject/qjson.c232
-rw-r--r--qobject/qlist.c184
-rw-r--r--qobject/qlit.c125
-rw-r--r--qobject/qnull.c31
-rw-r--r--qobject/qnum.c241
-rw-r--r--qobject/qobject-internal.h39
-rw-r--r--qobject/qobject.c72
-rw-r--r--qobject/qstring.c102
17 files changed, 3660 insertions, 0 deletions
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
new file mode 100644
index 000000000..1487cc5dd
--- /dev/null
+++ b/qobject/block-qdict.c
@@ -0,0 +1,738 @@
+/*
+ * Special QDict functions used by the block layer
+ *
+ * Copyright (c) 2013-2018 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "block/qdict.h"
+#include "qapi/qmp/qbool.h"
+#include "qapi/qmp/qlist.h"
+#include "qapi/qmp/qnum.h"
+#include "qapi/qmp/qstring.h"
+#include "qapi/qobject-input-visitor.h"
+#include "qemu/cutils.h"
+#include "qapi/error.h"
+
+/**
+ * qdict_copy_default(): If no entry mapped by 'key' exists in 'dst' yet, the
+ * value of 'key' in 'src' is copied there (and the refcount increased
+ * accordingly).
+ */
+void qdict_copy_default(QDict *dst, QDict *src, const char *key)
+{
+ QObject *val;
+
+ if (qdict_haskey(dst, key)) {
+ return;
+ }
+
+ val = qdict_get(src, key);
+ if (val) {
+ qdict_put_obj(dst, key, qobject_ref(val));
+ }
+}
+
+/**
+ * qdict_set_default_str(): If no entry mapped by 'key' exists in 'dst' yet, a
+ * new QString initialised by 'val' is put there.
+ */
+void qdict_set_default_str(QDict *dst, const char *key, const char *val)
+{
+ if (qdict_haskey(dst, key)) {
+ return;
+ }
+
+ qdict_put_str(dst, key, val);
+}
+
+static void qdict_flatten_qdict(QDict *qdict, QDict *target,
+ const char *prefix);
+
+static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix)
+{
+ QObject *value;
+ const QListEntry *entry;
+ QDict *dict_val;
+ QList *list_val;
+ char *new_key;
+ int i;
+
+ /* This function is never called with prefix == NULL, i.e., it is always
+ * called from within qdict_flatten_q(list|dict)(). Therefore, it does not
+ * need to remove list entries during the iteration (the whole list will be
+ * deleted eventually anyway from qdict_flatten_qdict()). */
+ assert(prefix);
+
+ entry = qlist_first(qlist);
+
+ for (i = 0; entry; entry = qlist_next(entry), i++) {
+ value = qlist_entry_obj(entry);
+ dict_val = qobject_to(QDict, value);
+ list_val = qobject_to(QList, value);
+ new_key = g_strdup_printf("%s.%i", prefix, i);
+
+ /*
+ * Flatten non-empty QDict and QList recursively into @target,
+ * copy other objects to @target
+ */
+ if (dict_val && qdict_size(dict_val)) {
+ qdict_flatten_qdict(dict_val, target, new_key);
+ } else if (list_val && !qlist_empty(list_val)) {
+ qdict_flatten_qlist(list_val, target, new_key);
+ } else {
+ qdict_put_obj(target, new_key, qobject_ref(value));
+ }
+
+ g_free(new_key);
+ }
+}
+
+static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
+{
+ QObject *value;
+ const QDictEntry *entry, *next;
+ QDict *dict_val;
+ QList *list_val;
+ char *key, *new_key;
+
+ entry = qdict_first(qdict);
+
+ while (entry != NULL) {
+ next = qdict_next(qdict, entry);
+ value = qdict_entry_value(entry);
+ dict_val = qobject_to(QDict, value);
+ list_val = qobject_to(QList, value);
+
+ if (prefix) {
+ key = new_key = g_strdup_printf("%s.%s", prefix, entry->key);
+ } else {
+ key = entry->key;
+ new_key = NULL;
+ }
+
+ /*
+ * Flatten non-empty QDict and QList recursively into @target,
+ * copy other objects to @target.
+ * On the root level (if @qdict == @target), remove flattened
+ * nested QDicts and QLists from @qdict.
+ *
+ * (Note that we do not need to remove entries from nested
+ * dicts or lists. Their reference count is decremented on
+ * the root level, so there are no leaks. In fact, if they
+ * have a reference count greater than one, we are probably
+ * well advised not to modify them altogether.)
+ */
+ if (dict_val && qdict_size(dict_val)) {
+ qdict_flatten_qdict(dict_val, target, key);
+ if (target == qdict) {
+ qdict_del(qdict, entry->key);
+ }
+ } else if (list_val && !qlist_empty(list_val)) {
+ qdict_flatten_qlist(list_val, target, key);
+ if (target == qdict) {
+ qdict_del(qdict, entry->key);
+ }
+ } else if (target != qdict) {
+ qdict_put_obj(target, key, qobject_ref(value));
+ }
+
+ g_free(new_key);
+ entry = next;
+ }
+}
+
+/**
+ * qdict_flatten(): For each nested non-empty QDict with key x, all
+ * fields with key y are moved to this QDict and their key is renamed
+ * to "x.y". For each nested non-empty QList with key x, the field at
+ * index y is moved to this QDict with the key "x.y" (i.e., the
+ * reverse of what qdict_array_split() does).
+ * This operation is applied recursively for nested QDicts and QLists.
+ */
+void qdict_flatten(QDict *qdict)
+{
+ qdict_flatten_qdict(qdict, qdict, NULL);
+}
+
+/* extract all the src QDict entries starting by start into dst.
+ * If dst is NULL then the entries are simply removed from src. */
+void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start)
+
+{
+ const QDictEntry *entry, *next;
+ const char *p;
+
+ if (dst) {
+ *dst = qdict_new();
+ }
+ entry = qdict_first(src);
+
+ while (entry != NULL) {
+ next = qdict_next(src, entry);
+ if (strstart(entry->key, start, &p)) {
+ if (dst) {
+ qdict_put_obj(*dst, p, qobject_ref(entry->value));
+ }
+ qdict_del(src, entry->key);
+ }
+ entry = next;
+ }
+}
+
+static int qdict_count_prefixed_entries(const QDict *src, const char *start)
+{
+ const QDictEntry *entry;
+ int count = 0;
+
+ for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) {
+ if (strstart(entry->key, start, NULL)) {
+ if (count == INT_MAX) {
+ return -ERANGE;
+ }
+ count++;
+ }
+ }
+
+ return count;
+}
+
+/**
+ * qdict_array_split(): This function moves array-like elements of a QDict into
+ * a new QList. Every entry in the original QDict with a key "%u" or one
+ * prefixed "%u.", where %u designates an unsigned integer starting at 0 and
+ * incrementally counting up, will be moved to a new QDict at index %u in the
+ * output QList with the key prefix removed, if that prefix is "%u.". If the
+ * whole key is just "%u", the whole QObject will be moved unchanged without
+ * creating a new QDict. The function terminates when there is no entry in the
+ * QDict with a prefix directly (incrementally) following the last one; it also
+ * returns if there are both entries with "%u" and "%u." for the same index %u.
+ * Example: {"0.a": 42, "0.b": 23, "1.x": 0, "4.y": 1, "o.o": 7, "2": 66}
+ * (or {"1.x": 0, "4.y": 1, "0.a": 42, "o.o": 7, "0.b": 23, "2": 66})
+ * => [{"a": 42, "b": 23}, {"x": 0}, 66]
+ * and {"4.y": 1, "o.o": 7} (remainder of the old QDict)
+ */
+void qdict_array_split(QDict *src, QList **dst)
+{
+ unsigned i;
+
+ *dst = qlist_new();
+
+ for (i = 0; i < UINT_MAX; i++) {
+ QObject *subqobj;
+ bool is_subqdict;
+ QDict *subqdict;
+ char indexstr[32], prefix[32];
+ size_t snprintf_ret;
+
+ snprintf_ret = snprintf(indexstr, 32, "%u", i);
+ assert(snprintf_ret < 32);
+
+ subqobj = qdict_get(src, indexstr);
+
+ snprintf_ret = snprintf(prefix, 32, "%u.", i);
+ assert(snprintf_ret < 32);
+
+ /* Overflow is the same as positive non-zero results */
+ is_subqdict = qdict_count_prefixed_entries(src, prefix);
+
+ /*
+ * There may be either a single subordinate object (named
+ * "%u") or multiple objects (each with a key prefixed "%u."),
+ * but not both.
+ */
+ if (!subqobj == !is_subqdict) {
+ break;
+ }
+
+ if (is_subqdict) {
+ qdict_extract_subqdict(src, &subqdict, prefix);
+ assert(qdict_size(subqdict) > 0);
+ } else {
+ qobject_ref(subqobj);
+ qdict_del(src, indexstr);
+ }
+
+ qlist_append_obj(*dst, subqobj ?: QOBJECT(subqdict));
+ }
+}
+
+/**
+ * qdict_split_flat_key:
+ * @key: the key string to split
+ * @prefix: non-NULL pointer to hold extracted prefix
+ * @suffix: non-NULL pointer to remaining suffix
+ *
+ * Given a flattened key such as 'foo.0.bar', split it into two parts
+ * at the first '.' separator. Allows double dot ('..') to escape the
+ * normal separator.
+ *
+ * e.g.
+ * 'foo.0.bar' -> prefix='foo' and suffix='0.bar'
+ * 'foo..0.bar' -> prefix='foo.0' and suffix='bar'
+ *
+ * The '..' sequence will be unescaped in the returned 'prefix'
+ * string. The 'suffix' string will be left in escaped format, so it
+ * can be fed back into the qdict_split_flat_key() key as the input
+ * later.
+ *
+ * The caller is responsible for freeing the string returned in @prefix
+ * using g_free().
+ */
+static void qdict_split_flat_key(const char *key, char **prefix,
+ const char **suffix)
+{
+ const char *separator;
+ size_t i, j;
+
+ /* Find first '.' separator, but if there is a pair '..'
+ * that acts as an escape, so skip over '..' */
+ separator = NULL;
+ do {
+ if (separator) {
+ separator += 2;
+ } else {
+ separator = key;
+ }
+ separator = strchr(separator, '.');
+ } while (separator && separator[1] == '.');
+
+ if (separator) {
+ *prefix = g_strndup(key, separator - key);
+ *suffix = separator + 1;
+ } else {
+ *prefix = g_strdup(key);
+ *suffix = NULL;
+ }
+
+ /* Unescape the '..' sequence into '.' */
+ for (i = 0, j = 0; (*prefix)[i] != '\0'; i++, j++) {
+ if ((*prefix)[i] == '.') {
+ assert((*prefix)[i + 1] == '.');
+ i++;
+ }
+ (*prefix)[j] = (*prefix)[i];
+ }
+ (*prefix)[j] = '\0';
+}
+
+/**
+ * qdict_is_list:
+ * @maybe_list: dict to check if keys represent list elements.
+ *
+ * Determine whether all keys in @maybe_list are valid list elements.
+ * If @maybe_list is non-zero in length and all the keys look like
+ * valid list indexes, this will return 1. If @maybe_list is zero
+ * length or all keys are non-numeric then it will return 0 to indicate
+ * it is a normal qdict. If there is a mix of numeric and non-numeric
+ * keys, or the list indexes are non-contiguous, an error is reported.
+ *
+ * Returns: 1 if a valid list, 0 if a dict, -1 on error
+ */
+static int qdict_is_list(QDict *maybe_list, Error **errp)
+{
+ const QDictEntry *ent;
+ ssize_t len = 0;
+ ssize_t max = -1;
+ int is_list = -1;
+ int64_t val;
+
+ for (ent = qdict_first(maybe_list); ent != NULL;
+ ent = qdict_next(maybe_list, ent)) {
+ int is_index = !qemu_strtoi64(ent->key, NULL, 10, &val);
+
+ if (is_list == -1) {
+ is_list = is_index;
+ }
+
+ if (is_index != is_list) {
+ error_setg(errp, "Cannot mix list and non-list keys");
+ return -1;
+ }
+
+ if (is_index) {
+ len++;
+ if (val > max) {
+ max = val;
+ }
+ }
+ }
+
+ if (is_list == -1) {
+ assert(!qdict_size(maybe_list));
+ is_list = 0;
+ }
+
+ /* NB this isn't a perfect check - e.g. it won't catch
+ * a list containing '1', '+1', '01', '3', but that
+ * does not matter - we've still proved that the
+ * input is a list. It is up the caller to do a
+ * stricter check if desired */
+ if (len != (max + 1)) {
+ error_setg(errp, "List indices are not contiguous, "
+ "saw %zd elements but %zd largest index",
+ len, max);
+ return -1;
+ }
+
+ return is_list;
+}
+
+/**
+ * qdict_crumple:
+ * @src: the original flat dictionary (only scalar values) to crumple
+ *
+ * Takes a flat dictionary whose keys use '.' separator to indicate
+ * nesting, and values are scalars, empty dictionaries or empty lists,
+ * and crumples it into a nested structure.
+ *
+ * To include a literal '.' in a key name, it must be escaped as '..'
+ *
+ * For example, an input of:
+ *
+ * { 'foo.0.bar': 'one', 'foo.0.wizz': '1',
+ * 'foo.1.bar': 'two', 'foo.1.wizz': '2' }
+ *
+ * will result in an output of:
+ *
+ * {
+ * 'foo': [
+ * { 'bar': 'one', 'wizz': '1' },
+ * { 'bar': 'two', 'wizz': '2' }
+ * ],
+ * }
+ *
+ * The following scenarios in the input dict will result in an
+ * error being returned:
+ *
+ * - Any values in @src are non-scalar types
+ * - If keys in @src imply that a particular level is both a
+ * list and a dict. e.g., "foo.0.bar" and "foo.eek.bar".
+ * - If keys in @src imply that a particular level is a list,
+ * but the indices are non-contiguous. e.g. "foo.0.bar" and
+ * "foo.2.bar" without any "foo.1.bar" present.
+ * - If keys in @src represent list indexes, but are not in
+ * the "%zu" format. e.g. "foo.+0.bar"
+ *
+ * Returns: either a QDict or QList for the nested data structure, or NULL
+ * on error
+ */
+QObject *qdict_crumple(const QDict *src, Error **errp)
+{
+ const QDictEntry *ent;
+ QDict *two_level, *multi_level = NULL, *child_dict;
+ QDict *dict_val;
+ QList *list_val;
+ QObject *dst = NULL, *child;
+ size_t i;
+ char *prefix = NULL;
+ const char *suffix = NULL;
+ int is_list;
+
+ two_level = qdict_new();
+
+ /* Step 1: split our totally flat dict into a two level dict */
+ for (ent = qdict_first(src); ent != NULL; ent = qdict_next(src, ent)) {
+ dict_val = qobject_to(QDict, ent->value);
+ list_val = qobject_to(QList, ent->value);
+ if ((dict_val && qdict_size(dict_val))
+ || (list_val && !qlist_empty(list_val))) {
+ error_setg(errp, "Value %s is not flat", ent->key);
+ goto error;
+ }
+
+ qdict_split_flat_key(ent->key, &prefix, &suffix);
+ child = qdict_get(two_level, prefix);
+ child_dict = qobject_to(QDict, child);
+
+ if (child) {
+ /*
+ * If @child_dict, then all previous keys with this prefix
+ * had a suffix. If @suffix, this one has one as well,
+ * and we're good, else there's a clash.
+ */
+ if (!child_dict || !suffix) {
+ error_setg(errp, "Cannot mix scalar and non-scalar keys");
+ goto error;
+ }
+ }
+
+ if (suffix) {
+ if (!child_dict) {
+ child_dict = qdict_new();
+ qdict_put(two_level, prefix, child_dict);
+ }
+ qdict_put_obj(child_dict, suffix, qobject_ref(ent->value));
+ } else {
+ qdict_put_obj(two_level, prefix, qobject_ref(ent->value));
+ }
+
+ g_free(prefix);
+ prefix = NULL;
+ }
+
+ /* Step 2: optionally process the two level dict recursively
+ * into a multi-level dict */
+ multi_level = qdict_new();
+ for (ent = qdict_first(two_level); ent != NULL;
+ ent = qdict_next(two_level, ent)) {
+ dict_val = qobject_to(QDict, ent->value);
+ if (dict_val && qdict_size(dict_val)) {
+ child = qdict_crumple(dict_val, errp);
+ if (!child) {
+ goto error;
+ }
+
+ qdict_put_obj(multi_level, ent->key, child);
+ } else {
+ qdict_put_obj(multi_level, ent->key, qobject_ref(ent->value));
+ }
+ }
+ qobject_unref(two_level);
+ two_level = NULL;
+
+ /* Step 3: detect if we need to turn our dict into list */
+ is_list = qdict_is_list(multi_level, errp);
+ if (is_list < 0) {
+ goto error;
+ }
+
+ if (is_list) {
+ dst = QOBJECT(qlist_new());
+
+ for (i = 0; i < qdict_size(multi_level); i++) {
+ char *key = g_strdup_printf("%zu", i);
+
+ child = qdict_get(multi_level, key);
+ g_free(key);
+
+ if (!child) {
+ error_setg(errp, "Missing list index %zu", i);
+ goto error;
+ }
+
+ qlist_append_obj(qobject_to(QList, dst), qobject_ref(child));
+ }
+ qobject_unref(multi_level);
+ multi_level = NULL;
+ } else {
+ dst = QOBJECT(multi_level);
+ }
+
+ return dst;
+
+ error:
+ g_free(prefix);
+ qobject_unref(multi_level);
+ qobject_unref(two_level);
+ qobject_unref(dst);
+ return NULL;
+}
+
+/**
+ * qdict_crumple_for_keyval_qiv:
+ * @src: the flat dictionary (only scalar values) to crumple
+ * @errp: location to store error
+ *
+ * Like qdict_crumple(), but additionally transforms scalar values so
+ * the result can be passed to qobject_input_visitor_new_keyval().
+ *
+ * The block subsystem uses this function to prepare its flat QDict
+ * with possibly confused scalar types for a visit. It should not be
+ * used for anything else, and it should go away once the block
+ * subsystem has been cleaned up.
+ */
+static QObject *qdict_crumple_for_keyval_qiv(QDict *src, Error **errp)
+{
+ QDict *tmp = NULL;
+ char *buf;
+ const char *s;
+ const QDictEntry *ent;
+ QObject *dst;
+
+ for (ent = qdict_first(src); ent; ent = qdict_next(src, ent)) {
+ buf = NULL;
+ switch (qobject_type(ent->value)) {
+ case QTYPE_QNULL:
+ case QTYPE_QSTRING:
+ continue;
+ case QTYPE_QNUM:
+ s = buf = qnum_to_string(qobject_to(QNum, ent->value));
+ break;
+ case QTYPE_QDICT:
+ case QTYPE_QLIST:
+ /* @src isn't flat; qdict_crumple() will fail */
+ continue;
+ case QTYPE_QBOOL:
+ s = qbool_get_bool(qobject_to(QBool, ent->value))
+ ? "on" : "off";
+ break;
+ default:
+ abort();
+ }
+
+ if (!tmp) {
+ tmp = qdict_clone_shallow(src);
+ }
+ qdict_put_str(tmp, ent->key, s);
+ g_free(buf);
+ }
+
+ dst = qdict_crumple(tmp ?: src, errp);
+ qobject_unref(tmp);
+ return dst;
+}
+
+/**
+ * qdict_array_entries(): Returns the number of direct array entries if the
+ * sub-QDict of src specified by the prefix in subqdict (or src itself for
+ * prefix == "") is valid as an array, i.e. the length of the created list if
+ * the sub-QDict would become empty after calling qdict_array_split() on it. If
+ * the array is not valid, -EINVAL is returned.
+ */
+int qdict_array_entries(QDict *src, const char *subqdict)
+{
+ const QDictEntry *entry;
+ unsigned i;
+ unsigned entries = 0;
+ size_t subqdict_len = strlen(subqdict);
+
+ assert(!subqdict_len || subqdict[subqdict_len - 1] == '.');
+
+ /* qdict_array_split() loops until UINT_MAX, but as we want to return
+ * negative errors, we only have a signed return value here. Any additional
+ * entries will lead to -EINVAL. */
+ for (i = 0; i < INT_MAX; i++) {
+ QObject *subqobj;
+ int subqdict_entries;
+ char *prefix = g_strdup_printf("%s%u.", subqdict, i);
+
+ subqdict_entries = qdict_count_prefixed_entries(src, prefix);
+
+ /* Remove ending "." */
+ prefix[strlen(prefix) - 1] = 0;
+ subqobj = qdict_get(src, prefix);
+
+ g_free(prefix);
+
+ if (subqdict_entries < 0) {
+ return subqdict_entries;
+ }
+
+ /* There may be either a single subordinate object (named "%u") or
+ * multiple objects (each with a key prefixed "%u."), but not both. */
+ if (subqobj && subqdict_entries) {
+ return -EINVAL;
+ } else if (!subqobj && !subqdict_entries) {
+ break;
+ }
+
+ entries += subqdict_entries ? subqdict_entries : 1;
+ }
+
+ /* Consider everything handled that isn't part of the given sub-QDict */
+ for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) {
+ if (!strstart(qdict_entry_key(entry), subqdict, NULL)) {
+ entries++;
+ }
+ }
+
+ /* Anything left in the sub-QDict that wasn't handled? */
+ if (qdict_size(src) != entries) {
+ return -EINVAL;
+ }
+
+ return i;
+}
+
+/**
+ * qdict_join(): Absorb the src QDict into the dest QDict, that is, move all
+ * elements from src to dest.
+ *
+ * If an element from src has a key already present in dest, it will not be
+ * moved unless overwrite is true.
+ *
+ * If overwrite is true, the conflicting values in dest will be discarded and
+ * replaced by the corresponding values from src.
+ *
+ * Therefore, with overwrite being true, the src QDict will always be empty when
+ * this function returns. If overwrite is false, the src QDict will be empty
+ * iff there were no conflicts.
+ */
+void qdict_join(QDict *dest, QDict *src, bool overwrite)
+{
+ const QDictEntry *entry, *next;
+
+ entry = qdict_first(src);
+ while (entry) {
+ next = qdict_next(src, entry);
+
+ if (overwrite || !qdict_haskey(dest, entry->key)) {
+ qdict_put_obj(dest, entry->key, qobject_ref(entry->value));
+ qdict_del(src, entry->key);
+ }
+
+ entry = next;
+ }
+}
+
+/**
+ * qdict_rename_keys(): Rename keys in qdict according to the replacements
+ * specified in the array renames. The array must be terminated by an entry
+ * with from = NULL.
+ *
+ * The renames are performed individually in the order of the array, so entries
+ * may be renamed multiple times and may or may not conflict depending on the
+ * order of the renames array.
+ *
+ * Returns true for success, false in error cases.
+ */
+bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp)
+{
+ QObject *qobj;
+
+ while (renames->from) {
+ if (qdict_haskey(qdict, renames->from)) {
+ if (qdict_haskey(qdict, renames->to)) {
+ error_setg(errp, "'%s' and its alias '%s' can't be used at the "
+ "same time", renames->to, renames->from);
+ return false;
+ }
+
+ qobj = qdict_get(qdict, renames->from);
+ qdict_put_obj(qdict, renames->to, qobject_ref(qobj));
+ qdict_del(qdict, renames->from);
+ }
+
+ renames++;
+ }
+ return true;
+}
+
+/*
+ * Create a QObject input visitor for flat @qdict with possibly
+ * confused scalar types.
+ *
+ * The block subsystem uses this function to visit its flat QDict with
+ * possibly confused scalar types. It should not be used for anything
+ * else, and it should go away once the block subsystem has been
+ * cleaned up.
+ */
+Visitor *qobject_input_visitor_new_flat_confused(QDict *qdict,
+ Error **errp)
+{
+ QObject *crumpled;
+ Visitor *v;
+
+ crumpled = qdict_crumple_for_keyval_qiv(qdict, errp);
+ if (!crumpled) {
+ return NULL;
+ }
+
+ v = qobject_input_visitor_new_keyval(crumpled);
+ qobject_unref(crumpled);
+ return v;
+}
diff --git a/qobject/json-lexer.c b/qobject/json-lexer.c
new file mode 100644
index 000000000..632320d72
--- /dev/null
+++ b/qobject/json-lexer.c
@@ -0,0 +1,365 @@
+/*
+ * JSON lexer
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "json-parser-int.h"
+
+#define MAX_TOKEN_SIZE (64ULL << 20)
+
+/*
+ * From RFC 8259 "The JavaScript Object Notation (JSON) Data
+ * Interchange Format", with [comments in brackets]:
+ *
+ * The set of tokens includes six structural characters, strings,
+ * numbers, and three literal names.
+ *
+ * These are the six structural characters:
+ *
+ * begin-array = ws %x5B ws ; [ left square bracket
+ * begin-object = ws %x7B ws ; { left curly bracket
+ * end-array = ws %x5D ws ; ] right square bracket
+ * end-object = ws %x7D ws ; } right curly bracket
+ * name-separator = ws %x3A ws ; : colon
+ * value-separator = ws %x2C ws ; , comma
+ *
+ * Insignificant whitespace is allowed before or after any of the six
+ * structural characters.
+ * [This lexer accepts it before or after any token, which is actually
+ * the same, as the grammar always has structural characters between
+ * other tokens.]
+ *
+ * ws = *(
+ * %x20 / ; Space
+ * %x09 / ; Horizontal tab
+ * %x0A / ; Line feed or New line
+ * %x0D ) ; Carriage return
+ *
+ * [...] three literal names:
+ * false null true
+ * [This lexer accepts [a-z]+, and leaves rejecting unknown literal
+ * names to the parser.]
+ *
+ * [Numbers:]
+ *
+ * number = [ minus ] int [ frac ] [ exp ]
+ * decimal-point = %x2E ; .
+ * digit1-9 = %x31-39 ; 1-9
+ * e = %x65 / %x45 ; e E
+ * exp = e [ minus / plus ] 1*DIGIT
+ * frac = decimal-point 1*DIGIT
+ * int = zero / ( digit1-9 *DIGIT )
+ * minus = %x2D ; -
+ * plus = %x2B ; +
+ * zero = %x30 ; 0
+ *
+ * [Strings:]
+ * string = quotation-mark *char quotation-mark
+ *
+ * char = unescaped /
+ * escape (
+ * %x22 / ; " quotation mark U+0022
+ * %x5C / ; \ reverse solidus U+005C
+ * %x2F / ; / solidus U+002F
+ * %x62 / ; b backspace U+0008
+ * %x66 / ; f form feed U+000C
+ * %x6E / ; n line feed U+000A
+ * %x72 / ; r carriage return U+000D
+ * %x74 / ; t tab U+0009
+ * %x75 4HEXDIG ) ; uXXXX U+XXXX
+ * escape = %x5C ; \
+ * quotation-mark = %x22 ; "
+ * unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
+ * [This lexer accepts any non-control character after escape, and
+ * leaves rejecting invalid ones to the parser.]
+ *
+ *
+ * Extensions over RFC 8259:
+ * - Extra escape sequence in strings:
+ * 0x27 (apostrophe) is recognized after escape, too
+ * - Single-quoted strings:
+ * Like double-quoted strings, except they're delimited by %x27
+ * (apostrophe) instead of %x22 (quotation mark), and can't contain
+ * unescaped apostrophe, but can contain unescaped quotation mark.
+ * - Interpolation, if enabled:
+ * The lexer accepts %[A-Za-z0-9]*, and leaves rejecting invalid
+ * ones to the parser.
+ *
+ * Note:
+ * - Input must be encoded in modified UTF-8.
+ * - Decoding and validating is left to the parser.
+ */
+
+enum json_lexer_state {
+ IN_RECOVERY = 1,
+ IN_DQ_STRING_ESCAPE,
+ IN_DQ_STRING,
+ IN_SQ_STRING_ESCAPE,
+ IN_SQ_STRING,
+ IN_ZERO,
+ IN_EXP_DIGITS,
+ IN_EXP_SIGN,
+ IN_EXP_E,
+ IN_MANTISSA,
+ IN_MANTISSA_DIGITS,
+ IN_DIGITS,
+ IN_SIGN,
+ IN_KEYWORD,
+ IN_INTERP,
+ IN_START,
+ IN_START_INTERP, /* must be IN_START + 1 */
+};
+
+QEMU_BUILD_BUG_ON(JSON_ERROR != 0);
+QEMU_BUILD_BUG_ON(IN_RECOVERY != JSON_ERROR + 1);
+QEMU_BUILD_BUG_ON((int)JSON_MIN <= (int)IN_START_INTERP);
+QEMU_BUILD_BUG_ON(JSON_MAX >= 0x80);
+QEMU_BUILD_BUG_ON(IN_START_INTERP != IN_START + 1);
+
+#define LOOKAHEAD 0x80
+#define TERMINAL(state) [0 ... 0xFF] = ((state) | LOOKAHEAD)
+
+static const uint8_t json_lexer[][256] = {
+ /* Relies on default initialization to IN_ERROR! */
+
+ /* error recovery */
+ [IN_RECOVERY] = {
+ /*
+ * Skip characters until a structural character, an ASCII
+ * control character other than '\t', or impossible UTF-8
+ * bytes '\xFE', '\xFF'. Structural characters and line
+ * endings are promising resynchronization points. Clients
+ * may use the others to force the JSON parser into known-good
+ * state; see docs/interop/qmp-spec.txt.
+ */
+ [0 ... 0x1F] = IN_START | LOOKAHEAD,
+ [0x20 ... 0xFD] = IN_RECOVERY,
+ [0xFE ... 0xFF] = IN_START | LOOKAHEAD,
+ ['\t'] = IN_RECOVERY,
+ ['['] = IN_START | LOOKAHEAD,
+ [']'] = IN_START | LOOKAHEAD,
+ ['{'] = IN_START | LOOKAHEAD,
+ ['}'] = IN_START | LOOKAHEAD,
+ [':'] = IN_START | LOOKAHEAD,
+ [','] = IN_START | LOOKAHEAD,
+ },
+
+ /* double quote string */
+ [IN_DQ_STRING_ESCAPE] = {
+ [0x20 ... 0xFD] = IN_DQ_STRING,
+ },
+ [IN_DQ_STRING] = {
+ [0x20 ... 0xFD] = IN_DQ_STRING,
+ ['\\'] = IN_DQ_STRING_ESCAPE,
+ ['"'] = JSON_STRING,
+ },
+
+ /* single quote string */
+ [IN_SQ_STRING_ESCAPE] = {
+ [0x20 ... 0xFD] = IN_SQ_STRING,
+ },
+ [IN_SQ_STRING] = {
+ [0x20 ... 0xFD] = IN_SQ_STRING,
+ ['\\'] = IN_SQ_STRING_ESCAPE,
+ ['\''] = JSON_STRING,
+ },
+
+ /* Zero */
+ [IN_ZERO] = {
+ TERMINAL(JSON_INTEGER),
+ ['0' ... '9'] = JSON_ERROR,
+ ['.'] = IN_MANTISSA,
+ },
+
+ /* Float */
+ [IN_EXP_DIGITS] = {
+ TERMINAL(JSON_FLOAT),
+ ['0' ... '9'] = IN_EXP_DIGITS,
+ },
+
+ [IN_EXP_SIGN] = {
+ ['0' ... '9'] = IN_EXP_DIGITS,
+ },
+
+ [IN_EXP_E] = {
+ ['-'] = IN_EXP_SIGN,
+ ['+'] = IN_EXP_SIGN,
+ ['0' ... '9'] = IN_EXP_DIGITS,
+ },
+
+ [IN_MANTISSA_DIGITS] = {
+ TERMINAL(JSON_FLOAT),
+ ['0' ... '9'] = IN_MANTISSA_DIGITS,
+ ['e'] = IN_EXP_E,
+ ['E'] = IN_EXP_E,
+ },
+
+ [IN_MANTISSA] = {
+ ['0' ... '9'] = IN_MANTISSA_DIGITS,
+ },
+
+ /* Number */
+ [IN_DIGITS] = {
+ TERMINAL(JSON_INTEGER),
+ ['0' ... '9'] = IN_DIGITS,
+ ['e'] = IN_EXP_E,
+ ['E'] = IN_EXP_E,
+ ['.'] = IN_MANTISSA,
+ },
+
+ [IN_SIGN] = {
+ ['0'] = IN_ZERO,
+ ['1' ... '9'] = IN_DIGITS,
+ },
+
+ /* keywords */
+ [IN_KEYWORD] = {
+ TERMINAL(JSON_KEYWORD),
+ ['a' ... 'z'] = IN_KEYWORD,
+ },
+
+ /* interpolation */
+ [IN_INTERP] = {
+ TERMINAL(JSON_INTERP),
+ ['A' ... 'Z'] = IN_INTERP,
+ ['a' ... 'z'] = IN_INTERP,
+ ['0' ... '9'] = IN_INTERP,
+ },
+
+ /*
+ * Two start states:
+ * - IN_START recognizes JSON tokens with our string extensions
+ * - IN_START_INTERP additionally recognizes interpolation.
+ */
+ [IN_START ... IN_START_INTERP] = {
+ ['"'] = IN_DQ_STRING,
+ ['\''] = IN_SQ_STRING,
+ ['0'] = IN_ZERO,
+ ['1' ... '9'] = IN_DIGITS,
+ ['-'] = IN_SIGN,
+ ['{'] = JSON_LCURLY,
+ ['}'] = JSON_RCURLY,
+ ['['] = JSON_LSQUARE,
+ [']'] = JSON_RSQUARE,
+ [','] = JSON_COMMA,
+ [':'] = JSON_COLON,
+ ['a' ... 'z'] = IN_KEYWORD,
+ [' '] = IN_START,
+ ['\t'] = IN_START,
+ ['\r'] = IN_START,
+ ['\n'] = IN_START,
+ },
+ [IN_START_INTERP]['%'] = IN_INTERP,
+};
+
+static inline uint8_t next_state(JSONLexer *lexer, char ch, bool flush,
+ bool *char_consumed)
+{
+ uint8_t next;
+
+ assert(lexer->state < ARRAY_SIZE(json_lexer));
+ next = json_lexer[lexer->state][(uint8_t)ch];
+ *char_consumed = !flush && !(next & LOOKAHEAD);
+ return next & ~LOOKAHEAD;
+}
+
+void json_lexer_init(JSONLexer *lexer, bool enable_interpolation)
+{
+ lexer->start_state = lexer->state = enable_interpolation
+ ? IN_START_INTERP : IN_START;
+ lexer->token = g_string_sized_new(3);
+ lexer->x = lexer->y = 0;
+}
+
+static void json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush)
+{
+ int new_state;
+ bool char_consumed = false;
+
+ lexer->x++;
+ if (ch == '\n') {
+ lexer->x = 0;
+ lexer->y++;
+ }
+
+ while (flush ? lexer->state != lexer->start_state : !char_consumed) {
+ new_state = next_state(lexer, ch, flush, &char_consumed);
+ if (char_consumed) {
+ assert(!flush);
+ g_string_append_c(lexer->token, ch);
+ }
+
+ switch (new_state) {
+ case JSON_LCURLY:
+ case JSON_RCURLY:
+ case JSON_LSQUARE:
+ case JSON_RSQUARE:
+ case JSON_COLON:
+ case JSON_COMMA:
+ case JSON_INTERP:
+ case JSON_INTEGER:
+ case JSON_FLOAT:
+ case JSON_KEYWORD:
+ case JSON_STRING:
+ json_message_process_token(lexer, lexer->token, new_state,
+ lexer->x, lexer->y);
+ /* fall through */
+ case IN_START:
+ g_string_truncate(lexer->token, 0);
+ new_state = lexer->start_state;
+ break;
+ case JSON_ERROR:
+ json_message_process_token(lexer, lexer->token, JSON_ERROR,
+ lexer->x, lexer->y);
+ new_state = IN_RECOVERY;
+ /* fall through */
+ case IN_RECOVERY:
+ g_string_truncate(lexer->token, 0);
+ break;
+ default:
+ break;
+ }
+ lexer->state = new_state;
+ }
+
+ /* Do not let a single token grow to an arbitrarily large size,
+ * this is a security consideration.
+ */
+ if (lexer->token->len > MAX_TOKEN_SIZE) {
+ json_message_process_token(lexer, lexer->token, lexer->state,
+ lexer->x, lexer->y);
+ g_string_truncate(lexer->token, 0);
+ lexer->state = lexer->start_state;
+ }
+}
+
+void json_lexer_feed(JSONLexer *lexer, const char *buffer, size_t size)
+{
+ size_t i;
+
+ for (i = 0; i < size; i++) {
+ json_lexer_feed_char(lexer, buffer[i], false);
+ }
+}
+
+void json_lexer_flush(JSONLexer *lexer)
+{
+ json_lexer_feed_char(lexer, 0, true);
+ assert(lexer->state == lexer->start_state);
+ json_message_process_token(lexer, lexer->token, JSON_END_OF_INPUT,
+ lexer->x, lexer->y);
+}
+
+void json_lexer_destroy(JSONLexer *lexer)
+{
+ g_string_free(lexer->token, true);
+}
diff --git a/qobject/json-parser-int.h b/qobject/json-parser-int.h
new file mode 100644
index 000000000..16a25d00b
--- /dev/null
+++ b/qobject/json-parser-int.h
@@ -0,0 +1,54 @@
+/*
+ * JSON Parser
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef JSON_PARSER_INT_H
+#define JSON_PARSER_INT_H
+
+#include "qapi/qmp/json-parser.h"
+
+typedef enum json_token_type {
+ JSON_ERROR = 0, /* must be zero, see json_lexer[] */
+ /* Gap for lexer states */
+ JSON_LCURLY = 100,
+ JSON_MIN = JSON_LCURLY,
+ JSON_RCURLY,
+ JSON_LSQUARE,
+ JSON_RSQUARE,
+ JSON_COLON,
+ JSON_COMMA,
+ JSON_INTEGER,
+ JSON_FLOAT,
+ JSON_KEYWORD,
+ JSON_STRING,
+ JSON_INTERP,
+ JSON_END_OF_INPUT,
+ JSON_MAX = JSON_END_OF_INPUT
+} JSONTokenType;
+
+typedef struct JSONToken JSONToken;
+
+/* json-lexer.c */
+void json_lexer_init(JSONLexer *lexer, bool enable_interpolation);
+void json_lexer_feed(JSONLexer *lexer, const char *buffer, size_t size);
+void json_lexer_flush(JSONLexer *lexer);
+void json_lexer_destroy(JSONLexer *lexer);
+
+/* json-streamer.c */
+void json_message_process_token(JSONLexer *lexer, GString *input,
+ JSONTokenType type, int x, int y);
+
+/* json-parser.c */
+JSONToken *json_token(JSONTokenType type, int x, int y, GString *tokstr);
+QObject *json_parser_parse(GQueue *tokens, va_list *ap, Error **errp);
+
+#endif
diff --git a/qobject/json-parser.c b/qobject/json-parser.c
new file mode 100644
index 000000000..008b326fb
--- /dev/null
+++ b/qobject/json-parser.c
@@ -0,0 +1,590 @@
+/*
+ * JSON Parser
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/ctype.h"
+#include "qemu/cutils.h"
+#include "qemu/unicode.h"
+#include "qapi/error.h"
+#include "qapi/qmp/qbool.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qlist.h"
+#include "qapi/qmp/qnull.h"
+#include "qapi/qmp/qnum.h"
+#include "qapi/qmp/qstring.h"
+#include "json-parser-int.h"
+
+struct JSONToken {
+ JSONTokenType type;
+ int x;
+ int y;
+ char str[];
+};
+
+typedef struct JSONParserContext {
+ Error *err;
+ JSONToken *current;
+ GQueue *buf;
+ va_list *ap;
+} JSONParserContext;
+
+#define BUG_ON(cond) assert(!(cond))
+
+/**
+ * TODO
+ *
+ * 0) make errors meaningful again
+ * 1) add geometry information to tokens
+ * 3) should we return a parsed size?
+ * 4) deal with premature EOI
+ */
+
+static QObject *parse_value(JSONParserContext *ctxt);
+
+/**
+ * Error handler
+ */
+static void GCC_FMT_ATTR(3, 4) parse_error(JSONParserContext *ctxt,
+ JSONToken *token, const char *msg, ...)
+{
+ va_list ap;
+ char message[1024];
+
+ if (ctxt->err) {
+ return;
+ }
+ va_start(ap, msg);
+ vsnprintf(message, sizeof(message), msg, ap);
+ va_end(ap);
+ error_setg(&ctxt->err, "JSON parse error, %s", message);
+}
+
+static int cvt4hex(const char *s)
+{
+ int cp, i;
+
+ cp = 0;
+ for (i = 0; i < 4; i++) {
+ if (!qemu_isxdigit(s[i])) {
+ return -1;
+ }
+ cp <<= 4;
+ if (s[i] >= '0' && s[i] <= '9') {
+ cp |= s[i] - '0';
+ } else if (s[i] >= 'a' && s[i] <= 'f') {
+ cp |= 10 + s[i] - 'a';
+ } else if (s[i] >= 'A' && s[i] <= 'F') {
+ cp |= 10 + s[i] - 'A';
+ } else {
+ return -1;
+ }
+ }
+ return cp;
+}
+
+/**
+ * parse_string(): Parse a JSON string
+ *
+ * From RFC 8259 "The JavaScript Object Notation (JSON) Data
+ * Interchange Format":
+ *
+ * char = unescaped /
+ * escape (
+ * %x22 / ; " quotation mark U+0022
+ * %x5C / ; \ reverse solidus U+005C
+ * %x2F / ; / solidus U+002F
+ * %x62 / ; b backspace U+0008
+ * %x66 / ; f form feed U+000C
+ * %x6E / ; n line feed U+000A
+ * %x72 / ; r carriage return U+000D
+ * %x74 / ; t tab U+0009
+ * %x75 4HEXDIG ) ; uXXXX U+XXXX
+ * escape = %x5C ; \
+ * quotation-mark = %x22 ; "
+ * unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
+ *
+ * Extensions over RFC 8259:
+ * - Extra escape sequence in strings:
+ * 0x27 (apostrophe) is recognized after escape, too
+ * - Single-quoted strings:
+ * Like double-quoted strings, except they're delimited by %x27
+ * (apostrophe) instead of %x22 (quotation mark), and can't contain
+ * unescaped apostrophe, but can contain unescaped quotation mark.
+ *
+ * Note:
+ * - Encoding is modified UTF-8.
+ * - Invalid Unicode characters are rejected.
+ * - Control characters \x00..\x1F are rejected by the lexer.
+ */
+static QString *parse_string(JSONParserContext *ctxt, JSONToken *token)
+{
+ const char *ptr = token->str;
+ GString *str;
+ char quote;
+ const char *beg;
+ int cp, trailing;
+ char *end;
+ ssize_t len;
+ char utf8_buf[5];
+
+ assert(*ptr == '"' || *ptr == '\'');
+ quote = *ptr++;
+ str = g_string_new(NULL);
+
+ while (*ptr != quote) {
+ assert(*ptr);
+ switch (*ptr) {
+ case '\\':
+ beg = ptr++;
+ switch (*ptr++) {
+ case '"':
+ g_string_append_c(str, '"');
+ break;
+ case '\'':
+ g_string_append_c(str, '\'');
+ break;
+ case '\\':
+ g_string_append_c(str, '\\');
+ break;
+ case '/':
+ g_string_append_c(str, '/');
+ break;
+ case 'b':
+ g_string_append_c(str, '\b');
+ break;
+ case 'f':
+ g_string_append_c(str, '\f');
+ break;
+ case 'n':
+ g_string_append_c(str, '\n');
+ break;
+ case 'r':
+ g_string_append_c(str, '\r');
+ break;
+ case 't':
+ g_string_append_c(str, '\t');
+ break;
+ case 'u':
+ cp = cvt4hex(ptr);
+ ptr += 4;
+
+ /* handle surrogate pairs */
+ if (cp >= 0xD800 && cp <= 0xDBFF
+ && ptr[0] == '\\' && ptr[1] == 'u') {
+ /* leading surrogate followed by \u */
+ cp = 0x10000 + ((cp & 0x3FF) << 10);
+ trailing = cvt4hex(ptr + 2);
+ if (trailing >= 0xDC00 && trailing <= 0xDFFF) {
+ /* followed by trailing surrogate */
+ cp |= trailing & 0x3FF;
+ ptr += 6;
+ } else {
+ cp = -1; /* invalid */
+ }
+ }
+
+ if (mod_utf8_encode(utf8_buf, sizeof(utf8_buf), cp) < 0) {
+ parse_error(ctxt, token,
+ "%.*s is not a valid Unicode character",
+ (int)(ptr - beg), beg);
+ goto out;
+ }
+ g_string_append(str, utf8_buf);
+ break;
+ default:
+ parse_error(ctxt, token, "invalid escape sequence in string");
+ goto out;
+ }
+ break;
+ case '%':
+ if (ctxt->ap) {
+ if (ptr[1] != '%') {
+ parse_error(ctxt, token, "can't interpolate into string");
+ goto out;
+ }
+ ptr++;
+ }
+ /* fall through */
+ default:
+ cp = mod_utf8_codepoint(ptr, 6, &end);
+ if (cp < 0) {
+ parse_error(ctxt, token, "invalid UTF-8 sequence in string");
+ goto out;
+ }
+ ptr = end;
+ len = mod_utf8_encode(utf8_buf, sizeof(utf8_buf), cp);
+ assert(len >= 0);
+ g_string_append(str, utf8_buf);
+ }
+ }
+
+ return qstring_from_gstring(str);
+
+out:
+ g_string_free(str, true);
+ return NULL;
+}
+
+/* Note: the token object returned by parser_context_peek_token or
+ * parser_context_pop_token is deleted as soon as parser_context_pop_token
+ * is called again.
+ */
+static JSONToken *parser_context_pop_token(JSONParserContext *ctxt)
+{
+ g_free(ctxt->current);
+ ctxt->current = g_queue_pop_head(ctxt->buf);
+ return ctxt->current;
+}
+
+static JSONToken *parser_context_peek_token(JSONParserContext *ctxt)
+{
+ return g_queue_peek_head(ctxt->buf);
+}
+
+/**
+ * Parsing rules
+ */
+static int parse_pair(JSONParserContext *ctxt, QDict *dict)
+{
+ QObject *key_obj = NULL;
+ QString *key;
+ QObject *value;
+ JSONToken *peek, *token;
+
+ peek = parser_context_peek_token(ctxt);
+ if (peek == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ goto out;
+ }
+
+ key_obj = parse_value(ctxt);
+ key = qobject_to(QString, key_obj);
+ if (!key) {
+ parse_error(ctxt, peek, "key is not a string in object");
+ goto out;
+ }
+
+ token = parser_context_pop_token(ctxt);
+ if (token == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ goto out;
+ }
+
+ if (token->type != JSON_COLON) {
+ parse_error(ctxt, token, "missing : in object pair");
+ goto out;
+ }
+
+ value = parse_value(ctxt);
+ if (value == NULL) {
+ parse_error(ctxt, token, "Missing value in dict");
+ goto out;
+ }
+
+ if (qdict_haskey(dict, qstring_get_str(key))) {
+ parse_error(ctxt, token, "duplicate key");
+ goto out;
+ }
+
+ qdict_put_obj(dict, qstring_get_str(key), value);
+
+ qobject_unref(key_obj);
+ return 0;
+
+out:
+ qobject_unref(key_obj);
+ return -1;
+}
+
+static QObject *parse_object(JSONParserContext *ctxt)
+{
+ QDict *dict = NULL;
+ JSONToken *token, *peek;
+
+ token = parser_context_pop_token(ctxt);
+ assert(token && token->type == JSON_LCURLY);
+
+ dict = qdict_new();
+
+ peek = parser_context_peek_token(ctxt);
+ if (peek == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ goto out;
+ }
+
+ if (peek->type != JSON_RCURLY) {
+ if (parse_pair(ctxt, dict) == -1) {
+ goto out;
+ }
+
+ token = parser_context_pop_token(ctxt);
+ if (token == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ goto out;
+ }
+
+ while (token->type != JSON_RCURLY) {
+ if (token->type != JSON_COMMA) {
+ parse_error(ctxt, token, "expected separator in dict");
+ goto out;
+ }
+
+ if (parse_pair(ctxt, dict) == -1) {
+ goto out;
+ }
+
+ token = parser_context_pop_token(ctxt);
+ if (token == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ goto out;
+ }
+ }
+ } else {
+ (void)parser_context_pop_token(ctxt);
+ }
+
+ return QOBJECT(dict);
+
+out:
+ qobject_unref(dict);
+ return NULL;
+}
+
+static QObject *parse_array(JSONParserContext *ctxt)
+{
+ QList *list = NULL;
+ JSONToken *token, *peek;
+
+ token = parser_context_pop_token(ctxt);
+ assert(token && token->type == JSON_LSQUARE);
+
+ list = qlist_new();
+
+ peek = parser_context_peek_token(ctxt);
+ if (peek == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ goto out;
+ }
+
+ if (peek->type != JSON_RSQUARE) {
+ QObject *obj;
+
+ obj = parse_value(ctxt);
+ if (obj == NULL) {
+ parse_error(ctxt, token, "expecting value");
+ goto out;
+ }
+
+ qlist_append_obj(list, obj);
+
+ token = parser_context_pop_token(ctxt);
+ if (token == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ goto out;
+ }
+
+ while (token->type != JSON_RSQUARE) {
+ if (token->type != JSON_COMMA) {
+ parse_error(ctxt, token, "expected separator in list");
+ goto out;
+ }
+
+ obj = parse_value(ctxt);
+ if (obj == NULL) {
+ parse_error(ctxt, token, "expecting value");
+ goto out;
+ }
+
+ qlist_append_obj(list, obj);
+
+ token = parser_context_pop_token(ctxt);
+ if (token == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ goto out;
+ }
+ }
+ } else {
+ (void)parser_context_pop_token(ctxt);
+ }
+
+ return QOBJECT(list);
+
+out:
+ qobject_unref(list);
+ return NULL;
+}
+
+static QObject *parse_keyword(JSONParserContext *ctxt)
+{
+ JSONToken *token;
+
+ token = parser_context_pop_token(ctxt);
+ assert(token && token->type == JSON_KEYWORD);
+
+ if (!strcmp(token->str, "true")) {
+ return QOBJECT(qbool_from_bool(true));
+ } else if (!strcmp(token->str, "false")) {
+ return QOBJECT(qbool_from_bool(false));
+ } else if (!strcmp(token->str, "null")) {
+ return QOBJECT(qnull());
+ }
+ parse_error(ctxt, token, "invalid keyword '%s'", token->str);
+ return NULL;
+}
+
+static QObject *parse_interpolation(JSONParserContext *ctxt)
+{
+ JSONToken *token;
+
+ token = parser_context_pop_token(ctxt);
+ assert(token && token->type == JSON_INTERP);
+
+ if (!strcmp(token->str, "%p")) {
+ return va_arg(*ctxt->ap, QObject *);
+ } else if (!strcmp(token->str, "%i")) {
+ return QOBJECT(qbool_from_bool(va_arg(*ctxt->ap, int)));
+ } else if (!strcmp(token->str, "%d")) {
+ return QOBJECT(qnum_from_int(va_arg(*ctxt->ap, int)));
+ } else if (!strcmp(token->str, "%ld")) {
+ return QOBJECT(qnum_from_int(va_arg(*ctxt->ap, long)));
+ } else if (!strcmp(token->str, "%lld")) {
+ return QOBJECT(qnum_from_int(va_arg(*ctxt->ap, long long)));
+ } else if (!strcmp(token->str, "%" PRId64)) {
+ return QOBJECT(qnum_from_int(va_arg(*ctxt->ap, int64_t)));
+ } else if (!strcmp(token->str, "%u")) {
+ return QOBJECT(qnum_from_uint(va_arg(*ctxt->ap, unsigned int)));
+ } else if (!strcmp(token->str, "%lu")) {
+ return QOBJECT(qnum_from_uint(va_arg(*ctxt->ap, unsigned long)));
+ } else if (!strcmp(token->str, "%llu")) {
+ return QOBJECT(qnum_from_uint(va_arg(*ctxt->ap, unsigned long long)));
+ } else if (!strcmp(token->str, "%" PRIu64)) {
+ return QOBJECT(qnum_from_uint(va_arg(*ctxt->ap, uint64_t)));
+ } else if (!strcmp(token->str, "%s")) {
+ return QOBJECT(qstring_from_str(va_arg(*ctxt->ap, const char *)));
+ } else if (!strcmp(token->str, "%f")) {
+ return QOBJECT(qnum_from_double(va_arg(*ctxt->ap, double)));
+ }
+ parse_error(ctxt, token, "invalid interpolation '%s'", token->str);
+ return NULL;
+}
+
+static QObject *parse_literal(JSONParserContext *ctxt)
+{
+ JSONToken *token;
+
+ token = parser_context_pop_token(ctxt);
+ assert(token);
+
+ switch (token->type) {
+ case JSON_STRING:
+ return QOBJECT(parse_string(ctxt, token));
+ case JSON_INTEGER: {
+ /*
+ * Represent JSON_INTEGER as QNUM_I64 if possible, else as
+ * QNUM_U64, else as QNUM_DOUBLE. Note that qemu_strtoi64()
+ * and qemu_strtou64() fail with ERANGE when it's not
+ * possible.
+ *
+ * qnum_get_int() will then work for any signed 64-bit
+ * JSON_INTEGER, qnum_get_uint() for any unsigned 64-bit
+ * integer, and qnum_get_double() both for any JSON_INTEGER
+ * and any JSON_FLOAT (with precision loss for integers beyond
+ * 53 bits)
+ */
+ int ret;
+ int64_t value;
+ uint64_t uvalue;
+
+ ret = qemu_strtoi64(token->str, NULL, 10, &value);
+ if (!ret) {
+ return QOBJECT(qnum_from_int(value));
+ }
+ assert(ret == -ERANGE);
+
+ if (token->str[0] != '-') {
+ ret = qemu_strtou64(token->str, NULL, 10, &uvalue);
+ if (!ret) {
+ return QOBJECT(qnum_from_uint(uvalue));
+ }
+ assert(ret == -ERANGE);
+ }
+ }
+ /* fall through to JSON_FLOAT */
+ case JSON_FLOAT:
+ /* FIXME dependent on locale; a pervasive issue in QEMU */
+ /* FIXME our lexer matches RFC 8259 in forbidding Inf or NaN,
+ * but those might be useful extensions beyond JSON */
+ return QOBJECT(qnum_from_double(strtod(token->str, NULL)));
+ default:
+ abort();
+ }
+}
+
+static QObject *parse_value(JSONParserContext *ctxt)
+{
+ JSONToken *token;
+
+ token = parser_context_peek_token(ctxt);
+ if (token == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ return NULL;
+ }
+
+ switch (token->type) {
+ case JSON_LCURLY:
+ return parse_object(ctxt);
+ case JSON_LSQUARE:
+ return parse_array(ctxt);
+ case JSON_INTERP:
+ return parse_interpolation(ctxt);
+ case JSON_INTEGER:
+ case JSON_FLOAT:
+ case JSON_STRING:
+ return parse_literal(ctxt);
+ case JSON_KEYWORD:
+ return parse_keyword(ctxt);
+ default:
+ parse_error(ctxt, token, "expecting value");
+ return NULL;
+ }
+}
+
+JSONToken *json_token(JSONTokenType type, int x, int y, GString *tokstr)
+{
+ JSONToken *token = g_malloc(sizeof(JSONToken) + tokstr->len + 1);
+
+ token->type = type;
+ memcpy(token->str, tokstr->str, tokstr->len);
+ token->str[tokstr->len] = 0;
+ token->x = x;
+ token->y = y;
+ return token;
+}
+
+QObject *json_parser_parse(GQueue *tokens, va_list *ap, Error **errp)
+{
+ JSONParserContext ctxt = { .buf = tokens, .ap = ap };
+ QObject *result;
+
+ result = parse_value(&ctxt);
+ assert(ctxt.err || g_queue_is_empty(ctxt.buf));
+
+ error_propagate(errp, ctxt.err);
+
+ while (!g_queue_is_empty(ctxt.buf)) {
+ parser_context_pop_token(&ctxt);
+ }
+ g_free(ctxt.current);
+
+ return result;
+}
diff --git a/qobject/json-streamer.c b/qobject/json-streamer.c
new file mode 100644
index 000000000..b93d97b99
--- /dev/null
+++ b/qobject/json-streamer.c
@@ -0,0 +1,134 @@
+/*
+ * JSON streaming support
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "json-parser-int.h"
+
+#define MAX_TOKEN_SIZE (64ULL << 20)
+#define MAX_TOKEN_COUNT (2ULL << 20)
+#define MAX_NESTING (1 << 10)
+
+static void json_message_free_tokens(JSONMessageParser *parser)
+{
+ JSONToken *token;
+
+ while ((token = g_queue_pop_head(&parser->tokens))) {
+ g_free(token);
+ }
+}
+
+void json_message_process_token(JSONLexer *lexer, GString *input,
+ JSONTokenType type, int x, int y)
+{
+ JSONMessageParser *parser = container_of(lexer, JSONMessageParser, lexer);
+ QObject *json = NULL;
+ Error *err = NULL;
+ JSONToken *token;
+
+ switch (type) {
+ case JSON_LCURLY:
+ parser->brace_count++;
+ break;
+ case JSON_RCURLY:
+ parser->brace_count--;
+ break;
+ case JSON_LSQUARE:
+ parser->bracket_count++;
+ break;
+ case JSON_RSQUARE:
+ parser->bracket_count--;
+ break;
+ case JSON_ERROR:
+ error_setg(&err, "JSON parse error, stray '%s'", input->str);
+ goto out_emit;
+ case JSON_END_OF_INPUT:
+ if (g_queue_is_empty(&parser->tokens)) {
+ return;
+ }
+ json = json_parser_parse(&parser->tokens, parser->ap, &err);
+ goto out_emit;
+ default:
+ break;
+ }
+
+ /*
+ * Security consideration, we limit total memory allocated per object
+ * and the maximum recursion depth that a message can force.
+ */
+ if (parser->token_size + input->len + 1 > MAX_TOKEN_SIZE) {
+ error_setg(&err, "JSON token size limit exceeded");
+ goto out_emit;
+ }
+ if (g_queue_get_length(&parser->tokens) + 1 > MAX_TOKEN_COUNT) {
+ error_setg(&err, "JSON token count limit exceeded");
+ goto out_emit;
+ }
+ if (parser->bracket_count + parser->brace_count > MAX_NESTING) {
+ error_setg(&err, "JSON nesting depth limit exceeded");
+ goto out_emit;
+ }
+
+ token = json_token(type, x, y, input);
+ parser->token_size += input->len;
+
+ g_queue_push_tail(&parser->tokens, token);
+
+ if ((parser->brace_count > 0 || parser->bracket_count > 0)
+ && parser->brace_count >= 0 && parser->bracket_count >= 0) {
+ return;
+ }
+
+ json = json_parser_parse(&parser->tokens, parser->ap, &err);
+
+out_emit:
+ parser->brace_count = 0;
+ parser->bracket_count = 0;
+ json_message_free_tokens(parser);
+ parser->token_size = 0;
+ parser->emit(parser->opaque, json, err);
+}
+
+void json_message_parser_init(JSONMessageParser *parser,
+ void (*emit)(void *opaque, QObject *json,
+ Error *err),
+ void *opaque, va_list *ap)
+{
+ parser->emit = emit;
+ parser->opaque = opaque;
+ parser->ap = ap;
+ parser->brace_count = 0;
+ parser->bracket_count = 0;
+ g_queue_init(&parser->tokens);
+ parser->token_size = 0;
+
+ json_lexer_init(&parser->lexer, !!ap);
+}
+
+void json_message_parser_feed(JSONMessageParser *parser,
+ const char *buffer, size_t size)
+{
+ json_lexer_feed(&parser->lexer, buffer, size);
+}
+
+void json_message_parser_flush(JSONMessageParser *parser)
+{
+ json_lexer_flush(&parser->lexer);
+ assert(g_queue_is_empty(&parser->tokens));
+}
+
+void json_message_parser_destroy(JSONMessageParser *parser)
+{
+ json_lexer_destroy(&parser->lexer);
+ json_message_free_tokens(parser);
+}
diff --git a/qobject/json-writer.c b/qobject/json-writer.c
new file mode 100644
index 000000000..309a31d57
--- /dev/null
+++ b/qobject/json-writer.c
@@ -0,0 +1,247 @@
+/*
+ * JSON Writer
+ *
+ * Copyright IBM, Corp. 2009
+ * Copyright (c) 2010-2020 Red Hat Inc.
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ * Markus Armbruster <armbru@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qmp/json-writer.h"
+#include "qemu/unicode.h"
+
+struct JSONWriter {
+ bool pretty;
+ bool need_comma;
+ GString *contents;
+ GByteArray *container_is_array;
+};
+
+JSONWriter *json_writer_new(bool pretty)
+{
+ JSONWriter *writer = g_new(JSONWriter, 1);
+
+ writer->pretty = pretty;
+ writer->need_comma = false;
+ writer->contents = g_string_new(NULL);
+ writer->container_is_array = g_byte_array_new();
+ return writer;
+}
+
+const char *json_writer_get(JSONWriter *writer)
+{
+ g_assert(!writer->container_is_array->len);
+ return writer->contents->str;
+}
+
+GString *json_writer_get_and_free(JSONWriter *writer)
+{
+ GString *contents = writer->contents;
+
+ writer->contents = NULL;
+ g_byte_array_free(writer->container_is_array, true);
+ g_free(writer);
+ return contents;
+}
+
+void json_writer_free(JSONWriter *writer)
+{
+ if (writer) {
+ g_string_free(json_writer_get_and_free(writer), true);
+ }
+}
+
+static void enter_container(JSONWriter *writer, bool is_array)
+{
+ unsigned depth = writer->container_is_array->len;
+
+ g_byte_array_set_size(writer->container_is_array, depth + 1);
+ writer->container_is_array->data[depth] = is_array;
+ writer->need_comma = false;
+}
+
+static void leave_container(JSONWriter *writer, bool is_array)
+{
+ unsigned depth = writer->container_is_array->len;
+
+ assert(depth);
+ assert(writer->container_is_array->data[depth - 1] == is_array);
+ g_byte_array_set_size(writer->container_is_array, depth - 1);
+ writer->need_comma = true;
+}
+
+static bool in_object(JSONWriter *writer)
+{
+ unsigned depth = writer->container_is_array->len;
+
+ return depth && !writer->container_is_array->data[depth - 1];
+}
+
+static void pretty_newline(JSONWriter *writer)
+{
+ if (writer->pretty) {
+ g_string_append_printf(writer->contents, "\n%*s",
+ writer->container_is_array->len * 4, "");
+ }
+}
+
+static void pretty_newline_or_space(JSONWriter *writer)
+{
+ if (writer->pretty) {
+ g_string_append_printf(writer->contents, "\n%*s",
+ writer->container_is_array->len * 4, "");
+ } else {
+ g_string_append_c(writer->contents, ' ');
+ }
+}
+
+static void quoted_str(JSONWriter *writer, const char *str)
+{
+ const char *ptr;
+ char *end;
+ int cp;
+
+ g_string_append_c(writer->contents, '"');
+
+ for (ptr = str; *ptr; ptr = end) {
+ cp = mod_utf8_codepoint(ptr, 6, &end);
+ switch (cp) {
+ case '\"':
+ g_string_append(writer->contents, "\\\"");
+ break;
+ case '\\':
+ g_string_append(writer->contents, "\\\\");
+ break;
+ case '\b':
+ g_string_append(writer->contents, "\\b");
+ break;
+ case '\f':
+ g_string_append(writer->contents, "\\f");
+ break;
+ case '\n':
+ g_string_append(writer->contents, "\\n");
+ break;
+ case '\r':
+ g_string_append(writer->contents, "\\r");
+ break;
+ case '\t':
+ g_string_append(writer->contents, "\\t");
+ break;
+ default:
+ if (cp < 0) {
+ cp = 0xFFFD; /* replacement character */
+ }
+ if (cp > 0xFFFF) {
+ /* beyond BMP; need a surrogate pair */
+ g_string_append_printf(writer->contents, "\\u%04X\\u%04X",
+ 0xD800 + ((cp - 0x10000) >> 10),
+ 0xDC00 + ((cp - 0x10000) & 0x3FF));
+ } else if (cp < 0x20 || cp >= 0x7F) {
+ g_string_append_printf(writer->contents, "\\u%04X", cp);
+ } else {
+ g_string_append_c(writer->contents, cp);
+ }
+ }
+ };
+
+ g_string_append_c(writer->contents, '"');
+}
+
+static void maybe_comma_name(JSONWriter *writer, const char *name)
+{
+ if (writer->need_comma) {
+ g_string_append_c(writer->contents, ',');
+ pretty_newline_or_space(writer);
+ } else {
+ if (writer->contents->len) {
+ pretty_newline(writer);
+ }
+ writer->need_comma = true;
+ }
+
+ if (in_object(writer)) {
+ quoted_str(writer, name);
+ g_string_append(writer->contents, ": ");
+ }
+}
+
+void json_writer_start_object(JSONWriter *writer, const char *name)
+{
+ maybe_comma_name(writer, name);
+ g_string_append_c(writer->contents, '{');
+ enter_container(writer, false);
+}
+
+void json_writer_end_object(JSONWriter *writer)
+{
+ leave_container(writer, false);
+ pretty_newline(writer);
+ g_string_append_c(writer->contents, '}');
+}
+
+void json_writer_start_array(JSONWriter *writer, const char *name)
+{
+ maybe_comma_name(writer, name);
+ g_string_append_c(writer->contents, '[');
+ enter_container(writer, true);
+}
+
+void json_writer_end_array(JSONWriter *writer)
+{
+ leave_container(writer, true);
+ pretty_newline(writer);
+ g_string_append_c(writer->contents, ']');
+}
+
+void json_writer_bool(JSONWriter *writer, const char *name, bool val)
+{
+ maybe_comma_name(writer, name);
+ g_string_append(writer->contents, val ? "true" : "false");
+}
+
+void json_writer_null(JSONWriter *writer, const char *name)
+{
+ maybe_comma_name(writer, name);
+ g_string_append(writer->contents, "null");
+}
+
+void json_writer_int64(JSONWriter *writer, const char *name, int64_t val)
+{
+ maybe_comma_name(writer, name);
+ g_string_append_printf(writer->contents, "%" PRId64, val);
+}
+
+void json_writer_uint64(JSONWriter *writer, const char *name, uint64_t val)
+{
+ maybe_comma_name(writer, name);
+ g_string_append_printf(writer->contents, "%" PRIu64, val);
+}
+
+void json_writer_double(JSONWriter *writer, const char *name, double val)
+{
+ maybe_comma_name(writer, name);
+
+ /*
+ * FIXME: g_string_append_printf() is locale dependent; but JSON
+ * requires numbers to be formatted as if in the C locale.
+ * Dependence on C locale is a pervasive issue in QEMU.
+ */
+ /*
+ * FIXME: This risks printing Inf or NaN, which are not valid
+ * JSON values.
+ */
+ g_string_append_printf(writer->contents, "%.17g", val);
+}
+
+void json_writer_str(JSONWriter *writer, const char *name, const char *str)
+{
+ maybe_comma_name(writer, name);
+ quoted_str(writer, str);
+}
diff --git a/qobject/meson.build b/qobject/meson.build
new file mode 100644
index 000000000..4683a852a
--- /dev/null
+++ b/qobject/meson.build
@@ -0,0 +1,4 @@
+util_ss.add(files('qnull.c', 'qnum.c', 'qstring.c', 'qdict.c',
+ 'qlist.c', 'qbool.c', 'qlit.c', 'qjson.c', 'qobject.c',
+ 'json-writer.c', 'json-lexer.c', 'json-streamer.c', 'json-parser.c',
+ 'block-qdict.c'))
diff --git a/qobject/qbool.c b/qobject/qbool.c
new file mode 100644
index 000000000..16a600abb
--- /dev/null
+++ b/qobject/qbool.c
@@ -0,0 +1,58 @@
+/*
+ * QBool Module
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qmp/qbool.h"
+#include "qobject-internal.h"
+
+/**
+ * qbool_from_bool(): Create a new QBool from a bool
+ *
+ * Return strong reference.
+ */
+QBool *qbool_from_bool(bool value)
+{
+ QBool *qb;
+
+ qb = g_malloc(sizeof(*qb));
+ qobject_init(QOBJECT(qb), QTYPE_QBOOL);
+ qb->value = value;
+
+ return qb;
+}
+
+/**
+ * qbool_get_bool(): Get the stored bool
+ */
+bool qbool_get_bool(const QBool *qb)
+{
+ return qb->value;
+}
+
+/**
+ * qbool_is_equal(): Test whether the two QBools are equal
+ */
+bool qbool_is_equal(const QObject *x, const QObject *y)
+{
+ return qobject_to(QBool, x)->value == qobject_to(QBool, y)->value;
+}
+
+/**
+ * qbool_destroy_obj(): Free all memory allocated by a
+ * QBool object
+ */
+void qbool_destroy_obj(QObject *obj)
+{
+ assert(obj != NULL);
+ g_free(qobject_to(QBool, obj));
+}
diff --git a/qobject/qdict.c b/qobject/qdict.c
new file mode 100644
index 000000000..0216ca7ac
--- /dev/null
+++ b/qobject/qdict.c
@@ -0,0 +1,444 @@
+/*
+ * QDict Module
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ * Luiz Capitulino <lcapitulino@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qmp/qnum.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qbool.h"
+#include "qapi/qmp/qnull.h"
+#include "qapi/qmp/qstring.h"
+#include "qobject-internal.h"
+
+/**
+ * qdict_new(): Create a new QDict
+ *
+ * Return strong reference.
+ */
+QDict *qdict_new(void)
+{
+ QDict *qdict;
+
+ qdict = g_malloc0(sizeof(*qdict));
+ qobject_init(QOBJECT(qdict), QTYPE_QDICT);
+
+ return qdict;
+}
+
+/**
+ * tdb_hash(): based on the hash algorithm from gdbm, via tdb
+ * (from module-init-tools)
+ */
+static unsigned int tdb_hash(const char *name)
+{
+ unsigned value; /* Used to compute the hash value. */
+ unsigned i; /* Used to cycle through random values. */
+
+ /* Set the initial value from the key size. */
+ for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++) {
+ value = (value + (((const unsigned char *)name)[i] << (i * 5 % 24)));
+ }
+
+ return (1103515243 * value + 12345);
+}
+
+/**
+ * alloc_entry(): allocate a new QDictEntry
+ */
+static QDictEntry *alloc_entry(const char *key, QObject *value)
+{
+ QDictEntry *entry;
+
+ entry = g_malloc0(sizeof(*entry));
+ entry->key = g_strdup(key);
+ entry->value = value;
+
+ return entry;
+}
+
+/**
+ * qdict_entry_value(): Return qdict entry value
+ *
+ * Return weak reference.
+ */
+QObject *qdict_entry_value(const QDictEntry *entry)
+{
+ return entry->value;
+}
+
+/**
+ * qdict_entry_key(): Return qdict entry key
+ *
+ * Return a *pointer* to the string, it has to be duplicated before being
+ * stored.
+ */
+const char *qdict_entry_key(const QDictEntry *entry)
+{
+ return entry->key;
+}
+
+/**
+ * qdict_find(): List lookup function
+ */
+static QDictEntry *qdict_find(const QDict *qdict,
+ const char *key, unsigned int bucket)
+{
+ QDictEntry *entry;
+
+ QLIST_FOREACH(entry, &qdict->table[bucket], next)
+ if (!strcmp(entry->key, key)) {
+ return entry;
+ }
+
+ return NULL;
+}
+
+/**
+ * qdict_put_obj(): Put a new QObject into the dictionary
+ *
+ * Insert the pair 'key:value' into 'qdict', if 'key' already exists
+ * its 'value' will be replaced.
+ *
+ * This is done by freeing the reference to the stored QObject and
+ * storing the new one in the same entry.
+ *
+ * NOTE: ownership of 'value' is transferred to the QDict
+ */
+void qdict_put_obj(QDict *qdict, const char *key, QObject *value)
+{
+ unsigned int bucket;
+ QDictEntry *entry;
+
+ bucket = tdb_hash(key) % QDICT_BUCKET_MAX;
+ entry = qdict_find(qdict, key, bucket);
+ if (entry) {
+ /* replace key's value */
+ qobject_unref(entry->value);
+ entry->value = value;
+ } else {
+ /* allocate a new entry */
+ entry = alloc_entry(key, value);
+ QLIST_INSERT_HEAD(&qdict->table[bucket], entry, next);
+ qdict->size++;
+ }
+}
+
+void qdict_put_int(QDict *qdict, const char *key, int64_t value)
+{
+ qdict_put(qdict, key, qnum_from_int(value));
+}
+
+void qdict_put_bool(QDict *qdict, const char *key, bool value)
+{
+ qdict_put(qdict, key, qbool_from_bool(value));
+}
+
+void qdict_put_str(QDict *qdict, const char *key, const char *value)
+{
+ qdict_put(qdict, key, qstring_from_str(value));
+}
+
+void qdict_put_null(QDict *qdict, const char *key)
+{
+ qdict_put(qdict, key, qnull());
+}
+
+/**
+ * qdict_get(): Lookup for a given 'key'
+ *
+ * Return a weak reference to the QObject associated with 'key' if
+ * 'key' is present in the dictionary, NULL otherwise.
+ */
+QObject *qdict_get(const QDict *qdict, const char *key)
+{
+ QDictEntry *entry;
+
+ entry = qdict_find(qdict, key, tdb_hash(key) % QDICT_BUCKET_MAX);
+ return (entry == NULL ? NULL : entry->value);
+}
+
+/**
+ * qdict_haskey(): Check if 'key' exists
+ *
+ * Return 1 if 'key' exists in the dict, 0 otherwise
+ */
+int qdict_haskey(const QDict *qdict, const char *key)
+{
+ unsigned int bucket = tdb_hash(key) % QDICT_BUCKET_MAX;
+ return (qdict_find(qdict, key, bucket) == NULL ? 0 : 1);
+}
+
+/**
+ * qdict_size(): Return the size of the dictionary
+ */
+size_t qdict_size(const QDict *qdict)
+{
+ return qdict->size;
+}
+
+/**
+ * qdict_get_double(): Get an number mapped by 'key'
+ *
+ * This function assumes that 'key' exists and it stores a QNum.
+ *
+ * Return number mapped by 'key'.
+ */
+double qdict_get_double(const QDict *qdict, const char *key)
+{
+ return qnum_get_double(qobject_to(QNum, qdict_get(qdict, key)));
+}
+
+/**
+ * qdict_get_int(): Get an integer mapped by 'key'
+ *
+ * This function assumes that 'key' exists and it stores a
+ * QNum representable as int.
+ *
+ * Return integer mapped by 'key'.
+ */
+int64_t qdict_get_int(const QDict *qdict, const char *key)
+{
+ return qnum_get_int(qobject_to(QNum, qdict_get(qdict, key)));
+}
+
+/**
+ * qdict_get_bool(): Get a bool mapped by 'key'
+ *
+ * This function assumes that 'key' exists and it stores a
+ * QBool object.
+ *
+ * Return bool mapped by 'key'.
+ */
+bool qdict_get_bool(const QDict *qdict, const char *key)
+{
+ return qbool_get_bool(qobject_to(QBool, qdict_get(qdict, key)));
+}
+
+/**
+ * qdict_get_qlist(): If @qdict maps @key to a QList, return it, else NULL.
+ */
+QList *qdict_get_qlist(const QDict *qdict, const char *key)
+{
+ return qobject_to(QList, qdict_get(qdict, key));
+}
+
+/**
+ * qdict_get_qdict(): If @qdict maps @key to a QDict, return it, else NULL.
+ */
+QDict *qdict_get_qdict(const QDict *qdict, const char *key)
+{
+ return qobject_to(QDict, qdict_get(qdict, key));
+}
+
+/**
+ * qdict_get_str(): Get a pointer to the stored string mapped
+ * by 'key'
+ *
+ * This function assumes that 'key' exists and it stores a
+ * QString object.
+ *
+ * Return pointer to the string mapped by 'key'.
+ */
+const char *qdict_get_str(const QDict *qdict, const char *key)
+{
+ return qstring_get_str(qobject_to(QString, qdict_get(qdict, key)));
+}
+
+/**
+ * qdict_get_try_int(): Try to get integer mapped by 'key'
+ *
+ * Return integer mapped by 'key', if it is not present in the
+ * dictionary or if the stored object is not a QNum representing an
+ * integer, 'def_value' will be returned.
+ */
+int64_t qdict_get_try_int(const QDict *qdict, const char *key,
+ int64_t def_value)
+{
+ QNum *qnum = qobject_to(QNum, qdict_get(qdict, key));
+ int64_t val;
+
+ if (!qnum || !qnum_get_try_int(qnum, &val)) {
+ return def_value;
+ }
+
+ return val;
+}
+
+/**
+ * qdict_get_try_bool(): Try to get a bool mapped by 'key'
+ *
+ * Return bool mapped by 'key', if it is not present in the
+ * dictionary or if the stored object is not of QBool type
+ * 'def_value' will be returned.
+ */
+bool qdict_get_try_bool(const QDict *qdict, const char *key, bool def_value)
+{
+ QBool *qbool = qobject_to(QBool, qdict_get(qdict, key));
+
+ return qbool ? qbool_get_bool(qbool) : def_value;
+}
+
+/**
+ * qdict_get_try_str(): Try to get a pointer to the stored string
+ * mapped by 'key'
+ *
+ * Return a pointer to the string mapped by 'key', if it is not present
+ * in the dictionary or if the stored object is not of QString type
+ * NULL will be returned.
+ */
+const char *qdict_get_try_str(const QDict *qdict, const char *key)
+{
+ QString *qstr = qobject_to(QString, qdict_get(qdict, key));
+
+ return qstr ? qstring_get_str(qstr) : NULL;
+}
+
+static QDictEntry *qdict_next_entry(const QDict *qdict, int first_bucket)
+{
+ int i;
+
+ for (i = first_bucket; i < QDICT_BUCKET_MAX; i++) {
+ if (!QLIST_EMPTY(&qdict->table[i])) {
+ return QLIST_FIRST(&qdict->table[i]);
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * qdict_first(): Return first qdict entry for iteration.
+ */
+const QDictEntry *qdict_first(const QDict *qdict)
+{
+ return qdict_next_entry(qdict, 0);
+}
+
+/**
+ * qdict_next(): Return next qdict entry in an iteration.
+ */
+const QDictEntry *qdict_next(const QDict *qdict, const QDictEntry *entry)
+{
+ QDictEntry *ret;
+
+ ret = QLIST_NEXT(entry, next);
+ if (!ret) {
+ unsigned int bucket = tdb_hash(entry->key) % QDICT_BUCKET_MAX;
+ ret = qdict_next_entry(qdict, bucket + 1);
+ }
+
+ return ret;
+}
+
+/**
+ * qdict_clone_shallow(): Clones a given QDict. Its entries are not copied, but
+ * another reference is added.
+ */
+QDict *qdict_clone_shallow(const QDict *src)
+{
+ QDict *dest;
+ QDictEntry *entry;
+ int i;
+
+ dest = qdict_new();
+
+ for (i = 0; i < QDICT_BUCKET_MAX; i++) {
+ QLIST_FOREACH(entry, &src->table[i], next) {
+ qdict_put_obj(dest, entry->key, qobject_ref(entry->value));
+ }
+ }
+
+ return dest;
+}
+
+/**
+ * qentry_destroy(): Free all the memory allocated by a QDictEntry
+ */
+static void qentry_destroy(QDictEntry *e)
+{
+ assert(e != NULL);
+ assert(e->key != NULL);
+ assert(e->value != NULL);
+
+ qobject_unref(e->value);
+ g_free(e->key);
+ g_free(e);
+}
+
+/**
+ * qdict_del(): Delete a 'key:value' pair from the dictionary
+ *
+ * This will destroy all data allocated by this entry.
+ */
+void qdict_del(QDict *qdict, const char *key)
+{
+ QDictEntry *entry;
+
+ entry = qdict_find(qdict, key, tdb_hash(key) % QDICT_BUCKET_MAX);
+ if (entry) {
+ QLIST_REMOVE(entry, next);
+ qentry_destroy(entry);
+ qdict->size--;
+ }
+}
+
+/**
+ * qdict_is_equal(): Test whether the two QDicts are equal
+ *
+ * Here, equality means whether they contain the same keys and whether
+ * the respective values are in turn equal (i.e. invoking
+ * qobject_is_equal() on them yields true).
+ */
+bool qdict_is_equal(const QObject *x, const QObject *y)
+{
+ const QDict *dict_x = qobject_to(QDict, x);
+ const QDict *dict_y = qobject_to(QDict, y);
+ const QDictEntry *e;
+
+ if (qdict_size(dict_x) != qdict_size(dict_y)) {
+ return false;
+ }
+
+ for (e = qdict_first(dict_x); e; e = qdict_next(dict_x, e)) {
+ const QObject *obj_x = qdict_entry_value(e);
+ const QObject *obj_y = qdict_get(dict_y, qdict_entry_key(e));
+
+ if (!qobject_is_equal(obj_x, obj_y)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/**
+ * qdict_destroy_obj(): Free all the memory allocated by a QDict
+ */
+void qdict_destroy_obj(QObject *obj)
+{
+ int i;
+ QDict *qdict;
+
+ assert(obj != NULL);
+ qdict = qobject_to(QDict, obj);
+
+ for (i = 0; i < QDICT_BUCKET_MAX; i++) {
+ QDictEntry *entry = QLIST_FIRST(&qdict->table[i]);
+ while (entry) {
+ QDictEntry *tmp = QLIST_NEXT(entry, next);
+ QLIST_REMOVE(entry, next);
+ qentry_destroy(entry);
+ entry = tmp;
+ }
+ }
+
+ g_free(qdict);
+}
diff --git a/qobject/qjson.c b/qobject/qjson.c
new file mode 100644
index 000000000..167fcb429
--- /dev/null
+++ b/qobject/qjson.c
@@ -0,0 +1,232 @@
+/*
+ * QObject JSON integration
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qapi/qmp/json-parser.h"
+#include "qapi/qmp/json-writer.h"
+#include "qapi/qmp/qjson.h"
+#include "qapi/qmp/qbool.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qlist.h"
+#include "qapi/qmp/qnum.h"
+#include "qapi/qmp/qstring.h"
+
+typedef struct JSONParsingState {
+ JSONMessageParser parser;
+ QObject *result;
+ Error *err;
+} JSONParsingState;
+
+static void consume_json(void *opaque, QObject *json, Error *err)
+{
+ JSONParsingState *s = opaque;
+
+ assert(!json != !err);
+ assert(!s->result || !s->err);
+
+ if (s->result) {
+ qobject_unref(s->result);
+ s->result = NULL;
+ error_setg(&s->err, "Expecting at most one JSON value");
+ }
+ if (s->err) {
+ qobject_unref(json);
+ error_free(err);
+ return;
+ }
+ s->result = json;
+ s->err = err;
+}
+
+/*
+ * Parse @string as JSON value.
+ * If @ap is non-null, interpolate %-escapes.
+ * Takes ownership of %p arguments.
+ * On success, return the JSON value.
+ * On failure, store an error through @errp and return NULL.
+ * Ownership of %p arguments becomes indeterminate then. To avoid
+ * leaks, callers passing %p must terminate on error, e.g. by passing
+ * &error_abort.
+ */
+static QObject *qobject_from_jsonv(const char *string, va_list *ap,
+ Error **errp)
+{
+ JSONParsingState state = {};
+
+ json_message_parser_init(&state.parser, consume_json, &state, ap);
+ json_message_parser_feed(&state.parser, string, strlen(string));
+ json_message_parser_flush(&state.parser);
+ json_message_parser_destroy(&state.parser);
+
+ if (!state.result && !state.err) {
+ error_setg(&state.err, "Expecting a JSON value");
+ }
+
+ error_propagate(errp, state.err);
+ return state.result;
+}
+
+QObject *qobject_from_json(const char *string, Error **errp)
+{
+ return qobject_from_jsonv(string, NULL, errp);
+}
+
+/*
+ * Parse @string as JSON value with %-escapes interpolated.
+ * Abort on error. Do not use with untrusted @string.
+ * Return the resulting QObject. It is never null.
+ */
+QObject *qobject_from_vjsonf_nofail(const char *string, va_list ap)
+{
+ va_list ap_copy;
+ QObject *obj;
+
+ /* va_copy() is needed when va_list is an array type */
+ va_copy(ap_copy, ap);
+ obj = qobject_from_jsonv(string, &ap_copy, &error_abort);
+ va_end(ap_copy);
+
+ assert(obj);
+ return obj;
+}
+
+/*
+ * Parse @string as JSON value with %-escapes interpolated.
+ * Abort on error. Do not use with untrusted @string.
+ * Return the resulting QObject. It is never null.
+ */
+QObject *qobject_from_jsonf_nofail(const char *string, ...)
+{
+ QObject *obj;
+ va_list ap;
+
+ va_start(ap, string);
+ obj = qobject_from_vjsonf_nofail(string, ap);
+ va_end(ap);
+
+ return obj;
+}
+
+/*
+ * Parse @string as JSON object with %-escapes interpolated.
+ * Abort on error. Do not use with untrusted @string.
+ * Return the resulting QDict. It is never null.
+ */
+QDict *qdict_from_vjsonf_nofail(const char *string, va_list ap)
+{
+ QDict *qdict;
+
+ qdict = qobject_to(QDict, qobject_from_vjsonf_nofail(string, ap));
+ assert(qdict);
+ return qdict;
+}
+
+/*
+ * Parse @string as JSON object with %-escapes interpolated.
+ * Abort on error. Do not use with untrusted @string.
+ * Return the resulting QDict. It is never null.
+ */
+QDict *qdict_from_jsonf_nofail(const char *string, ...)
+{
+ QDict *qdict;
+ va_list ap;
+
+ va_start(ap, string);
+ qdict = qdict_from_vjsonf_nofail(string, ap);
+ va_end(ap);
+ return qdict;
+}
+
+static void to_json(JSONWriter *writer, const char *name,
+ const QObject *obj)
+{
+ switch (qobject_type(obj)) {
+ case QTYPE_QNULL:
+ json_writer_null(writer, name);
+ break;
+ case QTYPE_QNUM: {
+ QNum *val = qobject_to(QNum, obj);
+
+ switch (val->kind) {
+ case QNUM_I64:
+ json_writer_int64(writer, name, val->u.i64);
+ break;
+ case QNUM_U64:
+ json_writer_uint64(writer, name, val->u.u64);
+ break;
+ case QNUM_DOUBLE:
+ json_writer_double(writer, name, val->u.dbl);
+ break;
+ default:
+ abort();
+ }
+ break;
+ }
+ case QTYPE_QSTRING: {
+ QString *val = qobject_to(QString, obj);
+
+ json_writer_str(writer, name, qstring_get_str(val));
+ break;
+ }
+ case QTYPE_QDICT: {
+ QDict *val = qobject_to(QDict, obj);
+ const QDictEntry *entry;
+
+ json_writer_start_object(writer, name);
+
+ for (entry = qdict_first(val);
+ entry;
+ entry = qdict_next(val, entry)) {
+ to_json(writer, qdict_entry_key(entry), qdict_entry_value(entry));
+ }
+
+ json_writer_end_object(writer);
+ break;
+ }
+ case QTYPE_QLIST: {
+ QList *val = qobject_to(QList, obj);
+ QListEntry *entry;
+
+ json_writer_start_array(writer, name);
+
+ QLIST_FOREACH_ENTRY(val, entry) {
+ to_json(writer, NULL, qlist_entry_obj(entry));
+ }
+
+ json_writer_end_array(writer);
+ break;
+ }
+ case QTYPE_QBOOL: {
+ QBool *val = qobject_to(QBool, obj);
+
+ json_writer_bool(writer, name, qbool_get_bool(val));
+ break;
+ }
+ default:
+ abort();
+ }
+}
+
+GString *qobject_to_json_pretty(const QObject *obj, bool pretty)
+{
+ JSONWriter *writer = json_writer_new(pretty);
+
+ to_json(writer, NULL, obj);
+ return json_writer_get_and_free(writer);
+}
+
+GString *qobject_to_json(const QObject *obj)
+{
+ return qobject_to_json_pretty(obj, false);
+}
diff --git a/qobject/qlist.c b/qobject/qlist.c
new file mode 100644
index 000000000..60562a1f5
--- /dev/null
+++ b/qobject/qlist.c
@@ -0,0 +1,184 @@
+/*
+ * QList Module
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ * Luiz Capitulino <lcapitulino@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qmp/qbool.h"
+#include "qapi/qmp/qlist.h"
+#include "qapi/qmp/qnull.h"
+#include "qapi/qmp/qnum.h"
+#include "qapi/qmp/qstring.h"
+#include "qemu/queue.h"
+#include "qobject-internal.h"
+
+/**
+ * qlist_new(): Create a new QList
+ *
+ * Return strong reference.
+ */
+QList *qlist_new(void)
+{
+ QList *qlist;
+
+ qlist = g_malloc(sizeof(*qlist));
+ qobject_init(QOBJECT(qlist), QTYPE_QLIST);
+ QTAILQ_INIT(&qlist->head);
+
+ return qlist;
+}
+
+QList *qlist_copy(QList *src)
+{
+ QList *dst = qlist_new();
+ QListEntry *entry;
+ QObject *elt;
+
+ QLIST_FOREACH_ENTRY(src, entry) {
+ elt = qlist_entry_obj(entry);
+ qobject_ref(elt);
+ qlist_append_obj(dst, elt);
+ }
+ return dst;
+}
+
+/**
+ * qlist_append_obj(): Append an QObject into QList
+ *
+ * NOTE: ownership of 'value' is transferred to the QList
+ */
+void qlist_append_obj(QList *qlist, QObject *value)
+{
+ QListEntry *entry;
+
+ entry = g_malloc(sizeof(*entry));
+ entry->value = value;
+
+ QTAILQ_INSERT_TAIL(&qlist->head, entry, next);
+}
+
+void qlist_append_int(QList *qlist, int64_t value)
+{
+ qlist_append(qlist, qnum_from_int(value));
+}
+
+void qlist_append_bool(QList *qlist, bool value)
+{
+ qlist_append(qlist, qbool_from_bool(value));
+}
+
+void qlist_append_str(QList *qlist, const char *value)
+{
+ qlist_append(qlist, qstring_from_str(value));
+}
+
+void qlist_append_null(QList *qlist)
+{
+ qlist_append(qlist, qnull());
+}
+
+QObject *qlist_pop(QList *qlist)
+{
+ QListEntry *entry;
+ QObject *ret;
+
+ if (qlist == NULL || QTAILQ_EMPTY(&qlist->head)) {
+ return NULL;
+ }
+
+ entry = QTAILQ_FIRST(&qlist->head);
+ QTAILQ_REMOVE(&qlist->head, entry, next);
+
+ ret = entry->value;
+ g_free(entry);
+
+ return ret;
+}
+
+QObject *qlist_peek(QList *qlist)
+{
+ QListEntry *entry;
+
+ if (qlist == NULL || QTAILQ_EMPTY(&qlist->head)) {
+ return NULL;
+ }
+
+ entry = QTAILQ_FIRST(&qlist->head);
+
+ return entry->value;
+}
+
+int qlist_empty(const QList *qlist)
+{
+ return QTAILQ_EMPTY(&qlist->head);
+}
+
+size_t qlist_size(const QList *qlist)
+{
+ size_t count = 0;
+ QListEntry *entry;
+
+ QLIST_FOREACH_ENTRY(qlist, entry) {
+ count++;
+ }
+ return count;
+}
+
+/**
+ * qlist_is_equal(): Test whether the two QLists are equal
+ *
+ * In order to be considered equal, the respective two objects at each
+ * index of the two lists have to compare equal (regarding
+ * qobject_is_equal()), and both lists have to have the same number of
+ * elements.
+ * That means both lists have to contain equal objects in equal order.
+ */
+bool qlist_is_equal(const QObject *x, const QObject *y)
+{
+ const QList *list_x = qobject_to(QList, x);
+ const QList *list_y = qobject_to(QList, y);
+ const QListEntry *entry_x, *entry_y;
+
+ entry_x = qlist_first(list_x);
+ entry_y = qlist_first(list_y);
+
+ while (entry_x && entry_y) {
+ if (!qobject_is_equal(qlist_entry_obj(entry_x),
+ qlist_entry_obj(entry_y)))
+ {
+ return false;
+ }
+
+ entry_x = qlist_next(entry_x);
+ entry_y = qlist_next(entry_y);
+ }
+
+ return !entry_x && !entry_y;
+}
+
+/**
+ * qlist_destroy_obj(): Free all the memory allocated by a QList
+ */
+void qlist_destroy_obj(QObject *obj)
+{
+ QList *qlist;
+ QListEntry *entry, *next_entry;
+
+ assert(obj != NULL);
+ qlist = qobject_to(QList, obj);
+
+ QTAILQ_FOREACH_SAFE(entry, &qlist->head, next, next_entry) {
+ QTAILQ_REMOVE(&qlist->head, entry, next);
+ qobject_unref(entry->value);
+ g_free(entry);
+ }
+
+ g_free(qlist);
+}
diff --git a/qobject/qlit.c b/qobject/qlit.c
new file mode 100644
index 000000000..be8332136
--- /dev/null
+++ b/qobject/qlit.c
@@ -0,0 +1,125 @@
+/*
+ * QLit literal qobject
+ *
+ * Copyright IBM, Corp. 2009
+ * Copyright (c) 2013, 2015, 2017 Red Hat Inc.
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ * Markus Armbruster <armbru@redhat.com>
+ * Marc-André Lureau <marcandre.lureau@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "qapi/qmp/qlit.h"
+#include "qapi/qmp/qbool.h"
+#include "qapi/qmp/qlist.h"
+#include "qapi/qmp/qnum.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qstring.h"
+#include "qapi/qmp/qnull.h"
+
+static bool qlit_equal_qdict(const QLitObject *lhs, const QDict *qdict)
+{
+ int i;
+
+ for (i = 0; lhs->value.qdict[i].key; i++) {
+ QObject *obj = qdict_get(qdict, lhs->value.qdict[i].key);
+
+ if (!qlit_equal_qobject(&lhs->value.qdict[i].value, obj)) {
+ return false;
+ }
+ }
+
+ /* Note: the literal qdict must not contain duplicates, this is
+ * considered a programming error and it isn't checked here. */
+ if (qdict_size(qdict) != i) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool qlit_equal_qlist(const QLitObject *lhs, const QList *qlist)
+{
+ QListEntry *e;
+ int i = 0;
+
+ QLIST_FOREACH_ENTRY(qlist, e) {
+ QObject *obj = qlist_entry_obj(e);
+
+ if (!qlit_equal_qobject(&lhs->value.qlist[i], obj)) {
+ return false;
+ }
+ i++;
+ }
+
+ return !e && lhs->value.qlist[i].type == QTYPE_NONE;
+}
+
+bool qlit_equal_qobject(const QLitObject *lhs, const QObject *rhs)
+{
+ if (!rhs || lhs->type != qobject_type(rhs)) {
+ return false;
+ }
+
+ switch (lhs->type) {
+ case QTYPE_QBOOL:
+ return lhs->value.qbool == qbool_get_bool(qobject_to(QBool, rhs));
+ case QTYPE_QNUM:
+ return lhs->value.qnum == qnum_get_int(qobject_to(QNum, rhs));
+ case QTYPE_QSTRING:
+ return (strcmp(lhs->value.qstr,
+ qstring_get_str(qobject_to(QString, rhs))) == 0);
+ case QTYPE_QDICT:
+ return qlit_equal_qdict(lhs, qobject_to(QDict, rhs));
+ case QTYPE_QLIST:
+ return qlit_equal_qlist(lhs, qobject_to(QList, rhs));
+ case QTYPE_QNULL:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+QObject *qobject_from_qlit(const QLitObject *qlit)
+{
+ switch (qlit->type) {
+ case QTYPE_QNULL:
+ return QOBJECT(qnull());
+ case QTYPE_QNUM:
+ return QOBJECT(qnum_from_int(qlit->value.qnum));
+ case QTYPE_QSTRING:
+ return QOBJECT(qstring_from_str(qlit->value.qstr));
+ case QTYPE_QDICT: {
+ QDict *qdict = qdict_new();
+ QLitDictEntry *e;
+
+ for (e = qlit->value.qdict; e->key; e++) {
+ qdict_put_obj(qdict, e->key, qobject_from_qlit(&e->value));
+ }
+ return QOBJECT(qdict);
+ }
+ case QTYPE_QLIST: {
+ QList *qlist = qlist_new();
+ QLitObject *e;
+
+ for (e = qlit->value.qlist; e->type != QTYPE_NONE; e++) {
+ qlist_append_obj(qlist, qobject_from_qlit(e));
+ }
+ return QOBJECT(qlist);
+ }
+ case QTYPE_QBOOL:
+ return QOBJECT(qbool_from_bool(qlit->value.qbool));
+ default:
+ assert(0);
+ }
+
+ return NULL;
+}
diff --git a/qobject/qnull.c b/qobject/qnull.c
new file mode 100644
index 000000000..b26b36821
--- /dev/null
+++ b/qobject/qnull.c
@@ -0,0 +1,31 @@
+/*
+ * QNull
+ *
+ * Copyright (C) 2015 Red Hat, Inc.
+ *
+ * Authors:
+ * Markus Armbruster <armbru@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1
+ * or later. See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qmp/qnull.h"
+#include "qobject-internal.h"
+
+QNull qnull_ = {
+ .base = {
+ .type = QTYPE_QNULL,
+ .refcnt = 1,
+ },
+};
+
+/**
+ * qnull_is_equal(): Always return true because any two QNull objects
+ * are equal.
+ */
+bool qnull_is_equal(const QObject *x, const QObject *y)
+{
+ return true;
+}
diff --git a/qobject/qnum.c b/qobject/qnum.c
new file mode 100644
index 000000000..5dd66938d
--- /dev/null
+++ b/qobject/qnum.c
@@ -0,0 +1,241 @@
+/*
+ * QNum Module
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ * Luiz Capitulino <lcapitulino@redhat.com>
+ * Anthony Liguori <aliguori@us.ibm.com>
+ * Marc-André Lureau <marcandre.lureau@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qmp/qnum.h"
+#include "qobject-internal.h"
+
+/**
+ * qnum_from_int(): Create a new QNum from an int64_t
+ *
+ * Return strong reference.
+ */
+QNum *qnum_from_int(int64_t value)
+{
+ QNum *qn = g_new(QNum, 1);
+
+ qobject_init(QOBJECT(qn), QTYPE_QNUM);
+ qn->kind = QNUM_I64;
+ qn->u.i64 = value;
+
+ return qn;
+}
+
+/**
+ * qnum_from_uint(): Create a new QNum from an uint64_t
+ *
+ * Return strong reference.
+ */
+QNum *qnum_from_uint(uint64_t value)
+{
+ QNum *qn = g_new(QNum, 1);
+
+ qobject_init(QOBJECT(qn), QTYPE_QNUM);
+ qn->kind = QNUM_U64;
+ qn->u.u64 = value;
+
+ return qn;
+}
+
+/**
+ * qnum_from_double(): Create a new QNum from a double
+ *
+ * Return strong reference.
+ */
+QNum *qnum_from_double(double value)
+{
+ QNum *qn = g_new(QNum, 1);
+
+ qobject_init(QOBJECT(qn), QTYPE_QNUM);
+ qn->kind = QNUM_DOUBLE;
+ qn->u.dbl = value;
+
+ return qn;
+}
+
+/**
+ * qnum_get_try_int(): Get an integer representation of the number
+ *
+ * Return true on success.
+ */
+bool qnum_get_try_int(const QNum *qn, int64_t *val)
+{
+ switch (qn->kind) {
+ case QNUM_I64:
+ *val = qn->u.i64;
+ return true;
+ case QNUM_U64:
+ if (qn->u.u64 > INT64_MAX) {
+ return false;
+ }
+ *val = qn->u.u64;
+ return true;
+ case QNUM_DOUBLE:
+ return false;
+ }
+
+ assert(0);
+ return false;
+}
+
+/**
+ * qnum_get_int(): Get an integer representation of the number
+ *
+ * assert() on failure.
+ */
+int64_t qnum_get_int(const QNum *qn)
+{
+ int64_t val;
+ bool success = qnum_get_try_int(qn, &val);
+ assert(success);
+ return val;
+}
+
+/**
+ * qnum_get_uint(): Get an unsigned integer from the number
+ *
+ * Return true on success.
+ */
+bool qnum_get_try_uint(const QNum *qn, uint64_t *val)
+{
+ switch (qn->kind) {
+ case QNUM_I64:
+ if (qn->u.i64 < 0) {
+ return false;
+ }
+ *val = qn->u.i64;
+ return true;
+ case QNUM_U64:
+ *val = qn->u.u64;
+ return true;
+ case QNUM_DOUBLE:
+ return false;
+ }
+
+ assert(0);
+ return false;
+}
+
+/**
+ * qnum_get_uint(): Get an unsigned integer from the number
+ *
+ * assert() on failure.
+ */
+uint64_t qnum_get_uint(const QNum *qn)
+{
+ uint64_t val;
+ bool success = qnum_get_try_uint(qn, &val);
+ assert(success);
+ return val;
+}
+
+/**
+ * qnum_get_double(): Get a float representation of the number
+ *
+ * qnum_get_double() loses precision for integers beyond 53 bits.
+ */
+double qnum_get_double(QNum *qn)
+{
+ switch (qn->kind) {
+ case QNUM_I64:
+ return qn->u.i64;
+ case QNUM_U64:
+ return qn->u.u64;
+ case QNUM_DOUBLE:
+ return qn->u.dbl;
+ }
+
+ assert(0);
+ return 0.0;
+}
+
+char *qnum_to_string(QNum *qn)
+{
+ switch (qn->kind) {
+ case QNUM_I64:
+ return g_strdup_printf("%" PRId64, qn->u.i64);
+ case QNUM_U64:
+ return g_strdup_printf("%" PRIu64, qn->u.u64);
+ case QNUM_DOUBLE:
+ /* 17 digits suffice for IEEE double */
+ return g_strdup_printf("%.17g", qn->u.dbl);
+ }
+
+ assert(0);
+ return NULL;
+}
+
+/**
+ * qnum_is_equal(): Test whether the two QNums are equal
+ *
+ * Negative integers are never considered equal to unsigned integers,
+ * but positive integers in the range [0, INT64_MAX] are considered
+ * equal independently of whether the QNum's kind is i64 or u64.
+ *
+ * Doubles are never considered equal to integers.
+ */
+bool qnum_is_equal(const QObject *x, const QObject *y)
+{
+ QNum *num_x = qobject_to(QNum, x);
+ QNum *num_y = qobject_to(QNum, y);
+
+ switch (num_x->kind) {
+ case QNUM_I64:
+ switch (num_y->kind) {
+ case QNUM_I64:
+ /* Comparison in native int64_t type */
+ return num_x->u.i64 == num_y->u.i64;
+ case QNUM_U64:
+ /* Implicit conversion of x to uin64_t, so we have to
+ * check its sign before */
+ return num_x->u.i64 >= 0 && num_x->u.i64 == num_y->u.u64;
+ case QNUM_DOUBLE:
+ return false;
+ }
+ abort();
+ case QNUM_U64:
+ switch (num_y->kind) {
+ case QNUM_I64:
+ return qnum_is_equal(y, x);
+ case QNUM_U64:
+ /* Comparison in native uint64_t type */
+ return num_x->u.u64 == num_y->u.u64;
+ case QNUM_DOUBLE:
+ return false;
+ }
+ abort();
+ case QNUM_DOUBLE:
+ switch (num_y->kind) {
+ case QNUM_I64:
+ case QNUM_U64:
+ return false;
+ case QNUM_DOUBLE:
+ /* Comparison in native double type */
+ return num_x->u.dbl == num_y->u.dbl;
+ }
+ abort();
+ }
+
+ abort();
+}
+
+/**
+ * qnum_destroy_obj(): Free all memory allocated by a
+ * QNum object
+ */
+void qnum_destroy_obj(QObject *obj)
+{
+ assert(obj != NULL);
+ g_free(qobject_to(QNum, obj));
+}
diff --git a/qobject/qobject-internal.h b/qobject/qobject-internal.h
new file mode 100644
index 000000000..b310c8e1b
--- /dev/null
+++ b/qobject/qobject-internal.h
@@ -0,0 +1,39 @@
+/*
+ * QObject internals
+ *
+ * Copyright (C) 2015 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1
+ * or later. See the COPYING.LIB file in the top-level directory.
+ */
+
+#ifndef QOBJECT_INTERNAL_H
+#define QOBJECT_INTERNAL_H
+
+#include "qapi/qmp/qobject.h"
+
+static inline void qobject_init(QObject *obj, QType type)
+{
+ assert(QTYPE_NONE < type && type < QTYPE__MAX);
+ obj->base.refcnt = 1;
+ obj->base.type = type;
+}
+
+void qbool_destroy_obj(QObject *obj);
+bool qbool_is_equal(const QObject *x, const QObject *y);
+
+void qdict_destroy_obj(QObject *obj);
+bool qdict_is_equal(const QObject *x, const QObject *y);
+
+void qlist_destroy_obj(QObject *obj);
+bool qlist_is_equal(const QObject *x, const QObject *y);
+
+bool qnull_is_equal(const QObject *x, const QObject *y);
+
+void qnum_destroy_obj(QObject *obj);
+bool qnum_is_equal(const QObject *x, const QObject *y);
+
+void qstring_destroy_obj(QObject *obj);
+bool qstring_is_equal(const QObject *x, const QObject *y);
+
+#endif
diff --git a/qobject/qobject.c b/qobject/qobject.c
new file mode 100644
index 000000000..d7077b8f2
--- /dev/null
+++ b/qobject/qobject.c
@@ -0,0 +1,72 @@
+/*
+ * QObject
+ *
+ * Copyright (C) 2015 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1
+ * or later. See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qmp/qbool.h"
+#include "qapi/qmp/qnull.h"
+#include "qapi/qmp/qnum.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qlist.h"
+#include "qapi/qmp/qstring.h"
+#include "qobject-internal.h"
+
+QEMU_BUILD_BUG_MSG(
+ offsetof(QNull, base) != 0 ||
+ offsetof(QNum, base) != 0 ||
+ offsetof(QString, base) != 0 ||
+ offsetof(QDict, base) != 0 ||
+ offsetof(QList, base) != 0 ||
+ offsetof(QBool, base) != 0,
+ "base qobject must be at offset 0");
+
+static void (*qdestroy[QTYPE__MAX])(QObject *) = {
+ [QTYPE_NONE] = NULL, /* No such object exists */
+ [QTYPE_QNULL] = NULL, /* qnull_ is indestructible */
+ [QTYPE_QNUM] = qnum_destroy_obj,
+ [QTYPE_QSTRING] = qstring_destroy_obj,
+ [QTYPE_QDICT] = qdict_destroy_obj,
+ [QTYPE_QLIST] = qlist_destroy_obj,
+ [QTYPE_QBOOL] = qbool_destroy_obj,
+};
+
+void qobject_destroy(QObject *obj)
+{
+ assert(!obj->base.refcnt);
+ assert(QTYPE_QNULL < obj->base.type && obj->base.type < QTYPE__MAX);
+ qdestroy[obj->base.type](obj);
+}
+
+
+static bool (*qis_equal[QTYPE__MAX])(const QObject *, const QObject *) = {
+ [QTYPE_NONE] = NULL, /* No such object exists */
+ [QTYPE_QNULL] = qnull_is_equal,
+ [QTYPE_QNUM] = qnum_is_equal,
+ [QTYPE_QSTRING] = qstring_is_equal,
+ [QTYPE_QDICT] = qdict_is_equal,
+ [QTYPE_QLIST] = qlist_is_equal,
+ [QTYPE_QBOOL] = qbool_is_equal,
+};
+
+bool qobject_is_equal(const QObject *x, const QObject *y)
+{
+ /* We cannot test x == y because an object does not need to be
+ * equal to itself (e.g. NaN floats are not). */
+
+ if (!x && !y) {
+ return true;
+ }
+
+ if (!x || !y || x->base.type != y->base.type) {
+ return false;
+ }
+
+ assert(QTYPE_NONE < x->base.type && x->base.type < QTYPE__MAX);
+
+ return qis_equal[x->base.type](x, y);
+}
diff --git a/qobject/qstring.c b/qobject/qstring.c
new file mode 100644
index 000000000..b4613899b
--- /dev/null
+++ b/qobject/qstring.c
@@ -0,0 +1,102 @@
+/*
+ * QString Module
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ * Luiz Capitulino <lcapitulino@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qmp/qstring.h"
+#include "qobject-internal.h"
+
+/**
+ * qstring_new(): Create a new empty QString
+ *
+ * Return strong reference.
+ */
+QString *qstring_new(void)
+{
+ return qstring_from_str("");
+}
+
+/**
+ * qstring_from_substr(): Create a new QString from a C string substring
+ *
+ * Return string reference
+ */
+QString *qstring_from_substr(const char *str, size_t start, size_t end)
+{
+ QString *qstring;
+
+ assert(start <= end);
+ qstring = g_malloc(sizeof(*qstring));
+ qobject_init(QOBJECT(qstring), QTYPE_QSTRING);
+ qstring->string = g_strndup(str + start, end - start);
+ return qstring;
+}
+
+/**
+ * qstring_from_str(): Create a new QString from a regular C string
+ *
+ * Return strong reference.
+ */
+QString *qstring_from_str(const char *str)
+{
+ return qstring_from_substr(str, 0, strlen(str));
+}
+
+/**
+ * qstring_from_gstring(): Convert a GString to a QString
+ *
+ * Return strong reference.
+ */
+
+QString *qstring_from_gstring(GString *gstr)
+{
+ QString *qstring;
+
+ qstring = g_malloc(sizeof(*qstring));
+ qobject_init(QOBJECT(qstring), QTYPE_QSTRING);
+ qstring->string = g_string_free(gstr, false);
+ return qstring;
+}
+
+
+/**
+ * qstring_get_str(): Return a pointer to the stored string
+ *
+ * NOTE: Should be used with caution, if the object is deallocated
+ * this pointer becomes invalid.
+ */
+const char *qstring_get_str(const QString *qstring)
+{
+ return qstring->string;
+}
+
+/**
+ * qstring_is_equal(): Test whether the two QStrings are equal
+ */
+bool qstring_is_equal(const QObject *x, const QObject *y)
+{
+ return !strcmp(qobject_to(QString, x)->string,
+ qobject_to(QString, y)->string);
+}
+
+/**
+ * qstring_destroy_obj(): Free all memory allocated by a QString
+ * object
+ */
+void qstring_destroy_obj(QObject *obj)
+{
+ QString *qs;
+
+ assert(obj != NULL);
+ qs = qobject_to(QString, obj);
+ g_free((char *)qs->string);
+ g_free(qs);
+}