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)