JSON-YY
view release on metacpan or search on metacpan
#define yyjson_min(x, y) ((x) < (y) ? (x) : (y))
#undef yyjson_max
#define yyjson_max(x, y) ((x) > (y) ? (x) : (y))
/* Used to write u64 literal for C89 which doesn't support "ULL" suffix. */
#undef U64
#define U64(hi, lo) ((((u64)hi##UL) << 32U) + lo##UL)
#undef U32
#define U32(hi) ((u32)(hi##UL))
/* Used to cast away (remove) const qualifier. */
#define constcast(type) (type)(void *)(size_t)(const void *)
/*
Compiler barriers for single variables.
These macros inform GCC that a read or write access to the given memory
location will occur, preventing certain compiler optimizations or reordering
around the access to 'val'. They do not emit any actual instructions.
This is useful when GCC's default optimization strategies are suboptimal and
precise control over memory access patterns is required.
These barriers are not needed when using Clang or MSVC.
*/
#if YYJSON_IS_REAL_GCC
# define gcc_load_barrier(val) __asm__ volatile(""::"m"(val))
# define gcc_store_barrier(val) __asm__ volatile("":"=m"(val))
# define gcc_full_barrier(val) __asm__ volatile("":"=m"(val):"m"(val))
#else
# define gcc_load_barrier(val)
# define gcc_store_barrier(val)
# define gcc_full_barrier(val)
#endif
/*==============================================================================
* MARK: - Constants (Private)
*============================================================================*/
/* Common error messages. */
#define MSG_FOPEN "failed to open file"
#define MSG_FREAD "failed to read file"
#define MSG_FWRITE "failed to write file"
#define MSG_FCLOSE "failed to close file"
#define MSG_MALLOC "failed to allocate memory"
#define MSG_CHAR_T "invalid literal, expected 'true'"
#define MSG_CHAR_F "invalid literal, expected 'false'"
#define MSG_CHAR_N "invalid literal, expected 'null'"
#define MSG_CHAR "unexpected character, expected a JSON value"
#define MSG_ARR_END "unexpected character, expected ',' or ']'"
#define MSG_OBJ_KEY "unexpected character, expected a string key"
#define MSG_OBJ_SEP "unexpected character, expected ':' after key"
#define MSG_OBJ_END "unexpected character, expected ',' or '}'"
#define MSG_GARBAGE "unexpected content after document"
#define MSG_NOT_END "unexpected end of data"
#define MSG_COMMENT "unclosed multiline comment"
#define MSG_COMMA "trailing comma is not allowed"
#define MSG_NAN_INF "nan or inf number is not allowed"
#define MSG_ERR_TYPE "invalid JSON value type"
#define MSG_ERR_BOM "UTF-8 byte order mark (BOM) is not supported"
#define MSG_ERR_UTF8 "invalid utf-8 encoding in string"
#define MSG_ERR_UTF16 "UTF-16 encoding is not supported"
#define MSG_ERR_UTF32 "UTF-32 encoding is not supported"
/* U64 constant values */
#undef U64_MAX
#define U64_MAX U64(0xFFFFFFFF, 0xFFFFFFFF)
#undef I64_MAX
#define I64_MAX U64(0x7FFFFFFF, 0xFFFFFFFF)
#undef USIZE_MAX
#define USIZE_MAX ((usize)(~(usize)0))
/* Maximum number of digits for reading u32/u64/usize safety (not overflow). */
#undef U32_SAFE_DIG
#define U32_SAFE_DIG 9 /* u32 max is 4294967295, 10 digits */
#undef U64_SAFE_DIG
#define U64_SAFE_DIG 19 /* u64 max is 18446744073709551615, 20 digits */
#undef USIZE_SAFE_DIG
#define USIZE_SAFE_DIG (sizeof(usize) == 8 ? U64_SAFE_DIG : U32_SAFE_DIG)
/* Inf bits (positive) */
#define F64_BITS_INF U64(0x7FF00000, 0x00000000)
/* NaN bits (quiet NaN, no payload, no sign) */
#if defined(__hppa__) || (defined(__mips__) && !defined(__mips_nan2008))
#define F64_BITS_NAN U64(0x7FF7FFFF, 0xFFFFFFFF)
#else
#define F64_BITS_NAN U64(0x7FF80000, 0x00000000)
#endif
/* maximum significant digits count in decimal when reading double number */
#define F64_MAX_DEC_DIG 768
/* maximum decimal power of double number (1.7976931348623157e308) */
#define F64_MAX_DEC_EXP 308
/* minimum decimal power of double number (4.9406564584124654e-324) */
#define F64_MIN_DEC_EXP (-324)
/* maximum binary power of double number */
#define F64_MAX_BIN_EXP 1024
/* minimum binary power of double number */
#define F64_MIN_BIN_EXP (-1021)
/* float/double number bits */
#define F32_BITS 32
#define F64_BITS 64
/* float/double number exponent part bits */
#define F32_EXP_BITS 8
#define F64_EXP_BITS 11
/* float/double number significand part bits */
#define F32_SIG_BITS 23
#define F64_SIG_BITS 52
/* float/double number significand part bits (with 1 hidden bit) */
#define F32_SIG_FULL_BITS 24
#define F64_SIG_FULL_BITS 53
if (len > 0) {
yyjson_mut_obj_iter iter;
yyjson_mut_obj_iter_init(rhs, &iter);
lhs = (yyjson_mut_val *)lhs->uni.ptr;
while (len-- > 0) {
rhs = yyjson_mut_obj_iter_getn(&iter, lhs->uni.str,
unsafe_yyjson_get_len(lhs));
if (!rhs) return false;
if (!unsafe_yyjson_mut_equals(lhs->next, rhs)) return false;
lhs = lhs->next->next;
}
}
/* yyjson allows duplicate keys, so the check may be inaccurate */
return true;
}
case YYJSON_TYPE_ARR: {
usize len = unsafe_yyjson_get_len(lhs);
if (len != unsafe_yyjson_get_len(rhs)) return false;
if (len > 0) {
lhs = (yyjson_mut_val *)lhs->uni.ptr;
rhs = (yyjson_mut_val *)rhs->uni.ptr;
while (len-- > 0) {
if (!unsafe_yyjson_mut_equals(lhs, rhs)) return false;
lhs = lhs->next;
rhs = rhs->next;
}
}
return true;
}
case YYJSON_TYPE_NUM:
return unsafe_yyjson_num_equals(lhs, rhs);
case YYJSON_TYPE_RAW:
case YYJSON_TYPE_STR:
return unsafe_yyjson_str_equals(lhs, rhs);
case YYJSON_TYPE_NULL:
case YYJSON_TYPE_BOOL:
return lhs->tag == rhs->tag;
default:
return false;
}
}
bool yyjson_locate_pos(const char *str, size_t len, size_t pos,
size_t *line, size_t *col, size_t *chr) {
usize line_sum = 0, line_pos = 0, chr_sum = 0;
const u8 *cur = (const u8 *)str;
const u8 *end = cur + pos;
if (!str || pos > len) {
if (line) *line = 0;
if (col) *col = 0;
if (chr) *chr = 0;
return false;
}
if (pos >= 3 && is_utf8_bom(cur)) cur += 3; /* don't count BOM */
while (cur < end) {
u8 c = *cur;
chr_sum += 1;
if (likely(c < 0x80)) { /* 0xxxxxxx (0x00-0x7F) ASCII */
if (c == '\n') {
line_sum += 1;
line_pos = chr_sum;
}
cur += 1;
}
else if (c < 0xC0) cur += 1; /* 10xxxxxx (0x80-0xBF) Invalid */
else if (c < 0xE0) cur += 2; /* 110xxxxx (0xC0-0xDF) 2-byte UTF-8 */
else if (c < 0xF0) cur += 3; /* 1110xxxx (0xE0-0xEF) 3-byte UTF-8 */
else if (c < 0xF8) cur += 4; /* 11110xxx (0xF0-0xF7) 4-byte UTF-8 */
else cur += 1; /* 11111xxx (0xF8-0xFF) Invalid */
}
if (line) *line = line_sum + 1;
if (col) *col = chr_sum - line_pos + 1;
if (chr) *chr = chr_sum;
return true;
}
#if !YYJSON_DISABLE_READER /* reader begin */
/* Check read flag, avoids `always false` warning when disabled. */
#define has_flg(_flg) unlikely(has_rflag(flg, YYJSON_READ_##_flg, 0))
#define has_allow(_flg) unlikely(has_rflag(flg, YYJSON_READ_ALLOW_##_flg, 1))
#define YYJSON_READ_ALLOW_TRIVIA (YYJSON_READ_ALLOW_COMMENTS | \
YYJSON_READ_ALLOW_EXT_WHITESPACE)
static_inline bool has_rflag(yyjson_read_flag flg, yyjson_read_flag chk,
bool non_standard) {
#if YYJSON_DISABLE_NON_STANDARD
if (non_standard) return false;
#endif
return (flg & chk) != 0;
}
/*==============================================================================
* MARK: - JSON Reader Utils (Private)
* These functions are used by JSON reader to read literals and comments.
*============================================================================*/
/** Read `true` literal, `*ptr[0]` should be `t`. */
static_inline bool read_true(u8 **ptr, yyjson_val *val) {
u8 *cur = *ptr;
if (likely(byte_match_4(cur, "true"))) {
val->tag = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_TRUE;
*ptr = cur + 4;
return true;
}
return false;
}
/** Read `false` literal, `*ptr[0]` should be `f`. */
static_inline bool read_false(u8 **ptr, yyjson_val *val) {
u8 *cur = *ptr;
if (has_allow(INF_AND_NAN)) {
if (hdr + 3 <= cur &&
is_truncated_str(cur - 3, eof, "infinity", false)) {
return true; /* e.g. infin would be read as inf + in */
}
}
}
if (code == YYJSON_READ_ERROR_INVALID_STRING) {
usize len = (usize)(eof - cur);
/* unicode escape sequence */
if (*cur == '\\') {
if (len == 1) return true;
if (len <= 5) {
if (*++cur != 'u') return false;
for (++cur; cur < eof; cur++) {
if (!char_is_hex(*cur)) return false;
}
return true;
} else if (len <= 11) {
/* incomplete surrogate pair? */
u16 hi;
if (*++cur != 'u') return false;
if (!hex_load_4(++cur, &hi)) return false;
if ((hi & 0xF800) != 0xD800) return false;
cur += 4;
if (cur >= eof) return true;
/* valid low surrogate is DC00...DFFF */
if (*cur != '\\') return false;
if (++cur >= eof) return true;
if (*cur != 'u') return false;
if (++cur >= eof) return true;
if (*cur != 'd' && *cur != 'D') return false;
if (++cur >= eof) return true;
if ((*cur < 'c' || *cur > 'f') && (*cur < 'C' || *cur > 'F'))
return false;
if (++cur >= eof) return true;
if (!char_is_hex(*cur)) return false;
return true;
}
return false;
}
/* 2 to 4 bytes UTF-8 */
if (is_truncated_utf8(cur, eof)) {
return true;
}
}
if (has_allow(COMMENTS)) {
if (code == YYJSON_READ_ERROR_INVALID_COMMENT) {
/* unclosed multiline comment */
return true;
}
if (code == YYJSON_READ_ERROR_UNEXPECTED_CHARACTER &&
*cur == '/' && cur + 1 == eof) {
/* truncated beginning of comment */
return true;
}
}
if (code == YYJSON_READ_ERROR_UNEXPECTED_CHARACTER &&
has_allow(BOM)) {
/* truncated UTF-8 BOM */
usize len = (usize)(eof - cur);
if (cur == hdr && len < 3 && !memcmp(hdr, "\xEF\xBB\xBF", len)) {
return true;
}
}
return false;
}
#if !YYJSON_DISABLE_FAST_FP_CONV /* FP_READER */
/*==============================================================================
* MARK: - BigInt For Floating Point Number Reader (Private)
*
* The bigint algorithm is used by floating-point number reader to get correctly
* rounded result for numbers with lots of digits. This part of code is rarely
* used for common numbers.
*============================================================================*/
/** Unsigned arbitrarily large integer */
typedef struct bigint {
u32 used; /* used chunks count, should not be 0 */
u64 bits[64]; /* chunks (58 is enough here) */
} bigint;
/**
Evaluate 'big += val'.
@param big A big number (can be 0).
@param val An unsigned integer (can be 0).
*/
static_inline void bigint_add_u64(bigint *big, u64 val) {
u32 idx, max;
u64 num = big->bits[0];
u64 add = num + val;
big->bits[0] = add;
if (likely((add >= num) || (add >= val))) return;
for ((void)(idx = 1), max = big->used; idx < max; idx++) {
if (likely(big->bits[idx] != U64_MAX)) {
big->bits[idx] += 1;
return;
}
big->bits[idx] = 0;
}
big->bits[big->used++] = 1;
}
/**
Evaluate 'big *= val'.
@param big A big number (can be 0).
@param val An unsigned integer (cannot be 0).
*/
static_inline void bigint_mul_u64(bigint *big, u64 val) {
u32 idx = 0, max = big->used;
u64 hi, lo, carry = 0;
for (; idx < max; idx++) {
if (big->bits[idx]) break;
}
for (; idx < max; idx++) {
u128_mul_add(big->bits[idx], val, carry, &hi, &lo);
fail_literal_null: return_err(cur, LITERAL, MSG_CHAR_N);
fail_character_val: return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
fail_character_arr_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_ARR_END);
fail_character_obj_key: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_KEY);
fail_character_obj_sep: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_SEP);
fail_character_obj_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_END);
fail_comment: return_err(cur, INVALID_COMMENT, MSG_COMMENT);
fail_garbage: return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
#undef val_incr
#undef return_err
}
/*==============================================================================
* MARK: - JSON Reader (Public)
*============================================================================*/
yyjson_doc *yyjson_read_opts(char *dat, usize len,
yyjson_read_flag flg,
const yyjson_alc *alc_ptr,
yyjson_read_err *err) {
#define return_err(_pos, _code, _msg) do { \
err->pos = (usize)(_pos); \
err->msg = _msg; \
err->code = YYJSON_READ_ERROR_##_code; \
if (!has_flg(INSITU) && hdr) alc.free(alc.ctx, (void *)hdr); \
return NULL; \
} while (false)
yyjson_read_err tmp_err;
yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
yyjson_doc *doc;
u8 *hdr = NULL, *eof, *cur;
/* validate input parameters */
if (!err) err = &tmp_err;
if (unlikely(!dat)) return_err(0, INVALID_PARAMETER, "input data is NULL");
if (unlikely(!len)) return_err(0, INVALID_PARAMETER, "input length is 0");
/* add 4-byte zero padding for input data if necessary */
if (has_flg(INSITU)) {
hdr = (u8 *)dat;
eof = (u8 *)dat + len;
cur = (u8 *)dat;
} else {
if (unlikely(len >= USIZE_MAX - YYJSON_PADDING_SIZE)) {
return_err(0, MEMORY_ALLOCATION, MSG_MALLOC);
}
hdr = (u8 *)alc.malloc(alc.ctx, len + YYJSON_PADDING_SIZE);
if (unlikely(!hdr)) {
return_err(0, MEMORY_ALLOCATION, MSG_MALLOC);
}
eof = hdr + len;
cur = hdr;
memcpy(hdr, dat, len);
}
memset(eof, 0, YYJSON_PADDING_SIZE);
if (has_allow(BOM)) {
if (len >= 3 && is_utf8_bom(cur)) cur += 3;
}
/* skip empty contents before json document */
if (unlikely(!char_is_ctn(*cur))) {
while (char_is_space(*cur)) cur++;
if (unlikely(!char_is_ctn(*cur))) {
if (has_allow(TRIVIA) && char_is_trivia(*cur)) {
if (!skip_trivia(&cur, eof, flg) && cur == eof) {
return_err(cur - hdr, INVALID_COMMENT, MSG_COMMENT);
}
}
}
if (unlikely(cur >= eof)) {
return_err(0, EMPTY_CONTENT, "input data is empty");
}
}
/* read json document */
if (likely(char_is_ctn(*cur))) {
if (char_is_space(cur[1]) && char_is_space(cur[2])) {
doc = read_root_pretty(hdr, cur, eof, alc, flg, err);
} else {
doc = read_root_minify(hdr, cur, eof, alc, flg, err);
}
} else {
doc = read_root_single(hdr, cur, eof, alc, flg, err);
}
/* check result */
if (likely(doc)) {
memset(err, 0, sizeof(yyjson_read_err));
} else {
/* RFC 8259: JSON text MUST be encoded using UTF-8 */
if (err->pos == 0 && err->code != YYJSON_READ_ERROR_MEMORY_ALLOCATION) {
if (is_utf8_bom(hdr)) err->msg = MSG_ERR_BOM;
else if (len >= 4 && is_utf32_bom(hdr)) err->msg = MSG_ERR_UTF32;
else if (len >= 2 && is_utf16_bom(hdr)) err->msg = MSG_ERR_UTF16;
}
if (!has_flg(INSITU)) alc.free(alc.ctx, hdr);
}
return doc;
#undef return_err
}
yyjson_doc *yyjson_read_file(const char *path,
yyjson_read_flag flg,
const yyjson_alc *alc_ptr,
yyjson_read_err *err) {
#define return_err(_code, _msg) do { \
err->pos = 0; \
err->msg = _msg; \
err->code = YYJSON_READ_ERROR_##_code; \
return NULL; \
} while (false)
yyjson_read_err tmp_err;
yyjson_doc *doc;
FILE *file;
if (!err) err = &tmp_err;
if (unlikely(!path)) return_err(INVALID_PARAMETER, "input path is NULL");
file = fopen_readonly(path);
if (unlikely(!file)) return_err(FILE_OPEN, MSG_FREAD);
doc = yyjson_read_fp(file, flg, alc_ptr, err);
fclose(file);
return doc;
#undef return_err
}
yyjson_doc *yyjson_read_fp(FILE *file,
yyjson_read_flag flg,
const yyjson_alc *alc_ptr,
yyjson_read_err *err) {
#define return_err(_code, _msg) do { \
err->pos = 0; \
err->msg = _msg; \
err->code = YYJSON_READ_ERROR_##_code; \
if (buf) alc.free(alc.ctx, buf); \
return NULL; \
} while (false)
yyjson_read_err tmp_err;
yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
yyjson_doc *doc;
long file_size = 0, file_pos;
void *buf = NULL;
usize buf_size = 0;
/* validate input parameters */
if (!err) err = &tmp_err;
if (dat_len >= sizeof(buf)) alc->free(alc->ctx, hdr);
return_err(cur, INVALID_NUMBER, msg);
}
if (dat_len >= sizeof(buf)) alc->free(alc->ctx, hdr);
if (yyjson_is_raw(val)) val->uni.str = dat;
return dat + (cur - hdr);
#else
if (!read_num(&cur, pre, flg, val, &msg)) {
return_err(cur, INVALID_NUMBER, msg);
}
return (const char *)cur;
#endif
#undef return_err
}
/*==============================================================================
* MARK: - Incremental JSON Reader (Public)
*============================================================================*/
#if !YYJSON_DISABLE_INCR_READER
/* labels within yyjson_incr_read() to resume incremental parsing */
#define LABEL_doc_begin 0
#define LABEL_arr_val_begin 1
#define LABEL_arr_val_end 2
#define LABEL_obj_key_begin 3
#define LABEL_obj_key_end 4
#define LABEL_obj_val_begin 5
#define LABEL_obj_val_end 6
#define LABEL_doc_end 7
/** State for incremental JSON reader, opaque in the API. */
struct yyjson_incr_state {
u32 label; /* current parser goto label */
yyjson_alc alc; /* allocator */
yyjson_read_flag flg; /* read flags */
u8 *hdr; /* JSON data header */
u8 *cur; /* current position in JSON data */
usize buf_len; /* total buffer length (without padding) */
usize hdr_len; /* value count used by yyjson_doc */
usize alc_len; /* value count allocated */
usize ctn_len; /* the number of elements in current container */
yyjson_val *val_hdr; /* the head of allocated values */
yyjson_val *val_end; /* the end of allocated values */
yyjson_val *val; /* current JSON value */
yyjson_val *ctn; /* current container */
u8 *str_con[2]; /* string parser incremental state */
};
yyjson_incr_state *yyjson_incr_new(char *buf, size_t buf_len,
yyjson_read_flag flg,
const yyjson_alc *alc_ptr) {
yyjson_incr_state *state = NULL;
yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
/* remove non-standard flags */
flg &= ~YYJSON_READ_JSON5;
flg &= ~YYJSON_READ_ALLOW_BOM;
flg &= ~YYJSON_READ_ALLOW_INVALID_UNICODE;
if (unlikely(!buf)) return NULL;
if (unlikely(buf_len >= USIZE_MAX - YYJSON_PADDING_SIZE)) return NULL;
state = (yyjson_incr_state *)alc.malloc(alc.ctx, sizeof(*state));
if (!state) return NULL;
memset(state, 0, sizeof(yyjson_incr_state));
state->alc = alc;
state->flg = flg;
state->buf_len = buf_len;
/* add 4-byte zero padding for input data if necessary */
if (has_flg(INSITU)) {
state->hdr = (u8 *)buf;
} else {
state->hdr = (u8 *)alc.malloc(alc.ctx, buf_len + YYJSON_PADDING_SIZE);
if (unlikely(!state->hdr)) {
alc.free(alc.ctx, state);
return NULL;
}
memcpy(state->hdr, buf, buf_len);
}
memset(state->hdr + buf_len, 0, YYJSON_PADDING_SIZE);
state->cur = state->hdr;
state->label = LABEL_doc_begin;
return state;
}
void yyjson_incr_free(yyjson_incr_state *state) {
if (state) {
yyjson_alc alc = state->alc;
memset(&state->alc, 0, sizeof(alc));
if (state->val_hdr) {
alc.free(alc.ctx, (void *)state->val_hdr);
}
if (state->hdr && !(state->flg & YYJSON_READ_INSITU)) {
alc.free(alc.ctx, state->hdr);
}
alc.free(alc.ctx, state);
}
}
yyjson_doc *yyjson_incr_read(yyjson_incr_state *state, size_t len,
yyjson_read_err *err) {
#define return_err_inv_param(_msg) do { \
err->pos = 0; \
err->msg = _msg; \
err->code = YYJSON_READ_ERROR_INVALID_PARAMETER; \
return NULL; \
} while (false)
#define return_err(_pos, _code, _msg) do { \
if (is_truncated_end(hdr, _pos, end, YYJSON_READ_ERROR_##_code, flg)) { \
goto unexpected_end; \
} else { \
err->pos = (usize)(_pos - hdr); \
err->code = YYJSON_READ_ERROR_##_code; \
err->msg = _msg; \
} \
return NULL; \
if (!val_hdr) {
hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
if (likely(char_is_ctn(*cur))) {
dat_len = has_flg(STOP_WHEN_DONE) ? 256 : state->buf_len;
alc_len = hdr_len +
(dat_len / YYJSON_READER_ESTIMATED_MINIFY_RATIO) + 4;
alc_len = yyjson_min(alc_len, alc_max);
} else {
alc_len = hdr_len + 1; /* single value */
}
val_hdr = (yyjson_val *)alc.malloc(alc.ctx,
alc_len * sizeof(yyjson_val));
if (unlikely(!val_hdr)) goto fail_alloc;
val_end = val_hdr + (alc_len - 2); /* padding for kv pair reading */
val = val_hdr + hdr_len;
ctn = val;
ctn_len = 0;
state->val_hdr = val_hdr;
state->val_end = val_end;
save_incr_state(doc_begin);
}
/* read json document */
if (*cur == '{') {
cur++;
ctn->tag = YYJSON_TYPE_OBJ;
ctn->uni.ofs = 0;
goto obj_key_begin;
}
if (*cur == '[') {
cur++;
ctn->tag = YYJSON_TYPE_ARR;
ctn->uni.ofs = 0;
goto arr_val_begin;
}
if (char_is_num(*cur)) {
if (likely(read_num(&cur, pre, flg, val, &msg))) goto doc_end;
goto fail_number;
}
if (*cur == '"') {
if (likely(read_str_con(&cur, end, flg, val, &msg, con))) goto doc_end;
goto fail_string;
}
if (*cur == 't') {
if (likely(read_true(&cur, val))) goto doc_end;
goto fail_literal_true;
}
if (*cur == 'f') {
if (likely(read_false(&cur, val))) goto doc_end;
goto fail_literal_false;
}
if (*cur == 'n') {
if (likely(read_null(&cur, val))) goto doc_end;
goto fail_literal_null;
}
msg = "unexpected character, expected a valid root value";
if (cur == hdr) {
/* RFC 8259: JSON text MUST be encoded using UTF-8 */
if (is_utf8_bom(hdr)) msg = MSG_ERR_BOM;
else if (len >= 4 && is_utf32_bom(hdr)) msg = MSG_ERR_UTF32;
else if (len >= 2 && is_utf16_bom(hdr)) msg = MSG_ERR_UTF16;
}
return_err(cur, UNEXPECTED_CHARACTER, msg);
arr_begin:
/* save current container */
ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
(ctn->tag & YYJSON_TAG_MASK);
/* create a new array value, save parent container offset */
val_incr();
val->tag = YYJSON_TYPE_ARR;
val->uni.ofs = (usize)((u8 *)val - (u8 *)ctn);
/* push the new array value as current container */
ctn = val;
ctn_len = 0;
arr_val_begin:
save_incr_state(arr_val_begin);
arr_val_continue:
if (*cur == '{') {
cur++;
goto obj_begin;
}
if (*cur == '[') {
cur++;
goto arr_begin;
}
if (char_is_num(*cur)) {
val_incr();
ctn_len++;
if (likely(read_num(&cur, pre, flg, val, &msg))) goto arr_val_maybe_end;
goto fail_number;
}
if (*cur == '"') {
val_incr();
ctn_len++;
if (likely(read_str_con(&cur, end, flg, val, &msg, con)))
goto arr_val_end;
goto fail_string;
}
if (*cur == 't') {
val_incr();
ctn_len++;
if (likely(read_true(&cur, val))) goto arr_val_end;
goto fail_literal_true;
}
if (*cur == 'f') {
val_incr();
ctn_len++;
if (likely(read_false(&cur, val))) goto arr_val_end;
goto fail_literal_false;
}
if (*cur == 'n') {
val_incr();
ctn_len++;
if (likely(read_null(&cur, val))) goto arr_val_end;
goto fail_literal_null;
( run in 0.579 second using v1.01-cache-2.11-cpan-39bf76dae61 )