kore

An easy to use, scalable and secure web application framework for writing web APIs in C.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

commit d7fbce37f5c31bb93db3836303dc957175b05c37
parent 760dff8b3cc3dbcc511f31cbe013be012a181a1e
Author: Joris Vink <joris@coders.se>
Date:   Thu, 19 Nov 2020 14:56:17 +0100

Better parsing of JSON integers and numbers.

Add 2 new types:
	KORE_JSON_TYPE_INTEGER
		signed integer type, internally stored as s64.

	KORE_JSON_TYPE_INTEGER_U64
		unsigned integer type, internally stored as u64.

Kore JSON parser will prefer marking integers as INTEGER_U64 if it
was unsigned and did not have fractions.

Diffstat:
include/kore/kore.h | 32++++++++++++++++++++++++--------
src/json.c | 82++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
2 files changed, 89 insertions(+), 25 deletions(-)

diff --git a/include/kore/kore.h b/include/kore/kore.h @@ -494,11 +494,13 @@ struct kore_buf { size_t offset; }; -#define KORE_JSON_TYPE_OBJECT 1 -#define KORE_JSON_TYPE_ARRAY 2 -#define KORE_JSON_TYPE_STRING 3 -#define KORE_JSON_TYPE_NUMBER 4 -#define KORE_JSON_TYPE_LITERAL 5 +#define KORE_JSON_TYPE_OBJECT 0x0001 +#define KORE_JSON_TYPE_ARRAY 0x0002 +#define KORE_JSON_TYPE_STRING 0x0004 +#define KORE_JSON_TYPE_NUMBER 0x0008 +#define KORE_JSON_TYPE_LITERAL 0x0010 +#define KORE_JSON_TYPE_INTEGER 0x0020 +#define KORE_JSON_TYPE_INTEGER_U64 0x0040 #define KORE_JSON_FALSE 0 #define KORE_JSON_TRUE 1 @@ -532,6 +534,12 @@ struct kore_buf { #define kore_json_find_number(j, p) \ kore_json_find(j, p, KORE_JSON_TYPE_NUMBER) +#define kore_json_find_integer(j, p) \ + kore_json_find(j, p, KORE_JSON_TYPE_INTEGER) + +#define kore_json_find_integer_u64(j, p) \ + kore_json_find(j, p, KORE_JSON_TYPE_INTEGER_U64) + #define kore_json_find_literal(j, p) \ kore_json_find(j, p, KORE_JSON_TYPE_LITERAL) @@ -547,6 +555,12 @@ struct kore_buf { #define kore_json_create_number(o, n, v) \ kore_json_create_item(o, n, KORE_JSON_TYPE_NUMBER, v) +#define kore_json_create_integer(o, n, v) \ + kore_json_create_item(o, n, KORE_JSON_TYPE_INTEGER, v) + +#define kore_json_create_integer_u64(o, n, v) \ + kore_json_create_item(o, n, KORE_JSON_TYPE_INTEGER_U64, v) + #define kore_json_create_literal(o, n, v) \ kore_json_create_item(o, n, KORE_JSON_TYPE_LITERAL, v) @@ -562,7 +576,7 @@ struct kore_json { }; struct kore_json_item { - int type; + u_int32_t type; char *name; struct kore_json_item *parent; @@ -571,6 +585,8 @@ struct kore_json_item { char *string; double number; int literal; + int64_t s64; + u_int64_t u64; } data; int (*parse)(struct kore_json *, @@ -1026,9 +1042,9 @@ void kore_json_item_tobuf(struct kore_json_item *, struct kore_buf *); const char *kore_json_strerror(struct kore_json *); struct kore_json_item *kore_json_find(struct kore_json_item *, - const char *, int); + const char *, u_int32_t); struct kore_json_item *kore_json_create_item(struct kore_json_item *, - const char *, int, ...); + const char *, u_int32_t, ...); void kore_keymgr_run(void); void kore_keymgr_cleanup(int); diff --git a/src/json.c b/src/json.c @@ -24,7 +24,7 @@ #include "kore.h" -static int json_guess_type(u_int8_t, int *); +static int json_guess_type(u_int8_t, u_int32_t *); static int json_next(struct kore_json *, u_int8_t *); static int json_peek(struct kore_json *, u_int8_t *); @@ -42,7 +42,7 @@ static int json_parse_literal(struct kore_json *, struct kore_json_item *); static struct kore_json_item *json_item_alloc(int, const char *, struct kore_json_item *); static struct kore_json_item *json_find_item(struct kore_json_item *, - char **, int, int); + char **, u_int32_t, int); static u_int8_t json_null_literal[] = { 'n', 'u', 'l', 'l' }; static u_int8_t json_true_literal[] = { 't', 'r', 'u', 'e' }; @@ -78,7 +78,7 @@ int kore_json_parse(struct kore_json *json) { u_int8_t ch; - int type; + u_int32_t type; if (json->root) return (KORE_RESULT_OK); @@ -112,7 +112,7 @@ kore_json_parse(struct kore_json *json) } struct kore_json_item * -kore_json_find(struct kore_json_item *root, const char *path, int type) +kore_json_find(struct kore_json_item *root, const char *path, u_int32_t type) { struct kore_json_item *item; char *copy; @@ -152,7 +152,7 @@ kore_json_strerror(struct kore_json *json) struct kore_json_item * kore_json_create_item(struct kore_json_item *parent, const char *name, - int type, ...) + u_int32_t type, ...) { const char *p; va_list args; @@ -177,6 +177,12 @@ kore_json_create_item(struct kore_json_item *parent, const char *name, case KORE_JSON_TYPE_NUMBER: item->data.number = va_arg(args, double); break; + case KORE_JSON_TYPE_INTEGER: + item->data.s64 = va_arg(args, int64_t); + break; + case KORE_JSON_TYPE_INTEGER_U64: + item->data.u64 = va_arg(args, u_int64_t); + break; case KORE_JSON_TYPE_LITERAL: item->data.literal = va_arg(args, int); break; @@ -237,6 +243,12 @@ kore_json_item_tobuf(struct kore_json_item *item, struct kore_buf *buf) case KORE_JSON_TYPE_NUMBER: kore_buf_appendf(buf, "%f", item->data.number); break; + case KORE_JSON_TYPE_INTEGER: + kore_buf_appendf(buf, "%" PRId64, item->data.s64); + break; + case KORE_JSON_TYPE_INTEGER_U64: + kore_buf_appendf(buf, "%" PRIu64, item->data.u64); + break; case KORE_JSON_TYPE_LITERAL: switch (item->data.literal) { case KORE_JSON_TRUE: @@ -262,7 +274,8 @@ kore_json_item_tobuf(struct kore_json_item *item, struct kore_buf *buf) } static struct kore_json_item * -json_find_item(struct kore_json_item *object, char **tokens, int type, int pos) +json_find_item(struct kore_json_item *object, char **tokens, + u_int32_t type, int pos) { char *p, *str; struct kore_json_item *item, *nitem; @@ -350,6 +363,8 @@ kore_json_item_free(struct kore_json_item *item) break; case KORE_JSON_TYPE_NUMBER: case KORE_JSON_TYPE_LITERAL: + case KORE_JSON_TYPE_INTEGER: + case KORE_JSON_TYPE_INTEGER_U64: break; default: fatal("%s: unknown type %d", __func__, item->type); @@ -381,6 +396,8 @@ json_item_alloc(int type, const char *name, struct kore_json_item *parent) item->parse = json_parse_string; break; case KORE_JSON_TYPE_NUMBER: + case KORE_JSON_TYPE_INTEGER: + case KORE_JSON_TYPE_INTEGER_U64: item->parse = json_parse_number; break; case KORE_JSON_TYPE_LITERAL: @@ -453,7 +470,7 @@ json_consume_whitespace(struct kore_json *json) } static int -json_guess_type(u_int8_t ch, int *type) +json_guess_type(u_int8_t ch, u_int32_t *type) { if (ch == '-' || (ch >= '0' && ch <= '9')) { *type = KORE_JSON_TYPE_NUMBER; @@ -486,9 +503,10 @@ static int json_parse_object(struct kore_json *json, struct kore_json_item *object) { u_int8_t ch; + u_int32_t type; char *key; struct kore_json_item *item; - int ret, type, hasnext; + int ret, hasnext; if (json->depth++ >= KORE_JSON_DEPTH_MAX) { json->error = KORE_JSON_ERR_DEPTH; @@ -586,9 +604,10 @@ static int json_parse_array(struct kore_json *json, struct kore_json_item *array) { u_int8_t ch; + u_int32_t type; char *key; struct kore_json_item *item; - int ret, type, hasnext; + int ret, hasnext; if (json->depth++ >= KORE_JSON_DEPTH_MAX) { json->error = KORE_JSON_ERR_DEPTH; @@ -680,16 +699,32 @@ json_parse_number(struct kore_json *json, struct kore_json_item *number) u_int8_t ch; int ret; char *str; + u_int32_t type; str = NULL; ret = KORE_RESULT_ERROR; kore_buf_reset(&json->tmpbuf); + type = KORE_JSON_TYPE_NUMBER | KORE_JSON_TYPE_INTEGER | + KORE_JSON_TYPE_INTEGER_U64; + for (;;) { if (!json_peek(json, &ch)) - goto cleanup; + break; switch (ch) { + case 'e': + case 'E': + case '.': + type = KORE_JSON_TYPE_NUMBER; + kore_buf_append(&json->tmpbuf, &ch, sizeof(ch)); + json->offset++; + continue; + case '-': + if (json->tmpbuf.offset != 0) + goto cleanup; + type &= ~KORE_JSON_TYPE_INTEGER_U64; + /* FALLTHROUGH */ case '0': case '1': case '2': @@ -701,10 +736,6 @@ json_parse_number(struct kore_json *json, struct kore_json_item *number) case '8': case '9': case '+': - case '-': - case 'e': - case 'E': - case '.': kore_buf_append(&json->tmpbuf, &ch, sizeof(ch)); json->offset++; continue; @@ -713,13 +744,30 @@ json_parse_number(struct kore_json *json, struct kore_json_item *number) break; } + if (type & KORE_JSON_TYPE_INTEGER_U64) + type = KORE_JSON_TYPE_INTEGER_U64; + + if (type & KORE_JSON_TYPE_INTEGER) + type = KORE_JSON_TYPE_INTEGER; + str = kore_buf_stringify(&json->tmpbuf, NULL); - number->data.number = kore_strtodouble(str, -DBL_MAX, DBL_MAX, &ret); - if (ret != KORE_RESULT_OK) + switch (type) { + case KORE_JSON_TYPE_NUMBER: + number->data.number = + kore_strtodouble(str, -DBL_MAX, DBL_MAX, &ret); + break; + case KORE_JSON_TYPE_INTEGER: + number->data.s64 = (int64_t)kore_strtonum64(str, 1, &ret); + break; + case KORE_JSON_TYPE_INTEGER_U64: + number->data.s64 = kore_strtonum64(str, 0, &ret); + break; + default: goto cleanup; + } - number->type = KORE_JSON_TYPE_NUMBER; + number->type = type; cleanup: if (ret == KORE_RESULT_ERROR && json->error == 0)