[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PULL 10/41] json: learn to parse uint64 numbers
From: |
Markus Armbruster |
Subject: |
[Qemu-devel] [PULL 10/41] json: learn to parse uint64 numbers |
Date: |
Fri, 9 Jun 2017 15:46:54 +0200 |
From: Marc-André Lureau <address@hidden>
Switch strtoll() usage to qemu_strtoi64() helper while at it.
Add a few tests for large numbers.
Signed-off-by: Marc-André Lureau <address@hidden>
Message-Id: <address@hidden>
Reviewed-by: Markus Armbruster <address@hidden>
Signed-off-by: Markus Armbruster <address@hidden>
---
qobject/json-lexer.c | 4 ++++
qobject/json-parser.c | 36 ++++++++++++++++++++++++++++--------
tests/check-qjson.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 76 insertions(+), 8 deletions(-)
diff --git a/qobject/json-lexer.c b/qobject/json-lexer.c
index af4a75e..980ba15 100644
--- a/qobject/json-lexer.c
+++ b/qobject/json-lexer.c
@@ -227,15 +227,18 @@ static const uint8_t json_lexer[][256] = {
/* escape */
[IN_ESCAPE_LL] = {
['d'] = JSON_ESCAPE,
+ ['u'] = JSON_ESCAPE,
},
[IN_ESCAPE_L] = {
['d'] = JSON_ESCAPE,
['l'] = IN_ESCAPE_LL,
+ ['u'] = JSON_ESCAPE,
},
[IN_ESCAPE_I64] = {
['d'] = JSON_ESCAPE,
+ ['u'] = JSON_ESCAPE,
},
[IN_ESCAPE_I6] = {
@@ -251,6 +254,7 @@ static const uint8_t json_lexer[][256] = {
['i'] = JSON_ESCAPE,
['p'] = JSON_ESCAPE,
['s'] = JSON_ESCAPE,
+ ['u'] = JSON_ESCAPE,
['f'] = JSON_ESCAPE,
['l'] = IN_ESCAPE_L,
['I'] = IN_ESCAPE_I,
diff --git a/qobject/json-parser.c b/qobject/json-parser.c
index 5e80828..7a417f2 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"
@@ -472,6 +473,13 @@ static QObject *parse_escape(JSONParserContext *ctxt,
va_list *ap)
} else if (!strcmp(token->str, "%lld") ||
!strcmp(token->str, "%I64d")) {
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")) {
@@ -493,21 +501,33 @@ static QObject *parse_literal(JSONParserContext *ctxt)
case JSON_INTEGER: {
/*
* Represent JSON_INTEGER as QNUM_I64 if possible, else as
- * QNUM_DOUBLE. Note that strtoll() fails with ERANGE when
- * it's not possible.
+ * 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, and qnum_get_double() both for any
- * JSON_INTEGER and any JSON_FLOAT (with precision loss for
- * integers beyond 53 bits)
+ * 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;
- errno = 0; /* strtoll doesn't set errno on success */
- value = strtoll(token->str, NULL, 10);
- if (errno != ERANGE) {
+ 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:
diff --git a/tests/check-qjson.c b/tests/check-qjson.c
index f0a89f7..53f2275 100644
--- a/tests/check-qjson.c
+++ b/tests/check-qjson.c
@@ -906,6 +906,49 @@ static void simple_number(void)
}
}
+static void large_number(void)
+{
+ const char *maxu64 = "18446744073709551615"; /* 2^64-1 */
+ const char *gtu64 = "18446744073709551616"; /* 2^64 */
+ const char *lti64 = "-9223372036854775809"; /* -2^63 - 1 */
+ QNum *qnum;
+ QString *str;
+ uint64_t val;
+ int64_t ival;
+
+ qnum = qobject_to_qnum(qobject_from_json(maxu64, &error_abort));
+ g_assert(qnum);
+ g_assert_cmpuint(qnum_get_uint(qnum), ==, 18446744073709551615U);
+ g_assert(!qnum_get_try_int(qnum, &ival));
+
+ str = qobject_to_json(QOBJECT(qnum));
+ g_assert_cmpstr(qstring_get_str(str), ==, maxu64);
+ QDECREF(str);
+ QDECREF(qnum);
+
+ qnum = qobject_to_qnum(qobject_from_json(gtu64, &error_abort));
+ g_assert(qnum);
+ g_assert_cmpfloat(qnum_get_double(qnum), ==, 18446744073709552e3);
+ g_assert(!qnum_get_try_uint(qnum, &val));
+ g_assert(!qnum_get_try_int(qnum, &ival));
+
+ str = qobject_to_json(QOBJECT(qnum));
+ g_assert_cmpstr(qstring_get_str(str), ==, gtu64);
+ QDECREF(str);
+ QDECREF(qnum);
+
+ qnum = qobject_to_qnum(qobject_from_json(lti64, &error_abort));
+ g_assert(qnum);
+ g_assert_cmpfloat(qnum_get_double(qnum), ==, -92233720368547758e2);
+ g_assert(!qnum_get_try_uint(qnum, &val));
+ g_assert(!qnum_get_try_int(qnum, &ival));
+
+ str = qobject_to_json(QOBJECT(qnum));
+ g_assert_cmpstr(qstring_get_str(str), ==, "-9223372036854775808");
+ QDECREF(str);
+ QDECREF(qnum);
+}
+
static void float_number(void)
{
int i;
@@ -1475,6 +1518,7 @@ int main(int argc, char **argv)
g_test_add_func("/literals/string/vararg", vararg_string);
g_test_add_func("/literals/number/simple", simple_number);
+ g_test_add_func("/literals/number/large", large_number);
g_test_add_func("/literals/number/float", float_number);
g_test_add_func("/literals/number/vararg", vararg_number);
--
2.7.5
- [Qemu-devel] [PULL 00/41] QAPI patches for 2017-06-09, Markus Armbruster, 2017/06/09
- [Qemu-devel] [PULL 02/41] object: fix potential leak in getters, Markus Armbruster, 2017/06/09
- [Qemu-devel] [PULL 05/41] qapi: Clean up qobject_input_type_number() control flow, Markus Armbruster, 2017/06/09
- [Qemu-devel] [PULL 03/41] tests: Remove test cases for alternates of 'number' and 'int', Markus Armbruster, 2017/06/09
- [Qemu-devel] [PULL 01/41] qdev: remove PropertyInfo.qtype field, Markus Armbruster, 2017/06/09
- [Qemu-devel] [PULL 09/41] qnum: add uint type, Markus Armbruster, 2017/06/09
- [Qemu-devel] [PULL 10/41] json: learn to parse uint64 numbers,
Markus Armbruster <=
- [Qemu-devel] [PULL 12/41] object: add uint property setter/getter, Markus Armbruster, 2017/06/09
- [Qemu-devel] [PULL 11/41] qapi: update the qobject visitor to use QNUM_U64, Markus Armbruster, 2017/06/09
- [Qemu-devel] [PULL 20/41] isa: use get_uint() for "io-base", Markus Armbruster, 2017/06/09
- [Qemu-devel] [PULL 16/41] qdev: wrap default property value in an union, Markus Armbruster, 2017/06/09
- [Qemu-devel] [PULL 04/41] tests: add more int/number ranges checks, Markus Armbruster, 2017/06/09
- [Qemu-devel] [PULL 35/41] auxbus: use get_uint() for "addr" property, Markus Armbruster, 2017/06/09
- [Qemu-devel] [PULL 24/41] aspeed: use {set, get}_uint() for "ram-size" property, Markus Armbruster, 2017/06/09
- [Qemu-devel] [PULL 29/41] acpi: use get_uint() for "pci-hole*" properties, Markus Armbruster, 2017/06/09
- [Qemu-devel] [PULL 15/41] qdev: Rename DEFINE_PROP_DEFAULT() to DEFINE_PROP_SIGNED(), Markus Armbruster, 2017/06/09
- [Qemu-devel] [PULL 33/41] xen: use get_uint() for "max-ram-below-4g" property, Markus Armbruster, 2017/06/09