summaryrefslogtreecommitdiffstats
path: root/qemu/qobject
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/qobject')
-rw-r--r--qemu/qobject/Makefile.objs2
-rw-r--r--qemu/qobject/json-lexer.c48
-rw-r--r--qemu/qobject/json-parser.c340
-rw-r--r--qemu/qobject/json-streamer.c92
-rw-r--r--qemu/qobject/qbool.c16
-rw-r--r--qemu/qobject/qdict.c55
-rw-r--r--qemu/qobject/qfloat.c16
-rw-r--r--qemu/qobject/qint.c16
-rw-r--r--qemu/qobject/qjson.c15
-rw-r--r--qemu/qobject/qlist.c15
-rw-r--r--qemu/qobject/qnull.c13
-rw-r--r--qemu/qobject/qobject.c35
-rw-r--r--qemu/qobject/qstring.c16
13 files changed, 269 insertions, 410 deletions
diff --git a/qemu/qobject/Makefile.objs b/qemu/qobject/Makefile.objs
index 0031e8b69..bed55084b 100644
--- a/qemu/qobject/Makefile.objs
+++ b/qemu/qobject/Makefile.objs
@@ -1,2 +1,2 @@
util-obj-y = qnull.o qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o
-util-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o
+util-obj-y += qjson.o qobject.o json-lexer.o json-streamer.o json-parser.o
diff --git a/qemu/qobject/json-lexer.c b/qemu/qobject/json-lexer.c
index b19623e22..496374d9a 100644
--- a/qemu/qobject/json-lexer.c
+++ b/qemu/qobject/json-lexer.c
@@ -11,10 +11,7 @@
*
*/
-#include "qapi/qmp/qstring.h"
-#include "qapi/qmp/qlist.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qint.h"
+#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qapi/qmp/json-lexer.h"
@@ -30,7 +27,7 @@
*/
enum json_lexer_state {
- IN_ERROR = 0,
+ IN_ERROR = 0, /* must really be 0, see json_lexer[] */
IN_DQ_UCODE3,
IN_DQ_UCODE2,
IN_DQ_UCODE1,
@@ -62,6 +59,8 @@ enum json_lexer_state {
IN_START,
};
+QEMU_BUILD_BUG_ON((int)JSON_MIN <= (int)IN_START);
+
#define TERMINAL(state) [0 ... 0x7F] = (state)
/* Return whether TERMINAL is a terminal state and the transition to it
@@ -71,6 +70,8 @@ enum json_lexer_state {
(json_lexer[(old_state)][0] == (terminal))
static const uint8_t json_lexer[][256] = {
+ /* Relies on default initialization to IN_ERROR! */
+
/* double quote string */
[IN_DQ_UCODE3] = {
['0' ... '9'] = IN_DQ_STRING,
@@ -253,12 +254,12 @@ static const uint8_t json_lexer[][256] = {
['0'] = IN_ZERO,
['1' ... '9'] = IN_NONZERO_NUMBER,
['-'] = IN_NEG_NONZERO_NUMBER,
- ['{'] = JSON_OPERATOR,
- ['}'] = JSON_OPERATOR,
- ['['] = JSON_OPERATOR,
- [']'] = JSON_OPERATOR,
- [','] = JSON_OPERATOR,
- [':'] = JSON_OPERATOR,
+ ['{'] = JSON_LCURLY,
+ ['}'] = JSON_RCURLY,
+ ['['] = JSON_LSQUARE,
+ [']'] = JSON_RSQUARE,
+ [','] = JSON_COMMA,
+ [':'] = JSON_COLON,
['a' ... 'z'] = IN_KEYWORD,
['%'] = IN_ESCAPE,
[' '] = IN_WHITESPACE,
@@ -272,7 +273,7 @@ void json_lexer_init(JSONLexer *lexer, JSONLexerEmitter func)
{
lexer->emit = func;
lexer->state = IN_START;
- lexer->token = qstring_new();
+ lexer->token = g_string_sized_new(3);
lexer->x = lexer->y = 0;
}
@@ -287,14 +288,20 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush)
}
do {
+ assert(lexer->state <= ARRAY_SIZE(json_lexer));
new_state = json_lexer[lexer->state][(uint8_t)ch];
char_consumed = !TERMINAL_NEEDED_LOOKAHEAD(lexer->state, new_state);
if (char_consumed) {
- qstring_append_chr(lexer->token, ch);
+ g_string_append_c(lexer->token, ch);
}
switch (new_state) {
- case JSON_OPERATOR:
+ case JSON_LCURLY:
+ case JSON_RCURLY:
+ case JSON_LSQUARE:
+ case JSON_RSQUARE:
+ case JSON_COLON:
+ case JSON_COMMA:
case JSON_ESCAPE:
case JSON_INTEGER:
case JSON_FLOAT:
@@ -303,8 +310,7 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush)
lexer->emit(lexer, lexer->token, new_state, lexer->x, lexer->y);
/* fall through */
case JSON_SKIP:
- QDECREF(lexer->token);
- lexer->token = qstring_new();
+ g_string_truncate(lexer->token, 0);
new_state = IN_START;
break;
case IN_ERROR:
@@ -322,8 +328,7 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush)
* induce an error/flush state.
*/
lexer->emit(lexer, lexer->token, JSON_ERROR, lexer->x, lexer->y);
- QDECREF(lexer->token);
- lexer->token = qstring_new();
+ g_string_truncate(lexer->token, 0);
new_state = IN_START;
lexer->state = new_state;
return 0;
@@ -336,10 +341,9 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush)
/* Do not let a single token grow to an arbitrarily large size,
* this is a security consideration.
*/
- if (lexer->token->length > MAX_TOKEN_SIZE) {
+ if (lexer->token->len > MAX_TOKEN_SIZE) {
lexer->emit(lexer, lexer->token, lexer->state, lexer->x, lexer->y);
- QDECREF(lexer->token);
- lexer->token = qstring_new();
+ g_string_truncate(lexer->token, 0);
lexer->state = IN_START;
}
@@ -369,5 +373,5 @@ int json_lexer_flush(JSONLexer *lexer)
void json_lexer_destroy(JSONLexer *lexer)
{
- QDECREF(lexer->token);
+ g_string_free(lexer->token, true);
}
diff --git a/qemu/qobject/json-parser.c b/qemu/qobject/json-parser.c
index ac991ba3c..67ed72731 100644
--- a/qemu/qobject/json-parser.c
+++ b/qemu/qobject/json-parser.c
@@ -1,5 +1,5 @@
/*
- * JSON Parser
+ * JSON Parser
*
* Copyright IBM, Corp. 2009
*
@@ -11,8 +11,8 @@
*
*/
-#include <stdarg.h>
-
+#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "qemu-common.h"
#include "qapi/qmp/qstring.h"
#include "qapi/qmp/qint.h"
@@ -22,15 +22,13 @@
#include "qapi/qmp/qbool.h"
#include "qapi/qmp/json-parser.h"
#include "qapi/qmp/json-lexer.h"
+#include "qapi/qmp/json-streamer.h"
typedef struct JSONParserContext
{
Error *err;
- struct {
- QObject **buf;
- size_t pos;
- size_t count;
- } tokens;
+ JSONToken *current;
+ GQueue *buf;
} JSONParserContext;
#define BUG_ON(cond) assert(!(cond))
@@ -47,58 +45,10 @@ typedef struct JSONParserContext
static QObject *parse_value(JSONParserContext *ctxt, va_list *ap);
/**
- * Token manipulators
- *
- * tokens are dictionaries that contain a type, a string value, and geometry information
- * about a token identified by the lexer. These are routines that make working with
- * these objects a bit easier.
- */
-static const char *token_get_value(QObject *obj)
-{
- return qdict_get_str(qobject_to_qdict(obj), "token");
-}
-
-static JSONTokenType token_get_type(QObject *obj)
-{
- return qdict_get_int(qobject_to_qdict(obj), "type");
-}
-
-static int token_is_operator(QObject *obj, char op)
-{
- const char *val;
-
- if (token_get_type(obj) != JSON_OPERATOR) {
- return 0;
- }
-
- val = token_get_value(obj);
-
- return (val[0] == op) && (val[1] == 0);
-}
-
-static int token_is_keyword(QObject *obj, const char *value)
-{
- if (token_get_type(obj) != JSON_KEYWORD) {
- return 0;
- }
-
- return strcmp(token_get_value(obj), value) == 0;
-}
-
-static int token_is_escape(QObject *obj, const char *value)
-{
- if (token_get_type(obj) != JSON_ESCAPE) {
- return 0;
- }
-
- return (strcmp(token_get_value(obj), value) == 0);
-}
-
-/**
* Error handler
*/
static void GCC_FMT_ATTR(3, 4) parse_error(JSONParserContext *ctxt,
- QObject *token, const char *msg, ...)
+ JSONToken *token, const char *msg, ...)
{
va_list ap;
char message[1024];
@@ -176,9 +126,10 @@ static int hex2decimal(char ch)
* \t
* \u four-hex-digits
*/
-static QString *qstring_from_escaped_str(JSONParserContext *ctxt, QObject *token)
+static QString *qstring_from_escaped_str(JSONParserContext *ctxt,
+ JSONToken *token)
{
- const char *ptr = token_get_value(token);
+ const char *ptr = token->str;
QString *str;
int double_quote = 1;
@@ -274,73 +225,34 @@ out:
return NULL;
}
-static QObject *parser_context_pop_token(JSONParserContext *ctxt)
-{
- QObject *token;
- g_assert(ctxt->tokens.pos < ctxt->tokens.count);
- token = ctxt->tokens.buf[ctxt->tokens.pos];
- ctxt->tokens.pos++;
- return token;
-}
-
-/* Note: parser_context_{peek|pop}_token do not increment the
- * token object's refcount. In both cases the references will continue
- * to be tracked and cleaned up in parser_context_free(), so do not
- * attempt to free the token object.
+/* 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 QObject *parser_context_peek_token(JSONParserContext *ctxt)
-{
- QObject *token;
- g_assert(ctxt->tokens.pos < ctxt->tokens.count);
- token = ctxt->tokens.buf[ctxt->tokens.pos];
- return token;
-}
-
-static JSONParserContext parser_context_save(JSONParserContext *ctxt)
-{
- JSONParserContext saved_ctxt = {0};
- saved_ctxt.tokens.pos = ctxt->tokens.pos;
- saved_ctxt.tokens.count = ctxt->tokens.count;
- saved_ctxt.tokens.buf = ctxt->tokens.buf;
- return saved_ctxt;
-}
-
-static void parser_context_restore(JSONParserContext *ctxt,
- JSONParserContext saved_ctxt)
+static JSONToken *parser_context_pop_token(JSONParserContext *ctxt)
{
- ctxt->tokens.pos = saved_ctxt.tokens.pos;
- ctxt->tokens.count = saved_ctxt.tokens.count;
- ctxt->tokens.buf = saved_ctxt.tokens.buf;
+ g_free(ctxt->current);
+ assert(!g_queue_is_empty(ctxt->buf));
+ ctxt->current = g_queue_pop_head(ctxt->buf);
+ return ctxt->current;
}
-static void tokens_append_from_iter(QObject *obj, void *opaque)
+static JSONToken *parser_context_peek_token(JSONParserContext *ctxt)
{
- JSONParserContext *ctxt = opaque;
- g_assert(ctxt->tokens.pos < ctxt->tokens.count);
- ctxt->tokens.buf[ctxt->tokens.pos++] = obj;
- qobject_incref(obj);
+ assert(!g_queue_is_empty(ctxt->buf));
+ return g_queue_peek_head(ctxt->buf);
}
-static JSONParserContext *parser_context_new(QList *tokens)
+static JSONParserContext *parser_context_new(GQueue *tokens)
{
JSONParserContext *ctxt;
- size_t count;
if (!tokens) {
return NULL;
}
- count = qlist_size(tokens);
- if (count == 0) {
- return NULL;
- }
-
ctxt = g_malloc0(sizeof(JSONParserContext));
- ctxt->tokens.pos = 0;
- ctxt->tokens.count = count;
- ctxt->tokens.buf = g_malloc(count * sizeof(QObject *));
- qlist_iter(tokens, tokens_append_from_iter, ctxt);
- ctxt->tokens.pos = 0;
+ ctxt->buf = tokens;
return ctxt;
}
@@ -348,12 +260,12 @@ static JSONParserContext *parser_context_new(QList *tokens)
/* to support error propagation, ctxt->err must be freed separately */
static void parser_context_free(JSONParserContext *ctxt)
{
- int i;
if (ctxt) {
- for (i = 0; i < ctxt->tokens.count; i++) {
- qobject_decref(ctxt->tokens.buf[i]);
+ while (!g_queue_is_empty(ctxt->buf)) {
+ parser_context_pop_token(ctxt);
}
- g_free(ctxt->tokens.buf);
+ g_free(ctxt->current);
+ g_queue_free(ctxt->buf);
g_free(ctxt);
}
}
@@ -363,8 +275,8 @@ static void parser_context_free(JSONParserContext *ctxt)
*/
static int parse_pair(JSONParserContext *ctxt, QDict *dict, va_list *ap)
{
- QObject *key = NULL, *token = NULL, *value, *peek;
- JSONParserContext saved_ctxt = parser_context_save(ctxt);
+ QObject *key = NULL, *value;
+ JSONToken *peek, *token;
peek = parser_context_peek_token(ctxt);
if (peek == NULL) {
@@ -384,7 +296,7 @@ static int parse_pair(JSONParserContext *ctxt, QDict *dict, va_list *ap)
goto out;
}
- if (!token_is_operator(token, ':')) {
+ if (token->type != JSON_COLON) {
parse_error(ctxt, token, "missing : in object pair");
goto out;
}
@@ -402,7 +314,6 @@ static int parse_pair(JSONParserContext *ctxt, QDict *dict, va_list *ap)
return 0;
out:
- parser_context_restore(ctxt, saved_ctxt);
qobject_decref(key);
return -1;
@@ -411,17 +322,10 @@ out:
static QObject *parse_object(JSONParserContext *ctxt, va_list *ap)
{
QDict *dict = NULL;
- QObject *token, *peek;
- JSONParserContext saved_ctxt = parser_context_save(ctxt);
+ JSONToken *token, *peek;
token = parser_context_pop_token(ctxt);
- if (token == NULL) {
- goto out;
- }
-
- if (!token_is_operator(token, '{')) {
- goto out;
- }
+ assert(token && token->type == JSON_LCURLY);
dict = qdict_new();
@@ -431,7 +335,7 @@ static QObject *parse_object(JSONParserContext *ctxt, va_list *ap)
goto out;
}
- if (!token_is_operator(peek, '}')) {
+ if (peek->type != JSON_RCURLY) {
if (parse_pair(ctxt, dict, ap) == -1) {
goto out;
}
@@ -442,8 +346,8 @@ static QObject *parse_object(JSONParserContext *ctxt, va_list *ap)
goto out;
}
- while (!token_is_operator(token, '}')) {
- if (!token_is_operator(token, ',')) {
+ while (token->type != JSON_RCURLY) {
+ if (token->type != JSON_COMMA) {
parse_error(ctxt, token, "expected separator in dict");
goto out;
}
@@ -465,7 +369,6 @@ static QObject *parse_object(JSONParserContext *ctxt, va_list *ap)
return QOBJECT(dict);
out:
- parser_context_restore(ctxt, saved_ctxt);
QDECREF(dict);
return NULL;
}
@@ -473,17 +376,10 @@ out:
static QObject *parse_array(JSONParserContext *ctxt, va_list *ap)
{
QList *list = NULL;
- QObject *token, *peek;
- JSONParserContext saved_ctxt = parser_context_save(ctxt);
+ JSONToken *token, *peek;
token = parser_context_pop_token(ctxt);
- if (token == NULL) {
- goto out;
- }
-
- if (!token_is_operator(token, '[')) {
- goto out;
- }
+ assert(token && token->type == JSON_LSQUARE);
list = qlist_new();
@@ -493,7 +389,7 @@ static QObject *parse_array(JSONParserContext *ctxt, va_list *ap)
goto out;
}
- if (!token_is_operator(peek, ']')) {
+ if (peek->type != JSON_RSQUARE) {
QObject *obj;
obj = parse_value(ctxt, ap);
@@ -510,8 +406,8 @@ static QObject *parse_array(JSONParserContext *ctxt, va_list *ap)
goto out;
}
- while (!token_is_operator(token, ']')) {
- if (!token_is_operator(token, ',')) {
+ while (token->type != JSON_RSQUARE) {
+ if (token->type != JSON_COMMA) {
parse_error(ctxt, token, "expected separator in list");
goto out;
}
@@ -537,99 +433,68 @@ static QObject *parse_array(JSONParserContext *ctxt, va_list *ap)
return QOBJECT(list);
out:
- parser_context_restore(ctxt, saved_ctxt);
QDECREF(list);
return NULL;
}
static QObject *parse_keyword(JSONParserContext *ctxt)
{
- QObject *token, *ret;
- JSONParserContext saved_ctxt = parser_context_save(ctxt);
+ JSONToken *token;
token = parser_context_pop_token(ctxt);
- if (token == NULL) {
- goto out;
- }
-
- if (token_get_type(token) != JSON_KEYWORD) {
- goto out;
- }
+ assert(token && token->type == JSON_KEYWORD);
- if (token_is_keyword(token, "true")) {
- ret = QOBJECT(qbool_from_bool(true));
- } else if (token_is_keyword(token, "false")) {
- ret = QOBJECT(qbool_from_bool(false));
- } else if (token_is_keyword(token, "null")) {
- ret = qnull();
- } else {
- parse_error(ctxt, token, "invalid keyword `%s'", token_get_value(token));
- goto out;
+ 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 qnull();
}
-
- return ret;
-
-out:
- parser_context_restore(ctxt, saved_ctxt);
-
+ parse_error(ctxt, token, "invalid keyword '%s'", token->str);
return NULL;
}
static QObject *parse_escape(JSONParserContext *ctxt, va_list *ap)
{
- QObject *token = NULL, *obj;
- JSONParserContext saved_ctxt = parser_context_save(ctxt);
+ JSONToken *token;
if (ap == NULL) {
- goto out;
+ return NULL;
}
token = parser_context_pop_token(ctxt);
- if (token == NULL) {
- goto out;
- }
-
- if (token_is_escape(token, "%p")) {
- obj = va_arg(*ap, QObject *);
- } else if (token_is_escape(token, "%i")) {
- obj = QOBJECT(qbool_from_bool(va_arg(*ap, int)));
- } else if (token_is_escape(token, "%d")) {
- obj = QOBJECT(qint_from_int(va_arg(*ap, int)));
- } else if (token_is_escape(token, "%ld")) {
- obj = QOBJECT(qint_from_int(va_arg(*ap, long)));
- } else if (token_is_escape(token, "%lld") ||
- token_is_escape(token, "%I64d")) {
- obj = QOBJECT(qint_from_int(va_arg(*ap, long long)));
- } else if (token_is_escape(token, "%s")) {
- obj = QOBJECT(qstring_from_str(va_arg(*ap, const char *)));
- } else if (token_is_escape(token, "%f")) {
- obj = QOBJECT(qfloat_from_double(va_arg(*ap, double)));
- } else {
- goto out;
+ assert(token && token->type == JSON_ESCAPE);
+
+ if (!strcmp(token->str, "%p")) {
+ return va_arg(*ap, QObject *);
+ } else if (!strcmp(token->str, "%i")) {
+ return QOBJECT(qbool_from_bool(va_arg(*ap, int)));
+ } else if (!strcmp(token->str, "%d")) {
+ return QOBJECT(qint_from_int(va_arg(*ap, int)));
+ } else if (!strcmp(token->str, "%ld")) {
+ return QOBJECT(qint_from_int(va_arg(*ap, long)));
+ } else if (!strcmp(token->str, "%lld") ||
+ !strcmp(token->str, "%I64d")) {
+ return QOBJECT(qint_from_int(va_arg(*ap, long long)));
+ } else if (!strcmp(token->str, "%s")) {
+ return QOBJECT(qstring_from_str(va_arg(*ap, const char *)));
+ } else if (!strcmp(token->str, "%f")) {
+ return QOBJECT(qfloat_from_double(va_arg(*ap, double)));
}
-
- return obj;
-
-out:
- parser_context_restore(ctxt, saved_ctxt);
-
return NULL;
}
static QObject *parse_literal(JSONParserContext *ctxt)
{
- QObject *token, *obj;
- JSONParserContext saved_ctxt = parser_context_save(ctxt);
+ JSONToken *token;
token = parser_context_pop_token(ctxt);
- if (token == NULL) {
- goto out;
- }
+ assert(token);
- switch (token_get_type(token)) {
+ switch (token->type) {
case JSON_STRING:
- obj = QOBJECT(qstring_from_escaped_str(ctxt, token));
- break;
+ return QOBJECT(qstring_from_escaped_str(ctxt, token));
case JSON_INTEGER: {
/* A possibility exists that this is a whole-valued float where the
* fractional part was left out due to being 0 (.0). It's not a big
@@ -646,56 +511,57 @@ static QObject *parse_literal(JSONParserContext *ctxt)
int64_t value;
errno = 0; /* strtoll doesn't set errno on success */
- value = strtoll(token_get_value(token), NULL, 10);
+ value = strtoll(token->str, NULL, 10);
if (errno != ERANGE) {
- obj = QOBJECT(qint_from_int(value));
- break;
+ return QOBJECT(qint_from_int(value));
}
/* fall through to JSON_FLOAT */
}
case JSON_FLOAT:
- /* FIXME dependent on locale */
- obj = QOBJECT(qfloat_from_double(strtod(token_get_value(token), NULL)));
- break;
+ /* FIXME dependent on locale; a pervasive issue in QEMU */
+ /* FIXME our lexer matches RFC 7159 in forbidding Inf or NaN,
+ * but those might be useful extensions beyond JSON */
+ return QOBJECT(qfloat_from_double(strtod(token->str, NULL)));
default:
- goto out;
+ abort();
}
-
- return obj;
-
-out:
- parser_context_restore(ctxt, saved_ctxt);
-
- return NULL;
}
static QObject *parse_value(JSONParserContext *ctxt, va_list *ap)
{
- QObject *obj;
+ JSONToken *token;
- obj = parse_object(ctxt, ap);
- if (obj == NULL) {
- obj = parse_array(ctxt, ap);
- }
- if (obj == NULL) {
- obj = parse_escape(ctxt, ap);
- }
- if (obj == NULL) {
- obj = parse_keyword(ctxt);
- }
- if (obj == NULL) {
- obj = parse_literal(ctxt);
+ token = parser_context_peek_token(ctxt);
+ if (token == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ return NULL;
}
- return obj;
+ switch (token->type) {
+ case JSON_LCURLY:
+ return parse_object(ctxt, ap);
+ case JSON_LSQUARE:
+ return parse_array(ctxt, ap);
+ case JSON_ESCAPE:
+ return parse_escape(ctxt, ap);
+ 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;
+ }
}
-QObject *json_parser_parse(QList *tokens, va_list *ap)
+QObject *json_parser_parse(GQueue *tokens, va_list *ap)
{
return json_parser_parse_err(tokens, ap, NULL);
}
-QObject *json_parser_parse_err(QList *tokens, va_list *ap, Error **errp)
+QObject *json_parser_parse_err(GQueue *tokens, va_list *ap, Error **errp)
{
JSONParserContext *ctxt = parser_context_new(tokens);
QObject *result;
diff --git a/qemu/qobject/json-streamer.c b/qemu/qobject/json-streamer.c
index 1b2f9b1d1..02516853a 100644
--- a/qemu/qobject/json-streamer.c
+++ b/qemu/qobject/json-streamer.c
@@ -11,50 +11,56 @@
*
*/
-#include "qapi/qmp/qlist.h"
-#include "qapi/qmp/qint.h"
-#include "qapi/qmp/qdict.h"
+#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qapi/qmp/json-lexer.h"
#include "qapi/qmp/json-streamer.h"
#define MAX_TOKEN_SIZE (64ULL << 20)
+#define MAX_TOKEN_COUNT (2ULL << 20)
#define MAX_NESTING (1ULL << 10)
-static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTokenType type, int x, int y)
+static void json_message_free_tokens(JSONMessageParser *parser)
+{
+ if (parser->tokens) {
+ g_queue_free(parser->tokens);
+ parser->tokens = NULL;
+ }
+}
+
+static void json_message_process_token(JSONLexer *lexer, GString *input,
+ JSONTokenType type, int x, int y)
{
JSONMessageParser *parser = container_of(lexer, JSONMessageParser, lexer);
- QDict *dict;
-
- if (type == JSON_OPERATOR) {
- switch (qstring_get_str(token)[0]) {
- case '{':
- parser->brace_count++;
- break;
- case '}':
- parser->brace_count--;
- break;
- case '[':
- parser->bracket_count++;
- break;
- case ']':
- parser->bracket_count--;
- break;
- default:
- break;
- }
+ 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;
+ default:
+ break;
}
- dict = qdict_new();
- qdict_put(dict, "type", qint_from_int(type));
- QINCREF(token);
- qdict_put(dict, "token", token);
- qdict_put(dict, "x", qint_from_int(x));
- qdict_put(dict, "y", qint_from_int(y));
+ token = g_malloc(sizeof(JSONToken) + input->len + 1);
+ token->type = type;
+ memcpy(token->str, input->str, input->len);
+ token->str[input->len] = 0;
+ token->x = x;
+ token->y = y;
- parser->token_size += token->length;
+ parser->token_size += input->len;
- qlist_append(parser->tokens, dict);
+ g_queue_push_tail(parser->tokens, token);
if (type == JSON_ERROR) {
goto out_emit_bad;
@@ -64,41 +70,39 @@ static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTok
parser->bracket_count == 0)) {
goto out_emit;
} else if (parser->token_size > MAX_TOKEN_SIZE ||
- parser->bracket_count > MAX_NESTING ||
- parser->brace_count > MAX_NESTING) {
+ g_queue_get_length(parser->tokens) > MAX_TOKEN_COUNT ||
+ parser->bracket_count + parser->brace_count > MAX_NESTING) {
/* Security consideration, we limit total memory allocated per object
* and the maximum recursion depth that a message can force.
*/
- goto out_emit;
+ goto out_emit_bad;
}
return;
out_emit_bad:
- /* clear out token list and tell the parser to emit and error
+ /*
+ * Clear out token list and tell the parser to emit an error
* indication by passing it a NULL list
*/
- QDECREF(parser->tokens);
- parser->tokens = NULL;
+ json_message_free_tokens(parser);
out_emit:
/* send current list of tokens to parser and reset tokenizer */
parser->brace_count = 0;
parser->bracket_count = 0;
+ /* parser->emit takes ownership of parser->tokens. */
parser->emit(parser, parser->tokens);
- if (parser->tokens) {
- QDECREF(parser->tokens);
- }
- parser->tokens = qlist_new();
+ parser->tokens = g_queue_new();
parser->token_size = 0;
}
void json_message_parser_init(JSONMessageParser *parser,
- void (*func)(JSONMessageParser *, QList *))
+ void (*func)(JSONMessageParser *, GQueue *))
{
parser->emit = func;
parser->brace_count = 0;
parser->bracket_count = 0;
- parser->tokens = qlist_new();
+ parser->tokens = g_queue_new();
parser->token_size = 0;
json_lexer_init(&parser->lexer, json_message_process_token);
@@ -118,5 +122,5 @@ int json_message_parser_flush(JSONMessageParser *parser)
void json_message_parser_destroy(JSONMessageParser *parser)
{
json_lexer_destroy(&parser->lexer);
- QDECREF(parser->tokens);
+ json_message_free_tokens(parser);
}
diff --git a/qemu/qobject/qbool.c b/qemu/qobject/qbool.c
index 5ff69f0b2..0606bbd2a 100644
--- a/qemu/qobject/qbool.c
+++ b/qemu/qobject/qbool.c
@@ -11,17 +11,11 @@
*
*/
+#include "qemu/osdep.h"
#include "qapi/qmp/qbool.h"
#include "qapi/qmp/qobject.h"
#include "qemu-common.h"
-static void qbool_destroy_obj(QObject *obj);
-
-static const QType qbool_type = {
- .code = QTYPE_QBOOL,
- .destroy = qbool_destroy_obj,
-};
-
/**
* qbool_from_bool(): Create a new QBool from a bool
*
@@ -32,8 +26,8 @@ QBool *qbool_from_bool(bool value)
QBool *qb;
qb = g_malloc(sizeof(*qb));
+ qobject_init(QOBJECT(qb), QTYPE_QBOOL);
qb->value = value;
- QOBJECT_INIT(qb, &qbool_type);
return qb;
}
@@ -51,9 +45,9 @@ bool qbool_get_bool(const QBool *qb)
*/
QBool *qobject_to_qbool(const QObject *obj)
{
- if (qobject_type(obj) != QTYPE_QBOOL)
+ if (!obj || qobject_type(obj) != QTYPE_QBOOL) {
return NULL;
-
+ }
return container_of(obj, QBool, base);
}
@@ -61,7 +55,7 @@ QBool *qobject_to_qbool(const QObject *obj)
* qbool_destroy_obj(): Free all memory allocated by a
* QBool object
*/
-static void qbool_destroy_obj(QObject *obj)
+void qbool_destroy_obj(QObject *obj)
{
assert(obj != NULL);
g_free(qobject_to_qbool(obj));
diff --git a/qemu/qobject/qdict.c b/qemu/qobject/qdict.c
index 67b1a58ab..a1285361c 100644
--- a/qemu/qobject/qdict.c
+++ b/qemu/qobject/qdict.c
@@ -10,6 +10,7 @@
* See the COPYING.LIB file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include "qapi/qmp/qint.h"
#include "qapi/qmp/qfloat.h"
#include "qapi/qmp/qdict.h"
@@ -18,13 +19,7 @@
#include "qapi/qmp/qobject.h"
#include "qemu/queue.h"
#include "qemu-common.h"
-
-static void qdict_destroy_obj(QObject *obj);
-
-static const QType qdict_type = {
- .code = QTYPE_QDICT,
- .destroy = qdict_destroy_obj,
-};
+#include "qemu/cutils.h"
/**
* qdict_new(): Create a new QDict
@@ -36,7 +31,7 @@ QDict *qdict_new(void)
QDict *qdict;
qdict = g_malloc0(sizeof(*qdict));
- QOBJECT_INIT(qdict, &qdict_type);
+ qobject_init(QOBJECT(qdict), QTYPE_QDICT);
return qdict;
}
@@ -46,9 +41,9 @@ QDict *qdict_new(void)
*/
QDict *qobject_to_qdict(const QObject *obj)
{
- if (qobject_type(obj) != QTYPE_QDICT)
+ if (!obj || qobject_type(obj) != QTYPE_QDICT) {
return NULL;
-
+ }
return container_of(obj, QDict, base);
}
@@ -184,8 +179,7 @@ size_t qdict_size(const QDict *qdict)
/**
* qdict_get_obj(): Get a QObject of a specific type
*/
-static QObject *qdict_get_obj(const QDict *qdict, const char *key,
- qtype_code type)
+static QObject *qdict_get_obj(const QDict *qdict, const char *key, QType type)
{
QObject *obj;
@@ -229,8 +223,7 @@ double qdict_get_double(const QDict *qdict, const char *key)
*/
int64_t qdict_get_int(const QDict *qdict, const char *key)
{
- QObject *obj = qdict_get_obj(qdict, key, QTYPE_QINT);
- return qint_get_int(qobject_to_qint(obj));
+ return qint_get_int(qobject_to_qint(qdict_get(qdict, key)));
}
/**
@@ -243,8 +236,7 @@ int64_t qdict_get_int(const QDict *qdict, const char *key)
*/
bool qdict_get_bool(const QDict *qdict, const char *key)
{
- QObject *obj = qdict_get_obj(qdict, key, QTYPE_QBOOL);
- return qbool_get_bool(qobject_to_qbool(obj));
+ return qbool_get_bool(qobject_to_qbool(qdict_get(qdict, key)));
}
/**
@@ -270,7 +262,7 @@ QList *qdict_get_qlist(const QDict *qdict, const char *key)
*/
QDict *qdict_get_qdict(const QDict *qdict, const char *key)
{
- return qobject_to_qdict(qdict_get_obj(qdict, key, QTYPE_QDICT));
+ return qobject_to_qdict(qdict_get(qdict, key));
}
/**
@@ -284,8 +276,7 @@ QDict *qdict_get_qdict(const QDict *qdict, const char *key)
*/
const char *qdict_get_str(const QDict *qdict, const char *key)
{
- QObject *obj = qdict_get_obj(qdict, key, QTYPE_QSTRING);
- return qstring_get_str(qobject_to_qstring(obj));
+ return qstring_get_str(qobject_to_qstring(qdict_get(qdict, key)));
}
/**
@@ -298,13 +289,9 @@ const char *qdict_get_str(const QDict *qdict, const char *key)
int64_t qdict_get_try_int(const QDict *qdict, const char *key,
int64_t def_value)
{
- QObject *obj;
-
- obj = qdict_get(qdict, key);
- if (!obj || qobject_type(obj) != QTYPE_QINT)
- return def_value;
+ QInt *qint = qobject_to_qint(qdict_get(qdict, key));
- return qint_get_int(qobject_to_qint(obj));
+ return qint ? qint_get_int(qint) : def_value;
}
/**
@@ -316,13 +303,9 @@ int64_t qdict_get_try_int(const QDict *qdict, const char *key,
*/
bool qdict_get_try_bool(const QDict *qdict, const char *key, bool def_value)
{
- QObject *obj;
-
- obj = qdict_get(qdict, key);
- if (!obj || qobject_type(obj) != QTYPE_QBOOL)
- return def_value;
+ QBool *qbool = qobject_to_qbool(qdict_get(qdict, key));
- return qbool_get_bool(qobject_to_qbool(obj));
+ return qbool ? qbool_get_bool(qbool) : def_value;
}
/**
@@ -335,13 +318,9 @@ bool qdict_get_try_bool(const QDict *qdict, const char *key, bool def_value)
*/
const char *qdict_get_try_str(const QDict *qdict, const char *key)
{
- QObject *obj;
-
- obj = qdict_get(qdict, key);
- if (!obj || qobject_type(obj) != QTYPE_QSTRING)
- return NULL;
+ QString *qstr = qobject_to_qstring(qdict_get(qdict, key));
- return qstring_get_str(qobject_to_qstring(obj));
+ return qstr ? qstring_get_str(qstr) : NULL;
}
/**
@@ -456,7 +435,7 @@ void qdict_del(QDict *qdict, const char *key)
/**
* qdict_destroy_obj(): Free all the memory allocated by a QDict
*/
-static void qdict_destroy_obj(QObject *obj)
+void qdict_destroy_obj(QObject *obj)
{
int i;
QDict *qdict;
diff --git a/qemu/qobject/qfloat.c b/qemu/qobject/qfloat.c
index 7de0992db..d5da84770 100644
--- a/qemu/qobject/qfloat.c
+++ b/qemu/qobject/qfloat.c
@@ -11,17 +11,11 @@
*
*/
+#include "qemu/osdep.h"
#include "qapi/qmp/qfloat.h"
#include "qapi/qmp/qobject.h"
#include "qemu-common.h"
-static void qfloat_destroy_obj(QObject *obj);
-
-static const QType qfloat_type = {
- .code = QTYPE_QFLOAT,
- .destroy = qfloat_destroy_obj,
-};
-
/**
* qfloat_from_int(): Create a new QFloat from a float
*
@@ -32,8 +26,8 @@ QFloat *qfloat_from_double(double value)
QFloat *qf;
qf = g_malloc(sizeof(*qf));
+ qobject_init(QOBJECT(qf), QTYPE_QFLOAT);
qf->value = value;
- QOBJECT_INIT(qf, &qfloat_type);
return qf;
}
@@ -51,9 +45,9 @@ double qfloat_get_double(const QFloat *qf)
*/
QFloat *qobject_to_qfloat(const QObject *obj)
{
- if (qobject_type(obj) != QTYPE_QFLOAT)
+ if (!obj || qobject_type(obj) != QTYPE_QFLOAT) {
return NULL;
-
+ }
return container_of(obj, QFloat, base);
}
@@ -61,7 +55,7 @@ QFloat *qobject_to_qfloat(const QObject *obj)
* qfloat_destroy_obj(): Free all memory allocated by a
* QFloat object
*/
-static void qfloat_destroy_obj(QObject *obj)
+void qfloat_destroy_obj(QObject *obj)
{
assert(obj != NULL);
g_free(qobject_to_qfloat(obj));
diff --git a/qemu/qobject/qint.c b/qemu/qobject/qint.c
index 86b9b04f0..d7d1b3021 100644
--- a/qemu/qobject/qint.c
+++ b/qemu/qobject/qint.c
@@ -10,17 +10,11 @@
* See the COPYING.LIB file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include "qapi/qmp/qint.h"
#include "qapi/qmp/qobject.h"
#include "qemu-common.h"
-static void qint_destroy_obj(QObject *obj);
-
-static const QType qint_type = {
- .code = QTYPE_QINT,
- .destroy = qint_destroy_obj,
-};
-
/**
* qint_from_int(): Create a new QInt from an int64_t
*
@@ -31,8 +25,8 @@ QInt *qint_from_int(int64_t value)
QInt *qi;
qi = g_malloc(sizeof(*qi));
+ qobject_init(QOBJECT(qi), QTYPE_QINT);
qi->value = value;
- QOBJECT_INIT(qi, &qint_type);
return qi;
}
@@ -50,9 +44,9 @@ int64_t qint_get_int(const QInt *qi)
*/
QInt *qobject_to_qint(const QObject *obj)
{
- if (qobject_type(obj) != QTYPE_QINT)
+ if (!obj || qobject_type(obj) != QTYPE_QINT) {
return NULL;
-
+ }
return container_of(obj, QInt, base);
}
@@ -60,7 +54,7 @@ QInt *qobject_to_qint(const QObject *obj)
* qint_destroy_obj(): Free all memory allocated by a
* QInt object
*/
-static void qint_destroy_obj(QObject *obj)
+void qint_destroy_obj(QObject *obj)
{
assert(obj != NULL);
g_free(qobject_to_qint(obj));
diff --git a/qemu/qobject/qjson.c b/qemu/qobject/qjson.c
index 33f8ef530..ef160d211 100644
--- a/qemu/qobject/qjson.c
+++ b/qemu/qobject/qjson.c
@@ -11,6 +11,7 @@
*
*/
+#include "qemu/osdep.h"
#include "qapi/qmp/json-lexer.h"
#include "qapi/qmp/json-parser.h"
#include "qapi/qmp/json-streamer.h"
@@ -20,6 +21,7 @@
#include "qapi/qmp/qbool.h"
#include "qapi/qmp/qfloat.h"
#include "qapi/qmp/qdict.h"
+#include "qemu/unicode.h"
typedef struct JSONParsingState
{
@@ -28,7 +30,7 @@ typedef struct JSONParsingState
QObject *result;
} JSONParsingState;
-static void parse_json(JSONMessageParser *parser, QList *tokens)
+static void parse_json(JSONMessageParser *parser, GQueue *tokens)
{
JSONParsingState *s = container_of(parser, JSONParsingState, parser);
s->result = json_parser_parse(tokens, s->ap);
@@ -237,6 +239,15 @@ static void to_json(const QObject *obj, QString *str, int pretty, int indent)
char buffer[1024];
int len;
+ /* FIXME: snprintf() 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. */
+ /* FIXME: the default precision of 6 for %f often causes
+ * rounding errors; we should be using DBL_DECIMAL_DIG (17),
+ * and only rounding to a shorter number if the result would
+ * still produce the same floating point value. */
len = snprintf(buffer, sizeof(buffer), "%f", qfloat_get_double(val));
while (len > 0 && buffer[len - 1] == '0') {
len--;
@@ -247,7 +258,7 @@ static void to_json(const QObject *obj, QString *str, int pretty, int indent)
} else {
buffer[len] = 0;
}
-
+
qstring_append(str, buffer);
break;
}
diff --git a/qemu/qobject/qlist.c b/qemu/qobject/qlist.c
index 1ced0de58..1ec74de2b 100644
--- a/qemu/qobject/qlist.c
+++ b/qemu/qobject/qlist.c
@@ -10,18 +10,12 @@
* See the COPYING.LIB file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include "qapi/qmp/qlist.h"
#include "qapi/qmp/qobject.h"
#include "qemu/queue.h"
#include "qemu-common.h"
-static void qlist_destroy_obj(QObject *obj);
-
-static const QType qlist_type = {
- .code = QTYPE_QLIST,
- .destroy = qlist_destroy_obj,
-};
-
/**
* qlist_new(): Create a new QList
*
@@ -32,8 +26,8 @@ QList *qlist_new(void)
QList *qlist;
qlist = g_malloc(sizeof(*qlist));
+ qobject_init(QOBJECT(qlist), QTYPE_QLIST);
QTAILQ_INIT(&qlist->head);
- QOBJECT_INIT(qlist, &qlist_type);
return qlist;
}
@@ -142,17 +136,16 @@ size_t qlist_size(const QList *qlist)
*/
QList *qobject_to_qlist(const QObject *obj)
{
- if (qobject_type(obj) != QTYPE_QLIST) {
+ if (!obj || qobject_type(obj) != QTYPE_QLIST) {
return NULL;
}
-
return container_of(obj, QList, base);
}
/**
* qlist_destroy_obj(): Free all the memory allocated by a QList
*/
-static void qlist_destroy_obj(QObject *obj)
+void qlist_destroy_obj(QObject *obj)
{
QList *qlist;
QListEntry *entry, *next_entry;
diff --git a/qemu/qobject/qnull.c b/qemu/qobject/qnull.c
index 9873e266e..c124d0585 100644
--- a/qemu/qobject/qnull.c
+++ b/qemu/qobject/qnull.c
@@ -10,20 +10,11 @@
* or later. See the COPYING.LIB file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qapi/qmp/qobject.h"
-static void qnull_destroy_obj(QObject *obj)
-{
- assert(0);
-}
-
-static const QType qnull_type = {
- .code = QTYPE_QNULL,
- .destroy = qnull_destroy_obj,
-};
-
QObject qnull_ = {
- .type = &qnull_type,
+ .type = QTYPE_QNULL,
.refcnt = 1,
};
diff --git a/qemu/qobject/qobject.c b/qemu/qobject/qobject.c
new file mode 100644
index 000000000..cd41fb940
--- /dev/null
+++ b/qemu/qobject/qobject.c
@@ -0,0 +1,35 @@
+/*
+ * 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 "qemu-common.h"
+#include "qapi/qmp/qbool.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qfloat.h"
+#include "qapi/qmp/qint.h"
+#include "qapi/qmp/qlist.h"
+#include "qapi/qmp/qstring.h"
+
+static void (*qdestroy[QTYPE__MAX])(QObject *) = {
+ [QTYPE_NONE] = NULL, /* No such object exists */
+ [QTYPE_QNULL] = NULL, /* qnull_ is indestructible */
+ [QTYPE_QINT] = qint_destroy_obj,
+ [QTYPE_QSTRING] = qstring_destroy_obj,
+ [QTYPE_QDICT] = qdict_destroy_obj,
+ [QTYPE_QLIST] = qlist_destroy_obj,
+ [QTYPE_QFLOAT] = qfloat_destroy_obj,
+ [QTYPE_QBOOL] = qbool_destroy_obj,
+};
+
+void qobject_destroy(QObject *obj)
+{
+ assert(!obj->refcnt);
+ assert(QTYPE_QNULL < obj->type && obj->type < QTYPE__MAX);
+ qdestroy[obj->type](obj);
+}
diff --git a/qemu/qobject/qstring.c b/qemu/qobject/qstring.c
index 607b7a142..5da7b5f37 100644
--- a/qemu/qobject/qstring.c
+++ b/qemu/qobject/qstring.c
@@ -10,17 +10,11 @@
* See the COPYING.LIB file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include "qapi/qmp/qobject.h"
#include "qapi/qmp/qstring.h"
#include "qemu-common.h"
-static void qstring_destroy_obj(QObject *obj);
-
-static const QType qstring_type = {
- .code = QTYPE_QSTRING,
- .destroy = qstring_destroy_obj,
-};
-
/**
* qstring_new(): Create a new empty QString
*
@@ -49,6 +43,7 @@ QString *qstring_from_substr(const char *str, int start, int end)
QString *qstring;
qstring = g_malloc(sizeof(*qstring));
+ qobject_init(QOBJECT(qstring), QTYPE_QSTRING);
qstring->length = end - start + 1;
qstring->capacity = qstring->length;
@@ -57,7 +52,6 @@ QString *qstring_from_substr(const char *str, int start, int end)
memcpy(qstring->string, str + start, qstring->length);
qstring->string[qstring->length] = 0;
- QOBJECT_INIT(qstring, &qstring_type);
return qstring;
}
@@ -117,9 +111,9 @@ void qstring_append_chr(QString *qstring, int c)
*/
QString *qobject_to_qstring(const QObject *obj)
{
- if (qobject_type(obj) != QTYPE_QSTRING)
+ if (!obj || qobject_type(obj) != QTYPE_QSTRING) {
return NULL;
-
+ }
return container_of(obj, QString, base);
}
@@ -138,7 +132,7 @@ const char *qstring_get_str(const QString *qstring)
* qstring_destroy_obj(): Free all memory allocated by a QString
* object
*/
-static void qstring_destroy_obj(QObject *obj)
+void qstring_destroy_obj(QObject *obj)
{
QString *qs;