diff --git a/include/zephyr/data/json.h b/include/zephyr/data/json.h index f140a8b45b5805..a93eb427374f2f 100644 --- a/include/zephyr/data/json.h +++ b/include/zephyr/data/json.h @@ -42,6 +42,7 @@ enum json_tokens { JSON_TOK_OPAQUE = '2', JSON_TOK_OBJ_ARRAY = '3', JSON_TOK_ENCODED_OBJ = '4', + JSON_TOK_INT64 = '5', JSON_TOK_TRUE = 't', JSON_TOK_FALSE = 'f', JSON_TOK_NULL = 'n', diff --git a/lib/utils/json.c b/lib/utils/json.c index de43a5d974de46..c1170fcfec97d6 100644 --- a/lib/utils/json.c +++ b/lib/utils/json.c @@ -308,6 +308,7 @@ static int element_token(enum json_tokens token) case JSON_TOK_ARRAY_START: case JSON_TOK_STRING: case JSON_TOK_NUMBER: + case JSON_TOK_INT64: case JSON_TOK_FLOAT: case JSON_TOK_OPAQUE: case JSON_TOK_OBJ_ARRAY: @@ -444,6 +445,30 @@ static int decode_num(const struct json_token *token, int32_t *num) return 0; } +static int decode_int64(const struct json_token *token, int64_t *num) +{ + char *endptr; + char prev_end; + + prev_end = *token->end; + *token->end = '\0'; + + errno = 0; + *num = strtoll(token->start, &endptr, 10); + + *token->end = prev_end; + + if (errno != 0) { + return -errno; + } + + if (endptr != token->end) { + return -EINVAL; + } + + return 0; +} + static bool equivalent_types(enum json_tokens type1, enum json_tokens type2) { if (type1 == JSON_TOK_TRUE || type1 == JSON_TOK_FALSE) { @@ -454,6 +479,10 @@ static bool equivalent_types(enum json_tokens type1, enum json_tokens type2) return true; } + if (type1 == JSON_TOK_NUMBER && type2 == JSON_TOK_INT64) { + return true; + } + if (type1 == JSON_TOK_STRING && type2 == JSON_TOK_OPAQUE) { return true; } @@ -511,6 +540,11 @@ static int64_t decode_value(struct json_obj *obj, return decode_num(value, num); } + case JSON_TOK_INT64: { + int64_t *num = field; + + return decode_int64(value, num); + } case JSON_TOK_OPAQUE: case JSON_TOK_FLOAT: { struct json_obj_token *obj_token = field; @@ -537,6 +571,8 @@ static ptrdiff_t get_elem_size(const struct json_obj_descr *descr) switch (descr->type) { case JSON_TOK_NUMBER: return sizeof(int32_t); + case JSON_TOK_INT64: + return sizeof(int64_t); case JSON_TOK_OPAQUE: case JSON_TOK_FLOAT: case JSON_TOK_OBJ_ARRAY: @@ -982,6 +1018,23 @@ static int num_encode(const int32_t *num, json_append_bytes_t append_bytes, return append_bytes(buf, (size_t)ret, data); } +static int int64_encode(const int64_t *num, json_append_bytes_t append_bytes, + void *data) +{ + char buf[sizeof("-9223372036854775808")]; + int ret; + + ret = snprintk(buf, sizeof(buf), "%" PRId64, *num); + if (ret < 0) { + return ret; + } + if (ret >= (int)sizeof(buf)) { + return -ENOMEM; + } + + return append_bytes(buf, (size_t)ret, data); +} + static int float_ascii_encode(struct json_obj_token *num, json_append_bytes_t append_bytes, void *data) { @@ -1044,6 +1097,8 @@ static int encode(const struct json_obj_descr *descr, const void *val, ptr, append_bytes, data); case JSON_TOK_NUMBER: return num_encode(ptr, append_bytes, data); + case JSON_TOK_INT64: + return int64_encode(ptr, append_bytes, data); case JSON_TOK_FLOAT: return float_ascii_encode(ptr, append_bytes, data); case JSON_TOK_OPAQUE: diff --git a/tests/lib/json/prj.conf b/tests/lib/json/prj.conf index 700ea224bba2f7..4a6c8522abd68d 100644 --- a/tests/lib/json/prj.conf +++ b/tests/lib/json/prj.conf @@ -1,3 +1,3 @@ CONFIG_JSON_LIBRARY=y CONFIG_ZTEST=y -CONFIG_ZTEST_STACK_SIZE=2048 +CONFIG_ZTEST_STACK_SIZE=3072 diff --git a/tests/lib/json/src/main.c b/tests/lib/json/src/main.c index b1b4884de93ed5..ae142f85d1961b 100644 --- a/tests/lib/json/src/main.c +++ b/tests/lib/json/src/main.c @@ -13,12 +13,15 @@ struct test_nested { int nested_int; bool nested_bool; const char *nested_string; + int64_t nested_int64; }; struct test_struct { const char *some_string; int some_int; bool some_bool; + int64_t some_int64; + int64_t another_int64; struct test_nested some_nested_struct; int some_array[16]; size_t some_array_len; @@ -45,6 +48,9 @@ struct test_int_limits { int int_max; int int_cero; int int_min; + int64_t int64_max; + int64_t int64_cero; + int64_t int64_min; }; static const struct json_obj_descr nested_descr[] = { @@ -52,12 +58,18 @@ static const struct json_obj_descr nested_descr[] = { JSON_OBJ_DESCR_PRIM(struct test_nested, nested_bool, JSON_TOK_TRUE), JSON_OBJ_DESCR_PRIM(struct test_nested, nested_string, JSON_TOK_STRING), + JSON_OBJ_DESCR_PRIM(struct test_nested, nested_int64, + JSON_TOK_INT64), }; static const struct json_obj_descr test_descr[] = { JSON_OBJ_DESCR_PRIM(struct test_struct, some_string, JSON_TOK_STRING), JSON_OBJ_DESCR_PRIM(struct test_struct, some_int, JSON_TOK_NUMBER), JSON_OBJ_DESCR_PRIM(struct test_struct, some_bool, JSON_TOK_TRUE), + JSON_OBJ_DESCR_PRIM(struct test_struct, some_int64, + JSON_TOK_INT64), + JSON_OBJ_DESCR_PRIM(struct test_struct, another_int64, + JSON_TOK_INT64), JSON_OBJ_DESCR_OBJECT(struct test_struct, some_nested_struct, nested_descr), JSON_OBJ_DESCR_ARRAY(struct test_struct, some_array, @@ -89,6 +101,9 @@ static const struct json_obj_descr obj_limits_descr[] = { JSON_OBJ_DESCR_PRIM(struct test_int_limits, int_max, JSON_TOK_NUMBER), JSON_OBJ_DESCR_PRIM(struct test_int_limits, int_cero, JSON_TOK_NUMBER), JSON_OBJ_DESCR_PRIM(struct test_int_limits, int_min, JSON_TOK_NUMBER), + JSON_OBJ_DESCR_PRIM(struct test_int_limits, int64_max, JSON_TOK_INT64), + JSON_OBJ_DESCR_PRIM(struct test_int_limits, int64_cero, JSON_TOK_INT64), + JSON_OBJ_DESCR_PRIM(struct test_int_limits, int64_min, JSON_TOK_INT64), }; struct array { @@ -180,11 +195,14 @@ ZTEST(lib_json_test, test_json_encoding) struct test_struct ts = { .some_string = "zephyr 123\uABCD", .some_int = 42, + .some_int64 = 1152921504606846977, + .another_int64 = -2305843009213693937, .some_bool = true, .some_nested_struct = { .nested_int = -1234, .nested_bool = false, - .nested_string = "this should be escaped: \t" + .nested_string = "this should be escaped: \t", + .nested_int64 = 4503599627370496, }, .some_array[0] = 1, .some_array[1] = 4, @@ -203,6 +221,7 @@ ZTEST(lib_json_test, test_json_encoding) .nested_int = 1234, .nested_bool = true, .nested_string = "no escape necessary", + .nested_int64 = 4503599627370496, }, .nested_obj_array = { {1, true, "true"}, @@ -212,19 +231,23 @@ ZTEST(lib_json_test, test_json_encoding) }; char encoded[] = "{\"some_string\":\"zephyr 123\uABCD\"," "\"some_int\":42,\"some_bool\":true," + "\"some_int64\":1152921504606846977," + "\"another_int64\":-2305843009213693937," "\"some_nested_struct\":{\"nested_int\":-1234," "\"nested_bool\":false,\"nested_string\":" - "\"this should be escaped: \\t\"}," + "\"this should be escaped: \\t\"," + "\"nested_int64\":4503599627370496}," "\"some_array\":[1,4,8,16,32]," "\"another_b!@l\":true," "\"if\":false," "\"another-array\":[2,3,5,7]," "\"4nother_ne$+\":{\"nested_int\":1234," "\"nested_bool\":true," - "\"nested_string\":\"no escape necessary\"}," + "\"nested_string\":\"no escape necessary\"," + "\"nested_int64\":4503599627370496}," "\"nested_obj_array\":[" - "{\"nested_int\":1,\"nested_bool\":true,\"nested_string\":\"true\"}," - "{\"nested_int\":0,\"nested_bool\":false,\"nested_string\":\"false\"}]" + "{\"nested_int\":1,\"nested_bool\":true,\"nested_string\":\"true\",\"nested_int64\":0}," + "{\"nested_int\":0,\"nested_bool\":false,\"nested_string\":\"false\",\"nested_int64\":0}]" "}"; char buffer[sizeof(encoded)]; int ret; @@ -249,10 +272,13 @@ ZTEST(lib_json_test, test_json_decoding) "\"some_bool\":true \t " "\n" "\r ," + "\"some_int64\":-4611686018427387904," + "\"another_int64\":-2147483648," "\"some_nested_struct\":{ " "\"nested_int\":-1234,\n\n" "\"nested_bool\":false,\t" "\"nested_string\":\"this should be escaped: \\t\"," + "\"nested_int64\":9223372036854775807," "\"extra_nested_array\":[0,-1]}," "\"extra_struct\":{\"nested_bool\":false}," "\"extra_bool\":true," @@ -262,7 +288,8 @@ ZTEST(lib_json_test, test_json_decoding) "\"another-array\":[2,3,5,7]," "\"4nother_ne$+\":{\"nested_int\":1234," "\"nested_bool\":true," - "\"nested_string\":\"no escape necessary\"}," + "\"nested_string\":\"no escape necessary\"," + "\"nested_int64\":-9223372036854775806}," "\"nested_obj_array\":[" "{\"nested_int\":1,\"nested_bool\":true,\"nested_string\":\"true\"}," "{\"nested_int\":0,\"nested_bool\":false,\"nested_string\":\"false\"}]" @@ -281,8 +308,14 @@ ZTEST(lib_json_test, test_json_decoding) "String not decoded correctly"); zassert_equal(ts.some_int, 42, "Positive integer not decoded correctly"); zassert_equal(ts.some_bool, true, "Boolean not decoded correctly"); + zassert_equal(ts.some_int64, -4611686018427387904, + "int64 not decoded correctly"); + zassert_equal(ts.another_int64, -2147483648, + "int64 not decoded correctly"); zassert_equal(ts.some_nested_struct.nested_int, -1234, "Nested negative integer not decoded correctly"); + zassert_equal(ts.some_nested_struct.nested_int64, 9223372036854775807, + "Nested int64 not decoded correctly"); zassert_equal(ts.some_nested_struct.nested_bool, false, "Nested boolean value not decoded correctly"); zassert_str_equal(ts.some_nested_struct.nested_string, @@ -304,6 +337,8 @@ ZTEST(lib_json_test, test_json_decoding) "Decoded named array not with expected values"); zassert_equal(ts.xnother_nexx.nested_int, 1234, "Named nested integer not decoded correctly"); + zassert_equal(ts.xnother_nexx.nested_int64, -9223372036854775806, + "Named nested int64 not decoded correctly"); zassert_equal(ts.xnother_nexx.nested_bool, true, "Named nested boolean not decoded correctly"); zassert_str_equal(ts.xnother_nexx.nested_string, @@ -330,13 +365,19 @@ ZTEST(lib_json_test, test_json_limits) int ret = 0; char encoded[] = "{\"int_max\":2147483647," "\"int_cero\":0," - "\"int_min\":-2147483648" + "\"int_min\":-2147483648," + "\"int64_max\":9223372036854775807," + "\"int64_cero\":0," + "\"int64_min\":-9223372036854775808" "}"; struct test_int_limits limits = { .int_max = INT_MAX, .int_cero = 0, .int_min = INT_MIN, + .int64_max = INT64_MAX, + .int64_cero = 0, + .int64_min = INT64_MIN, }; char buffer[sizeof(encoded)];