diff options
Diffstat (limited to 'qobject/json-parser.c')
-rw-r--r-- | qobject/json-parser.c | 56 |
1 files changed, 37 insertions, 19 deletions
diff --git a/qobject/json-parser.c b/qobject/json-parser.c index c18e48ab94..7a417f20cd 100644 --- a/qobject/json-parser.c +++ b/qobject/json-parser.c @@ -12,6 +12,7 @@ */ #include "qemu/osdep.h" +#include "qemu/cutils.h" #include "qapi/error.h" #include "qemu-common.h" #include "qapi/qmp/types.h" @@ -466,16 +467,23 @@ static QObject *parse_escape(JSONParserContext *ctxt, va_list *ap) } 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))); + return QOBJECT(qnum_from_int(va_arg(*ap, int))); } else if (!strcmp(token->str, "%ld")) { - return QOBJECT(qint_from_int(va_arg(*ap, long))); + return QOBJECT(qnum_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))); + return QOBJECT(qnum_from_int(va_arg(*ap, long long))); + } else if (!strcmp(token->str, "%u")) { + return QOBJECT(qnum_from_uint(va_arg(*ap, unsigned int))); + } else if (!strcmp(token->str, "%lu")) { + return QOBJECT(qnum_from_uint(va_arg(*ap, unsigned long))); + } else if (!strcmp(token->str, "%llu") || + !strcmp(token->str, "%I64u")) { + return QOBJECT(qnum_from_uint(va_arg(*ap, unsigned 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 QOBJECT(qnum_from_double(va_arg(*ap, double))); } return NULL; } @@ -491,24 +499,34 @@ static QObject *parse_literal(JSONParserContext *ctxt) case JSON_STRING: 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 - * deal to treat these as ints in the parser, so long as users of the - * resulting QObject know to expect a QInt in place of a QFloat in - * cases like these. + /* + * 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. * - * However, in some cases these values will overflow/underflow a - * QInt/int64 container, thus we should assume these are to be handled - * as QFloats/doubles rather than silently changing their values. - * - * strtoll() indicates these instances by setting errno to ERANGE + * 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); - errno = 0; /* strtoll doesn't set errno on success */ - value = strtoll(token->str, NULL, 10); - if (errno != ERANGE) { - return QOBJECT(qint_from_int(value)); + 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 */ } @@ -516,7 +534,7 @@ static QObject *parse_literal(JSONParserContext *ctxt) /* 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))); + return QOBJECT(qnum_from_double(strtod(token->str, NULL))); default: abort(); } |