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.
This commit is contained in:
Joris Vink 2020-11-19 14:56:17 +01:00
parent 760dff8b3c
commit d7fbce37f5
2 changed files with 89 additions and 25 deletions

View File

@ -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);

View File

@ -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)