sync json parser improvements from json2tsv repo - frontends - front-ends for some sites (experiment) (DIR) Log (DIR) Files (DIR) Refs (DIR) README (DIR) LICENSE --- (DIR) commit a5e2f07cb75a19578454e096f2c9f77cebc30084 (DIR) parent f292d66dca2b0154b56fc8fa6935b947bfc74452 (HTM) Author: Hiltjo Posthuma <hiltjo@codemadness.org> Date: Wed, 30 Mar 2022 00:01:52 +0200 sync json parser improvements from json2tsv repo Diffstat: M json.c | 40 +++++++++++++++++-------------- M json.h | 20 ++++++++++++-------- 2 files changed, 34 insertions(+), 26 deletions(-) --- (DIR) diff --git a/json.c b/json.c @@ -1,4 +1,3 @@ -#include <ctype.h> #include <errno.h> #include <stdint.h> #include <stdio.h> @@ -9,6 +8,9 @@ #include "json.h" +#define ISDIGIT(c) (((unsigned)c) - '0' < 10) +#define ISXDIGIT(c) ((((unsigned)c) - '0' < 10) || ((unsigned)c | 32) - 'a' < 6) + static const unsigned char *json_data; static size_t json_data_size; static size_t json_data_off; @@ -116,7 +118,7 @@ int parsejson(const char *s, size_t slen, void (*cb)(struct json_node *, size_t, const char *, void *), void *pp) { - struct json_node nodes[JSON_MAX_NODE_DEPTH] = { 0 }; + struct json_node nodes[JSON_MAX_NODE_DEPTH] = { { 0 } }; size_t depth = 0, p = 0, len, sz = 0; long cp, hi, lo; char pri[128], *str = NULL; @@ -148,7 +150,7 @@ handlechr: expect = EXPECT_VALUE; break; case '"': - nodes[depth].type = TYPE_STRING; + nodes[depth].type = JSON_TYPE_STRING; escape = 0; len = 0; while (1) { @@ -174,8 +176,8 @@ escchr: if (capacity(&str, &sz, len, 4) == -1) goto end; for (i = 12, cp = 0; i >= 0; i -= 4) { - if ((c = GETNEXT()) == EOF || !isxdigit(c)) - JSON_INVALID(); /* invalid codepoint */ + if ((c = GETNEXT()) == EOF || !ISXDIGIT(c)) + JSON_INVALID(); /* invalid code point */ cp |= (hexdigit(c) << i); } /* RFC8259 - 7. Strings - surrogates. @@ -190,8 +192,8 @@ escchr: goto escchr; } for (hi = cp, i = 12, lo = 0; i >= 0; i -= 4) { - if ((c = GETNEXT()) == EOF || !isxdigit(c)) - JSON_INVALID(); /* invalid codepoint */ + if ((c = GETNEXT()) == EOF || !ISXDIGIT(c)) + JSON_INVALID(); /* invalid code point */ lo |= (hexdigit(c) << i); } /* 0xdc00 - 0xdfff - low surrogates */ @@ -248,11 +250,11 @@ escchr: nodes[depth].index = 0; if (c == '[') { - nodes[depth].type = TYPE_ARRAY; + nodes[depth].type = JSON_TYPE_ARRAY; expect = EXPECT_ARRAY_VALUE; } else if (c == '{') { iskey = 1; - nodes[depth].type = TYPE_OBJECT; + nodes[depth].type = JSON_TYPE_OBJECT; expect = EXPECT_OBJECT_STRING; } @@ -267,11 +269,12 @@ escchr: case ']': case '}': if (!depth || - (c == ']' && nodes[depth - 1].type != TYPE_ARRAY) || - (c == '}' && nodes[depth - 1].type != TYPE_OBJECT)) + (c == ']' && nodes[depth - 1].type != JSON_TYPE_ARRAY) || + (c == '}' && nodes[depth - 1].type != JSON_TYPE_OBJECT)) JSON_INVALID(); /* unbalanced nodes */ - nodes[--depth].index++; + depth--; + nodes[depth].index++; expect = EXPECT_END; break; case ',': @@ -279,7 +282,7 @@ escchr: JSON_INVALID(); /* unbalanced nodes */ nodes[depth - 1].index++; - if (nodes[depth - 1].type == TYPE_OBJECT) { + if (nodes[depth - 1].type == JSON_TYPE_OBJECT) { iskey = 1; expect = EXPECT_STRING; } else { @@ -289,7 +292,7 @@ escchr: case 't': /* true */ if (GETNEXT() != 'r' || GETNEXT() != 'u' || GETNEXT() != 'e') JSON_INVALID(); - nodes[depth].type = TYPE_BOOL; + nodes[depth].type = JSON_TYPE_BOOL; cb(nodes, depth + 1, "true", pp); expect = EXPECT_END; break; @@ -297,26 +300,27 @@ escchr: if (GETNEXT() != 'a' || GETNEXT() != 'l' || GETNEXT() != 's' || GETNEXT() != 'e') JSON_INVALID(); - nodes[depth].type = TYPE_BOOL; + nodes[depth].type = JSON_TYPE_BOOL; cb(nodes, depth + 1, "false", pp); expect = EXPECT_END; break; case 'n': /* null */ if (GETNEXT() != 'u' || GETNEXT() != 'l' || GETNEXT() != 'l') JSON_INVALID(); - nodes[depth].type = TYPE_NULL; + nodes[depth].type = JSON_TYPE_NULL; cb(nodes, depth + 1, "null", pp); expect = EXPECT_END; break; default: /* number */ - nodes[depth].type = TYPE_NUMBER; + nodes[depth].type = JSON_TYPE_NUMBER; p = 0; pri[p++] = c; expect = EXPECT_END; while (1) { c = GETNEXT(); if (c == EOF || - !c || !strchr("0123456789eE+-.", c) || + (!ISDIGIT(c) && c != 'e' && c != 'E' && + c != '+' && c != '-' && c != '.') || p + 1 >= sizeof(pri)) { pri[p] = '\0'; cb(nodes, depth + 1, pri, pp); (DIR) diff --git a/json.h b/json.h @@ -1,12 +1,15 @@ -#include <stdint.h> +#ifndef _JSON_H_ +#define _JSON_H_ + +#include <stddef.h> enum JSONType { - TYPE_ARRAY = 'a', - TYPE_OBJECT = 'o', - TYPE_STRING = 's', - TYPE_BOOL = 'b', - TYPE_NULL = '?', - TYPE_NUMBER = 'n' + JSON_TYPE_ARRAY = 'a', + JSON_TYPE_OBJECT = 'o', + JSON_TYPE_STRING = 's', + JSON_TYPE_BOOL = 'b', + JSON_TYPE_NULL = '?', + JSON_TYPE_NUMBER = 'n' }; enum JSONError { @@ -25,4 +28,5 @@ struct json_node { int parsejson(const char *, size_t, void (*cb)(struct json_node *, size_t, const char *, void *), - void *); + void *); +#endif