1
0
mirror of git://jb55.com/damus synced 2024-09-16 02:03:45 +00:00
damus/nostrdb/flatcc/flatcc_json_parser.h
2023-08-28 08:17:25 -07:00

896 lines
35 KiB
C

#ifndef FLATCC_JSON_PARSE_H
#define FLATCC_JSON_PARSE_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* JSON RFC:
* http://www.ietf.org/rfc/rfc4627.txt?number=4627
*
* With several flatbuffers specific extensions.
*/
#include <stdlib.h>
#include <string.h>
#include "flatcc_rtconfig.h"
#include "flatcc_builder.h"
#include "flatcc_unaligned.h"
#define PDIAGNOSTIC_IGNORE_UNUSED
#include "portable/pdiagnostic_push.h"
enum flatcc_json_parser_flags {
flatcc_json_parser_f_skip_unknown = 1,
flatcc_json_parser_f_force_add = 2,
flatcc_json_parser_f_with_size = 4,
flatcc_json_parser_f_skip_array_overflow = 8,
flatcc_json_parser_f_reject_array_underflow = 16
};
#define FLATCC_JSON_PARSE_ERROR_MAP(XX) \
XX(ok, "ok") \
XX(eof, "eof") \
XX(deep_nesting, "deep nesting") \
XX(trailing_comma, "trailing comma") \
XX(expected_colon, "expected colon") \
XX(unexpected_character, "unexpected character") \
XX(invalid_numeric, "invalid numeric") \
XX(overflow, "overflow") \
XX(underflow, "underflow") \
XX(unbalanced_array, "unbalanced array") \
XX(unbalanced_object, "unbalanced object") \
XX(precision_loss, "precision loss") \
XX(float_unexpected, "float unexpected") \
XX(unknown_symbol, "unknown symbol") \
XX(unquoted_symbolic_list, "unquoted list of symbols") \
XX(unknown_union, "unknown union type") \
XX(expected_string, "expected string") \
XX(invalid_character, "invalid character") \
XX(invalid_escape, "invalid escape") \
XX(invalid_type, "invalid type") \
XX(unterminated_string, "unterminated string") \
XX(expected_object, "expected object") \
XX(expected_array, "expected array") \
XX(expected_scalar, "expected literal or symbolic scalar") \
XX(expected_union_type, "expected union type") \
XX(union_none_present, "union present with type NONE") \
XX(union_none_not_null, "union of type NONE is not null") \
XX(union_incomplete, "table has incomplete union") \
XX(duplicate, "table has duplicate field") \
XX(required, "required field missing") \
XX(union_vector_length, "union vector length mismatch") \
XX(base64, "invalid base64 content") \
XX(base64url, "invalid base64url content") \
XX(array_underflow, "fixed length array underflow") \
XX(array_overflow, "fixed length array overflow") \
XX(runtime, "runtime error") \
XX(not_supported, "not supported")
enum flatcc_json_parser_error_no {
#define XX(no, str) flatcc_json_parser_error_##no,
FLATCC_JSON_PARSE_ERROR_MAP(XX)
#undef XX
};
const char *flatcc_json_parser_error_string(int err);
#define flatcc_json_parser_ok flatcc_json_parser_error_ok
#define flatcc_json_parser_eof flatcc_json_parser_error_eof
/*
* The struct may be zero initialized in which case the line count will
* start at line zero, or the line may be set to 1 initially. The ctx
* is only used for error reporting and tracking non-standard unquoted
* ctx.
*
* `ctx` may for example hold a flatcc_builder_t pointer.
*/
typedef struct flatcc_json_parser_ctx flatcc_json_parser_t;
struct flatcc_json_parser_ctx {
flatcc_builder_t *ctx;
const char *line_start;
int flags;
#if FLATCC_JSON_PARSE_ALLOW_UNQUOTED
int unquoted;
#endif
int line, pos;
int error;
const char *start;
const char *end;
const char *error_loc;
/* Set at end of successful parse. */
const char *end_loc;
};
static inline int flatcc_json_parser_get_error(flatcc_json_parser_t *ctx)
{
return ctx->error;
}
static inline void flatcc_json_parser_init(flatcc_json_parser_t *ctx, flatcc_builder_t *B, const char *buf, const char *end, int flags)
{
memset(ctx, 0, sizeof(*ctx));
ctx->ctx = B;
ctx->line_start = buf;
ctx->line = 1;
ctx->flags = flags;
/* These are not needed for parsing, but may be helpful in reporting etc. */
ctx->start = buf;
ctx->end = end;
ctx->error_loc = buf;
}
const char *flatcc_json_parser_set_error(flatcc_json_parser_t *ctx, const char *loc, const char *end, int reason);
/*
* Wide space is not necessarily beneficial in the typical space, but it
* also isn't expensive so it may be added when there are applications
* that can benefit.
*/
const char *flatcc_json_parser_space_ext(flatcc_json_parser_t *ctx, const char *buf, const char *end);
static inline const char *flatcc_json_parser_space(flatcc_json_parser_t *ctx, const char *buf, const char *end)
{
if (end - buf > 1) {
if (buf[0] > 0x20) {
return buf;
}
if (buf[0] == 0x20 && buf[1] > 0x20) {
return buf + 1;
}
}
return flatcc_json_parser_space_ext(ctx, buf, end);
}
static inline const char *flatcc_json_parser_string_start(flatcc_json_parser_t *ctx, const char *buf, const char *end)
{
if (buf == end || *buf != '\"') {
return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_expected_string);
}
return ++buf;
}
static inline const char *flatcc_json_parser_string_end(flatcc_json_parser_t *ctx, const char *buf, const char *end)
{
if (buf == end || *buf != '\"') {
return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_unterminated_string);
}
return ++buf;
}
/*
* Parse a string as a fixed length char array as `s` with length `n`.
* and raise errors according to overflow/underflow runtime flags. Zero
* and truncate as needed. A trailing zero is not inserted if the input
* is at least the same length as the char array.
*
* Runtime flags: `skip_array_overflow`, `pad_array_underflow`.
*/
const char *flatcc_json_parser_char_array(flatcc_json_parser_t *ctx,
const char *buf, const char *end, char *s, size_t n);
/*
* Creates a string. Returns *ref == 0 on unrecoverable error or
* sets *ref to a valid new string reference.
*/
const char *flatcc_json_parser_build_string(flatcc_json_parser_t *ctx,
const char *buf, const char *end, flatcc_builder_ref_t *ref);
typedef char flatcc_json_parser_escape_buffer_t[5];
/*
* If the buffer does not hold a valid escape sequence, an error is
* returned with code[0] = 0/
*
* Otherwise code[0] the length (1-4) of the remaining
* characters in the code, transcoded from the escape sequence
* where a length of 4 only happens with escapaped surrogate pairs.
*
* The JSON extension `\xXX` is supported and may produced invalid UTF-8
* characters such as 0xff. The standard JSON escape `\uXXXX` is not
* checked for invalid code points and may produce invalid UTF-8.
*
* Regular characters are expected to valid UTF-8 but they are not checked
* and may therefore produce invalid UTF-8.
*
* Control characters within a string are rejected except in the
* standard JSON escpaped form for `\n \r \t \b \f`.
*
* Additional escape codes as per standard JSON: `\\ \/ \"`.
*/
const char *flatcc_json_parser_string_escape(flatcc_json_parser_t *ctx, const char *buf, const char *end, flatcc_json_parser_escape_buffer_t code);
/*
* Parses the longest unescaped run of string content followed by either
* an escape encoding, string termination, or error.
*/
const char *flatcc_json_parser_string_part(flatcc_json_parser_t *ctx, const char *buf, const char *end);
static inline const char *flatcc_json_parser_symbol_start(flatcc_json_parser_t *ctx, const char *buf, const char *end)
{
if (buf == end) {
return buf;
}
if (*buf == '\"') {
++buf;
#if FLATCC_JSON_PARSE_ALLOW_UNQUOTED
ctx->unquoted = 0;
#endif
} else {
#if FLATCC_JSON_PARSE_ALLOW_UNQUOTED
if (*buf == '.') {
return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_unexpected_character);
}
ctx->unquoted = 1;
#else
return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_unexpected_character);
#endif
}
return buf;
}
static inline uint64_t flatcc_json_parser_symbol_part_ext(const char *buf, const char *end)
{
uint64_t w = 0;
size_t n = (size_t)(end - buf);
if (n > 8) {
n = 8;
}
/* This can bloat inlining for a rarely executed case. */
#if 1
/* Fall through comments needed to silence gcc 7 warnings. */
switch (n) {
case 8: w |= ((uint64_t)buf[7]) << (0 * 8);
fallthrough;
case 7: w |= ((uint64_t)buf[6]) << (1 * 8);
fallthrough;
case 6: w |= ((uint64_t)buf[5]) << (2 * 8);
fallthrough;
case 5: w |= ((uint64_t)buf[4]) << (3 * 8);
fallthrough;
case 4: w |= ((uint64_t)buf[3]) << (4 * 8);
fallthrough;
case 3: w |= ((uint64_t)buf[2]) << (5 * 8);
fallthrough;
case 2: w |= ((uint64_t)buf[1]) << (6 * 8);
fallthrough;
case 1: w |= ((uint64_t)buf[0]) << (7 * 8);
fallthrough;
case 0:
break;
}
#else
/* But this is hardly much of an improvement. */
{
size_t i;
for (i = 0; i < n; ++i) {
w <<= 8;
if (i < n) {
w = buf[i];
}
}
}
#endif
return w;
}
/*
* Read out string as a big endian word. This allows for trie lookup,
* also when trailing characters are beyond keyword. This assumes the
* external words tested against are valid and therefore there need be
* no checks here. If a match is not made, the symbol_end function will
* consume and check any unmatched content - from _before_ this function
* was called - i.e. the returned buffer is tentative for use only if we
* accept the part returned here.
*
* Used for both symbols and symbolic constants.
*/
static inline uint64_t flatcc_json_parser_symbol_part(const char *buf, const char *end)
{
size_t n = (size_t)(end - buf);
#if FLATCC_ALLOW_UNALIGNED_ACCESS
if (n >= 8) {
return be64toh(*(uint64_t *)buf);
}
#endif
return flatcc_json_parser_symbol_part_ext(buf, end);
}
/* Don't allow space in dot notation neither inside nor outside strings. */
static inline const char *flatcc_json_parser_match_scope(flatcc_json_parser_t *ctx, const char *buf, const char *end, int pos)
{
const char *mark = buf;
(void)ctx;
if (end - buf <= pos) {
return mark;
}
if (buf[pos] != '.') {
return mark;
}
return buf + pos + 1;
}
const char *flatcc_json_parser_match_constant(flatcc_json_parser_t *ctx, const char *buf, const char *end, int pos, int *more);
/* We allow '.' in unquoted symbols, but not at the start or end. */
static inline const char *flatcc_json_parser_symbol_end(flatcc_json_parser_t *ctx, const char *buf, const char *end)
{
char c, clast = 0;
#if FLATCC_JSON_PARSE_ALLOW_UNQUOTED
if (ctx->unquoted) {
while (buf != end && *buf > 0x20) {
clast = c = *buf;
if (c == '_' || c == '.' || (c & 0x80) || (c >= '0' && c <= '9')) {
++buf;
continue;
}
/* Lower case. */
c |= 0x20;
if (c >= 'a' && c <= 'z') {
++buf;
continue;
}
break;
}
if (clast == '.') {
return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_unexpected_character);
}
} else {
#else
{
#endif
while (buf != end && *buf != '\"') {
if (*buf == '\\') {
if (end - buf < 2) {
break;
}
++buf;
}
++buf;
}
if (buf == end || *buf != '\"') {
return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_unterminated_string);
}
++buf;
}
return buf;
}
static inline const char *flatcc_json_parser_constant_start(flatcc_json_parser_t *ctx, const char *buf, const char *end)
{
buf = flatcc_json_parser_symbol_start(ctx, buf, end);
#if FLATCC_JSON_PARSE_ALLOW_UNQUOTED
if (!ctx->unquoted) {
#else
{
#endif
buf = flatcc_json_parser_space(ctx, buf, end);
}
return buf;
}
static inline const char *flatcc_json_parser_object_start(flatcc_json_parser_t *ctx, const char *buf, const char *end, int *more)
{
if (buf == end || *buf != '{') {
*more = 0;
return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_expected_object);
}
buf = flatcc_json_parser_space(ctx, buf + 1, end);
if (buf != end && *buf == '}') {
*more = 0;
return flatcc_json_parser_space(ctx, buf + 1, end);
}
*more = 1;
return buf;
}
static inline const char *flatcc_json_parser_object_end(flatcc_json_parser_t *ctx, const char *buf,
const char *end, int *more)
{
buf = flatcc_json_parser_space(ctx, buf, end);
if (buf == end) {
*more = 0;
return buf;
}
if (*buf != ',') {
*more = 0;
if (*buf != '}') {
return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_unbalanced_object);
} else {
return flatcc_json_parser_space(ctx, buf + 1, end);
}
}
buf = flatcc_json_parser_space(ctx, buf + 1, end);
if (buf == end) {
*more = 0;
return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_unbalanced_object);
}
#if FLATCC_JSON_PARSE_ALLOW_TRAILING_COMMA
if (*buf == '}') {
*more = 0;
return flatcc_json_parser_space(ctx, buf + 1, end);
}
#endif
*more = 1;
return buf;
}
static inline const char *flatcc_json_parser_array_start(flatcc_json_parser_t *ctx, const char *buf, const char *end, int *more)
{
if (buf == end || *buf != '[') {
*more = 0;
return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_expected_array);
}
buf = flatcc_json_parser_space(ctx, buf + 1, end);
if (buf != end && *buf == ']') {
*more = 0;
return flatcc_json_parser_space(ctx, buf + 1, end);
}
*more = 1;
return buf;
}
static inline const char *flatcc_json_parser_array_end(flatcc_json_parser_t *ctx, const char *buf,
const char *end, int *more)
{
buf = flatcc_json_parser_space(ctx, buf, end);
if (buf == end) {
*more = 0;
return buf;
}
if (*buf != ',') {
*more = 0;
if (*buf != ']') {
return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_unbalanced_array);
} else {
return flatcc_json_parser_space(ctx, buf + 1, end);
}
}
buf = flatcc_json_parser_space(ctx, buf + 1, end);
if (buf == end) {
*more = 0;
return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_unbalanced_array);
}
#if FLATCC_JSON_PARSE_ALLOW_TRAILING_COMMA
if (*buf == ']') {
*more = 0;
return flatcc_json_parser_space(ctx, buf + 1, end);
}
#endif
*more = 1;
return buf;
}
/*
* Detects if a symbol terminates at a given `pos` relative to the
* buffer pointer, or return fast.
*
* Failure to match is not an error but a recommendation to try
* alternative longer suffixes - only if such do not exist will
* there be an error. If a match was not eventually found,
* the `flatcc_json_parser_unmatched_symbol` should be called to consume
* the symbol and generate error messages.
*
* If a match was detected, ':' and surrounding space is consumed,
* or an error is generated.
*/
static inline const char *flatcc_json_parser_match_symbol(flatcc_json_parser_t *ctx, const char *buf,
const char *end, int pos)
{
const char *mark = buf;
if (end - buf <= pos) {
return mark;
}
#if FLATCC_JSON_PARSE_ALLOW_UNQUOTED
if (ctx->unquoted) {
if (buf[pos] > 0x20 && buf[pos] != ':') {
return mark;
}
buf += pos;
ctx->unquoted = 0;
} else {
#else
{
#endif
if (buf[pos] != '\"') {
return mark;
}
buf += pos + 1;
}
buf = flatcc_json_parser_space(ctx, buf, end);
if (buf != end && *buf == ':') {
++buf;
return flatcc_json_parser_space(ctx, buf, end);
}
return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_expected_colon);
}
static inline const char *flatcc_json_parser_match_type_suffix(flatcc_json_parser_t *ctx, const char *buf, const char *end, int pos)
{
if (end - buf <= pos + 5) {
return buf;
}
if (memcmp(buf + pos, "_type", 5)) {
return buf;
}
return flatcc_json_parser_match_symbol(ctx, buf, end, pos + 5);
}
const char *flatcc_json_parser_unmatched_symbol(flatcc_json_parser_t *ctx, const char *buf, const char *end);
static inline const char *flatcc_json_parser_coerce_uint64(
flatcc_json_parser_t *ctx, const char *buf,
const char *end, int value_sign, uint64_t value, uint64_t *v)
{
if (value_sign) {
return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_underflow);
}
*v = value;
return buf;
}
static inline const char *flatcc_json_parser_coerce_bool(flatcc_json_parser_t *ctx, const char *buf,
const char *end, int value_sign, uint64_t value, uint8_t *v)
{
if (value_sign) {
return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_underflow);
}
*v = (uint8_t)!!value;
return buf;
}
#define __flatcc_json_parser_define_coerce_unsigned(type, basetype, uctype) \
static inline const char *flatcc_json_parser_coerce_ ## type( \
flatcc_json_parser_t *ctx, const char *buf, \
const char *end, int value_sign, uint64_t value, basetype *v) \
{ \
if (value_sign) { \
return flatcc_json_parser_set_error(ctx, buf, end, \
flatcc_json_parser_error_underflow); \
} \
if (value > uctype ## _MAX) { \
return flatcc_json_parser_set_error(ctx, buf, end, \
flatcc_json_parser_error_overflow); \
} \
*v = (basetype)value; \
return buf; \
}
__flatcc_json_parser_define_coerce_unsigned(uint32, uint32_t, UINT32)
__flatcc_json_parser_define_coerce_unsigned(uint16, uint16_t, UINT16)
__flatcc_json_parser_define_coerce_unsigned(uint8, uint8_t, UINT8)
#define __flatcc_json_parser_define_coerce_signed(type, basetype, uctype) \
static inline const char *flatcc_json_parser_coerce_ ## type( \
flatcc_json_parser_t *ctx, const char *buf, \
const char *end, int value_sign, uint64_t value, basetype *v) \
{ \
if (value_sign) { \
if (value > (uint64_t)(uctype ## _MAX) + 1) { \
return flatcc_json_parser_set_error(ctx, buf, end, \
flatcc_json_parser_error_underflow); \
} \
*v = (basetype)-(int64_t)value; \
} else { \
if (value > uctype ## _MAX) { \
return flatcc_json_parser_set_error(ctx, buf, end, \
flatcc_json_parser_error_overflow); \
} \
*v = (basetype)value; \
} \
return buf; \
}
__flatcc_json_parser_define_coerce_signed(int64, int64_t, INT64)
__flatcc_json_parser_define_coerce_signed(int32, int32_t, INT32)
__flatcc_json_parser_define_coerce_signed(int16, int16_t, INT16)
__flatcc_json_parser_define_coerce_signed(int8, int8_t, INT8)
static inline const char *flatcc_json_parser_coerce_float(
flatcc_json_parser_t *ctx, const char *buf,
const char *end, int value_sign, uint64_t value, float *v)
{
(void)ctx;
(void)end;
*v = value_sign ? -(float)value : (float)value;
return buf;
}
static inline const char *flatcc_json_parser_coerce_double(
flatcc_json_parser_t *ctx, const char *buf,
const char *end, int value_sign, uint64_t value, double *v)
{
(void)ctx;
(void)end;
*v = value_sign ? -(double)value : (double)value;
return buf;
}
const char *flatcc_json_parser_double(flatcc_json_parser_t *ctx, const char *buf, const char *end, double *v);
const char *flatcc_json_parser_float(flatcc_json_parser_t *ctx, const char *buf, const char *end, float *v);
/*
* If the buffer does not contain a valid start character for a numeric
* value, the function will return the the input buffer without failure.
* This makes is possible to try a symbolic parse.
*/
const char *flatcc_json_parser_integer(flatcc_json_parser_t *ctx, const char *buf, const char *end,
int *value_sign, uint64_t *value);
/* Returns unchanged buffer without error if `null` is not matched. */
static inline const char *flatcc_json_parser_null(const char *buf, const char *end)
{
if (end - buf >= 4 && memcmp(buf, "null", 4) == 0) {
return buf + 4;
}
return buf;
}
static inline const char *flatcc_json_parser_none(flatcc_json_parser_t *ctx,
const char *buf, const char *end)
{
if (end - buf >= 4 && memcmp(buf, "null", 4) == 0) {
return buf + 4;
}
return flatcc_json_parser_set_error(ctx, buf, end,
flatcc_json_parser_error_union_none_not_null);
}
/*
* `parsers` is a null terminated array of parsers with at least one
* valid parser. A numeric literal parser may also be included.
*/
#define __flatcc_json_parser_define_integral_parser(type, basetype) \
static inline const char *flatcc_json_parser_ ## type( \
flatcc_json_parser_t *ctx, \
const char *buf, const char *end, basetype *v) \
{ \
uint64_t value = 0; \
int value_sign = 0; \
const char *mark = buf; \
\
*v = 0; \
if (buf == end) { \
return buf; \
} \
buf = flatcc_json_parser_integer(ctx, buf, end, &value_sign, &value); \
if (buf != mark) { \
return flatcc_json_parser_coerce_ ## type(ctx, \
buf, end, value_sign, value, v); \
} \
return buf; \
}
__flatcc_json_parser_define_integral_parser(uint64, uint64_t)
__flatcc_json_parser_define_integral_parser(uint32, uint32_t)
__flatcc_json_parser_define_integral_parser(uint16, uint16_t)
__flatcc_json_parser_define_integral_parser(uint8, uint8_t)
__flatcc_json_parser_define_integral_parser(int64, int64_t)
__flatcc_json_parser_define_integral_parser(int32, int32_t)
__flatcc_json_parser_define_integral_parser(int16, int16_t)
__flatcc_json_parser_define_integral_parser(int8, int8_t)
static inline const char *flatcc_json_parser_bool(flatcc_json_parser_t *ctx, const char *buf, const char *end, uint8_t *v)
{
const char *k;
uint8_t tmp;
k = buf;
if (end - buf >= 4 && memcmp(buf, "true", 4) == 0) {
*v = 1;
return k + 4;
} else if (end - buf >= 5 && memcmp(buf, "false", 5) == 0) {
*v = 0;
return k + 5;
}
buf = flatcc_json_parser_uint8(ctx, buf, end, &tmp);
*v = !!tmp;
return buf;
}
/*
* The `parsers` argument is a zero terminated array of parser
* functions with increasingly general scopes.
*
* Symbols can be be or'ed together by listing multiple space separated
* flags in source being parsed, like `{ x : "Red Blue" }`.
* Intended for flags, but generally available.
*
* `aggregate` means there are more symbols to follow.
*
* This function does not return input `buf` value if match was
* unsuccessful. It will either match or error.
*/
typedef const char *flatcc_json_parser_integral_symbol_f(flatcc_json_parser_t *ctx,
const char *buf, const char *end, int *value_sign, uint64_t *value, int *aggregate);
/*
* Raise an error if a syntax like `color: Red Green` is seen unless
* explicitly permitted. `color: "Red Green"` or `"color": "Red Green"
* or `color: Red` is permitted if unquoted is permitted but not
* unquoted list. Googles flatc JSON parser does not allow multiple
* symbolic values unless quoted, so this is the default.
*/
#if !FLATCC_JSON_PARSE_ALLOW_UNQUOTED || FLATCC_JSON_PARSE_ALLOW_UNQUOTED_LIST
#define __flatcc_json_parser_init_check_unquoted_list()
#define __flatcc_json_parser_check_unquoted_list()
#else
#define __flatcc_json_parser_init_check_unquoted_list() int list_count = 0;
#define __flatcc_json_parser_check_unquoted_list() \
if (list_count++ && ctx->unquoted) { \
return flatcc_json_parser_set_error(ctx, buf, end, \
flatcc_json_parser_error_unquoted_symbolic_list); \
}
#endif
#define __flatcc_json_parser_define_symbolic_integral_parser(type, basetype)\
static const char *flatcc_json_parser_symbolic_ ## type( \
flatcc_json_parser_t *ctx, \
const char *buf, const char *end, \
flatcc_json_parser_integral_symbol_f *parsers[], \
basetype *v) \
{ \
flatcc_json_parser_integral_symbol_f **p; \
const char *mark; \
basetype tmp = 0; \
uint64_t value; \
int value_sign, aggregate; \
__flatcc_json_parser_init_check_unquoted_list() \
\
*v = 0; \
buf = flatcc_json_parser_constant_start(ctx, buf, end); \
if (buf == end) { \
return buf; \
} \
do { \
p = parsers; \
do { \
/* call parser function */ \
buf = (*p)(ctx, (mark = buf), end, \
&value_sign, &value, &aggregate); \
if (buf == end) { \
return buf; \
} \
} while (buf == mark && *++p); \
if (mark == buf) { \
return flatcc_json_parser_set_error(ctx, buf, end, \
flatcc_json_parser_error_expected_scalar); \
} \
__flatcc_json_parser_check_unquoted_list() \
if (end == flatcc_json_parser_coerce_ ## type(ctx, \
buf, end, value_sign, value, &tmp)) { \
return end; \
} \
/* \
* `+=`, not `|=` because we also coerce to float and double, \
* and because we need to handle signed values. This may give \
* unexpected results with duplicate flags. \
*/ \
*v += tmp; \
} while (aggregate); \
return buf; \
}
__flatcc_json_parser_define_symbolic_integral_parser(uint64, uint64_t)
__flatcc_json_parser_define_symbolic_integral_parser(uint32, uint32_t)
__flatcc_json_parser_define_symbolic_integral_parser(uint16, uint16_t)
__flatcc_json_parser_define_symbolic_integral_parser(uint8, uint8_t)
__flatcc_json_parser_define_symbolic_integral_parser(int64, int64_t)
__flatcc_json_parser_define_symbolic_integral_parser(int32, int32_t)
__flatcc_json_parser_define_symbolic_integral_parser(int16, int16_t)
__flatcc_json_parser_define_symbolic_integral_parser(int8, int8_t)
__flatcc_json_parser_define_symbolic_integral_parser(bool, uint8_t)
/* We still parse integral values, but coerce to float or double. */
__flatcc_json_parser_define_symbolic_integral_parser(float, float)
__flatcc_json_parser_define_symbolic_integral_parser(double, double)
/* Parse vector as a base64 or base64url encoded string with no spaces permitted. */
const char *flatcc_json_parser_build_uint8_vector_base64(flatcc_json_parser_t *ctx,
const char *buf, const char *end, flatcc_builder_ref_t *ref, int urlsafe);
/*
* This doesn't do anything other than validate and advance past
* a JSON value which may use unquoted symbols.
*
* Upon call it is assumed that leading space has been stripped and that
* a JSON value is expected (i.e. root, or just after ':' in a
* container object, or less likely as an array member). Any trailing
* comma is assumed to belong to the parent context. Returns a parse
* location stripped from space so container should post call expect
* ',', '}', or ']', or EOF if the JSON is valid.
*/
const char *flatcc_json_parser_generic_json(flatcc_json_parser_t *ctx, const char *buf, const char *end);
/* Parse a JSON table. */
typedef const char *flatcc_json_parser_table_f(flatcc_json_parser_t *ctx,
const char *buf, const char *end, flatcc_builder_ref_t *pref);
/* Parses a JSON struct. */
typedef const char *flatcc_json_parser_struct_f(flatcc_json_parser_t *ctx,
const char *buf, const char *end, flatcc_builder_ref_t *pref);
/* Constructs a table, struct, or string object unless the type is 0 or unknown. */
typedef const char *flatcc_json_parser_union_f(flatcc_json_parser_t *ctx,
const char *buf, const char *end, uint8_t type, flatcc_builder_ref_t *pref);
typedef int flatcc_json_parser_is_known_type_f(uint8_t type);
/* Called at start by table parsers with at least 1 union. */
const char *flatcc_json_parser_prepare_unions(flatcc_json_parser_t *ctx,
const char *buf, const char *end, size_t union_total, size_t *handle);
const char *flatcc_json_parser_finalize_unions(flatcc_json_parser_t *ctx,
const char *buf, const char *end, size_t handle);
const char *flatcc_json_parser_union(flatcc_json_parser_t *ctx,
const char *buf, const char *end, size_t union_index,
flatbuffers_voffset_t id, size_t handle,
flatcc_json_parser_union_f *union_parser);
const char *flatcc_json_parser_union_type(flatcc_json_parser_t *ctx,
const char *buf, const char *end, size_t union_index,
flatbuffers_voffset_t id, size_t handle,
flatcc_json_parser_integral_symbol_f *type_parsers[],
flatcc_json_parser_union_f *union_parser);
const char *flatcc_json_parser_union_vector(flatcc_json_parser_t *ctx,
const char *buf, const char *end, size_t union_index,
flatbuffers_voffset_t id, size_t handle,
flatcc_json_parser_union_f *union_parser);
const char *flatcc_json_parser_union_type_vector(flatcc_json_parser_t *ctx,
const char *buf, const char *end, size_t union_index,
flatbuffers_voffset_t id, size_t handle,
flatcc_json_parser_integral_symbol_f *type_parsers[],
flatcc_json_parser_union_f *union_parser,
flatcc_json_parser_is_known_type_f accept_type);
/*
* Parses a table as root.
*
* Use the flag `flatcc_json_parser_f_with_size` to create a buffer with
* size prefix.
*
* `ctx` may be null or an uninitialized json parser to receive parse results.
* `builder` must a newly initialized or reset builder object.
* `buf`, `bufsiz` may be larger than the parsed json if trailing
* space or zeroes are expected, but they must represent a valid memory buffer.
* `fid` must be null, or a valid file identifier.
* `flags` default to 0. See also `flatcc_json_parser_flags`.
*/
int flatcc_json_parser_table_as_root(flatcc_builder_t *B, flatcc_json_parser_t *ctx,
const char *buf, size_t bufsiz, int flags, const char *fid,
flatcc_json_parser_table_f *parser);
/*
* Similar to `flatcc_json_parser_table_as_root` but parses a struct as
* root.
*/
int flatcc_json_parser_struct_as_root(flatcc_builder_t *B, flatcc_json_parser_t *ctx,
const char *buf, size_t bufsiz, int flags, const char *fid,
flatcc_json_parser_struct_f *parser);
#include "portable/pdiagnostic_pop.h"
#ifdef __cplusplus
}
#endif
#endif /* FLATCC_JSON_PARSE_H */