diff --git a/src/json.c b/src/json.c index 3acee050..deef49ff 100644 --- a/src/json.c +++ b/src/json.c @@ -1,7 +1,7 @@ /* vim: set et ts=3 sw=3 sts=3 ft=c: * - * Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved. - * https://github.com/udp/json-parser + * Copyright (C) 2012-2021 the json-parser authors All rights reserved. + * https://github.com/json-parser/json-parser * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,36 +29,49 @@ #include "json.h" -#define UNUSED(x) ( (void) x ) - #ifdef _MSC_VER #ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #endif +#endif + +#include +#include +#include +#include +#include +#include + +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + /* C99 might give us uintptr_t and UINTPTR_MAX but they also might not be provided */ #include #endif -const struct _json_value json_value_none; +#ifndef JSON_INT_T_OVERRIDDEN + #if defined(_MSC_VER) + /* https://docs.microsoft.com/en-us/cpp/cpp/data-type-ranges */ + #define JSON_INT_MAX 9223372036854775807LL + #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + /* C99 */ + #define JSON_INT_MAX INT_FAST64_MAX + #else + /* C89 */ + #include + #define JSON_INT_MAX LONG_MAX + #endif +#endif -#include -#include -#include -#include +#ifndef JSON_INT_MAX +#define JSON_INT_MAX (json_int_t)(((unsigned json_int_t)(-1)) / (unsigned json_int_t)2); +#endif typedef unsigned int json_uchar; -/* There has to be a better way to do this */ -static const json_int_t JSON_INT_MAX = sizeof(json_int_t) == 1 - ? INT8_MAX - : (sizeof(json_int_t) == 2 - ? INT16_MAX - : (sizeof(json_int_t) == 4 - ? INT32_MAX - : INT64_MAX)); +const struct _json_value json_value_none; static unsigned char hex_value (json_char c) { - if (isdigit(c)) + if (isdigit((unsigned char)c)) return c - '0'; switch (c) { @@ -79,10 +92,7 @@ static int would_overflow (json_int_t value, json_char b) typedef struct { - unsigned long used_memory; - - unsigned int uint_max; - unsigned long ulong_max; + size_t used_memory; json_settings settings; int first_pass; @@ -94,19 +104,19 @@ typedef struct static void * default_alloc (size_t size, int zero, void * user_data) { - UNUSED(user_data); - return zero ? calloc (1, size) : malloc (size); + (void)user_data; /* ignore unused-parameter warn */ + return zero ? calloc (1, size) : malloc (size); } static void default_free (void * ptr, void * user_data) { - UNUSED(user_data); - free (ptr); + (void)user_data; /* ignore unused-parameter warn */ + free (ptr); } -static void * json_alloc (json_state * state, unsigned long size, int zero) +static void * json_alloc (json_state * state, size_t size, int zero) { - if ((state->ulong_max - state->used_memory) < size) + if ((ULONG_MAX - 8 - state->used_memory) < size) return 0; if (state->settings.max_memory @@ -123,7 +133,7 @@ static int new_value (json_state * state, json_type type) { json_value * value; - int values_size; + size_t values_size; if (!state->first_pass) { @@ -157,14 +167,16 @@ static int new_value (json_state * state, values_size = sizeof (*value->u.object.values) * value->u.object.length; if (! (value->u.object.values = (json_object_entry *) json_alloc - (state, values_size + ((unsigned long) value->u.object.values), 0)) ) + #ifdef UINTPTR_MAX + (state, values_size + ((uintptr_t) value->u.object.values), 0)) ) + #else + (state, values_size + ((size_t) value->u.object.values), 0)) ) + #endif { return 0; } - char *s = (char *) value->u.object.values; - s += values_size; - value->_reserved.object_mem = s; + value->_reserved.object_mem = (void *) (((char *) value->u.object.values) + values_size); value->u.object.length = 0; break; @@ -213,8 +225,8 @@ static int new_value (json_state * state, } #define whitespace \ - case '\n': ++ state.cur_line; state.cur_col = 0; /* FALLTHRU */ \ - case ' ': case '\t': case '\r' + case '\n': ++ state.cur_line; state.cur_col = 0; /* FALLTHRU */ \ + case ' ': /* FALLTHRU */ case '\t': /* FALLTHRU */ case '\r' #define string_add(b) \ do { if (!state.first_pass) string [string_length] = b; ++ string_length; } while (0); @@ -245,13 +257,13 @@ json_value * json_parse_ex (json_settings * settings, size_t length, char * error_buf) { - json_char error [json_error_max]; + char error [json_error_max]; const json_char * end; json_value * top, * root, * alloc = 0; json_state state = { 0 }; - long flags; - double num_digits = 0, num_e = 0; - double num_fraction = 0; + long flags = 0; + int num_digits = 0; + double num_e = 0, num_fraction = 0; /* Skip UTF-8 BOM */ @@ -274,12 +286,6 @@ json_value * json_parse_ex (json_settings * settings, if (!state.settings.mem_free) state.settings.mem_free = default_free; - memset (&state.uint_max, 0xFF, sizeof (state.uint_max)); - memset (&state.ulong_max, 0xFF, sizeof (state.ulong_max)); - - state.uint_max -= 8; /* limit of how much can be added before next check */ - state.ulong_max -= 8; - for (state.first_pass = 1; state.first_pass >= 0; -- state.first_pass) { json_uchar uchar; @@ -299,11 +305,11 @@ json_value * json_parse_ex (json_settings * settings, if (flags & flag_string) { if (!b) - { snprintf (error, sizeof(error), "Unexpected EOF in string (at %u:%u)", line_and_col); + { sprintf (error, "%u:%u: Unexpected EOF in string", line_and_col); goto e_failed; } - if (string_length > state.uint_max) + if (string_length > UINT_MAX - 8) goto e_overflow; if (flags & flag_escaped) @@ -325,7 +331,7 @@ json_value * json_parse_ex (json_settings * settings, (uc_b3 = hex_value (*++ state.ptr)) == 0xFF || (uc_b4 = hex_value (*++ state.ptr)) == 0xFF) { - snprintf (error, sizeof(error), "Invalid character value `%c` (at %u:%u)", b, line_and_col); + sprintf (error, "%u:%u: Invalid character value `%c`", line_and_col, b); goto e_failed; } @@ -342,7 +348,7 @@ json_value * json_parse_ex (json_settings * settings, (uc_b3 = hex_value (*++ state.ptr)) == 0xFF || (uc_b4 = hex_value (*++ state.ptr)) == 0xFF) { - snprintf (error, sizeof(error), "Invalid character value `%c` (at %u:%u)", b, line_and_col); + sprintf (error, "%u:%u: Invalid character value `%c`", line_and_col, b); goto e_failed; } @@ -426,11 +432,12 @@ json_value * json_parse_ex (json_settings * settings, case json_object: - if (state.first_pass) { - char *s = (char *) top->u.object.values; - s += string_length+1; - top->u.object.values = (void *) s; - } else { + if (state.first_pass) { + json_char **chars = (json_char **) &top->u.object.values; + chars[0] += string_length + 1; + } + else + { top->u.object.values [top->u.object.length].name = (json_char *) top->_reserved.object_mem; @@ -472,7 +479,7 @@ json_value * json_parse_ex (json_settings * settings, if (flags & flag_block_comment) { if (!b) - { snprintf (error, sizeof(error), "%u:%u: Unexpected EOF in block comment", line_and_col); + { sprintf (error, "%u:%u: Unexpected EOF in block comment", line_and_col); goto e_failed; } @@ -488,12 +495,12 @@ json_value * json_parse_ex (json_settings * settings, else if (b == '/') { if (! (flags & (flag_seek_value | flag_done)) && top->type != json_object) - { snprintf (error, sizeof(error), "%u:%u: Comment not allowed here", line_and_col); + { sprintf (error, "%u:%u: Comment not allowed here", line_and_col); goto e_failed; } if (++ state.ptr == end) - { snprintf (error, sizeof(error), "%u:%u: EOF unexpected", line_and_col); + { sprintf (error, "%u:%u: EOF unexpected", line_and_col); goto e_failed; } @@ -508,7 +515,7 @@ json_value * json_parse_ex (json_settings * settings, continue; default: - snprintf (error, sizeof(error), "%u:%u: Unexpected `%c` in comment opening sequence", line_and_col, b); + sprintf (error, "%u:%u: Unexpected `%c` in comment opening sequence", line_and_col, b); goto e_failed; }; } @@ -526,8 +533,8 @@ json_value * json_parse_ex (json_settings * settings, default: - snprintf (error, sizeof(error), "%u:%u: Trailing garbage: `%c`", - state.cur_line, state.cur_col, b); + sprintf (error, "%u:%u: Trailing garbage: `%c`", + line_and_col, b); goto e_failed; }; @@ -545,7 +552,7 @@ json_value * json_parse_ex (json_settings * settings, if (top && top->type == json_array) flags = (flags & ~ (flag_need_comma | flag_seek_value)) | flag_next; else - { snprintf (error, sizeof(error), "%u:%u: Unexpected ]", line_and_col); + { sprintf (error, "%u:%u: Unexpected `]`", line_and_col); goto e_failed; } @@ -561,8 +568,8 @@ json_value * json_parse_ex (json_settings * settings, } else { - snprintf (error, sizeof(error), "%u:%u: Expected , before %c", - state.cur_line, state.cur_col, b); + sprintf (error, "%u:%u: Expected `,` before `%c`", + line_and_col, b); goto e_failed; } @@ -576,8 +583,8 @@ json_value * json_parse_ex (json_settings * settings, } else { - snprintf (error, sizeof(error), "%u:%u: Expected : before %c", - state.cur_line, state.cur_col, b); + sprintf (error, "%u:%u: Expected `:` before `%c`", + line_and_col, b); goto e_failed; } @@ -616,7 +623,7 @@ json_value * json_parse_ex (json_settings * settings, case 't': - if ((end - state.ptr) < 3 || *(++ state.ptr) != 'r' || + if ((end - state.ptr) <= 3 || *(++ state.ptr) != 'r' || *(++ state.ptr) != 'u' || *(++ state.ptr) != 'e') { goto e_unknown_value; @@ -632,7 +639,7 @@ json_value * json_parse_ex (json_settings * settings, case 'f': - if ((end - state.ptr) < 4 || *(++ state.ptr) != 'a' || + if ((end - state.ptr) <= 4 || *(++ state.ptr) != 'a' || *(++ state.ptr) != 'l' || *(++ state.ptr) != 's' || *(++ state.ptr) != 'e') { @@ -647,7 +654,7 @@ json_value * json_parse_ex (json_settings * settings, case 'n': - if ((end - state.ptr) < 3 || *(++ state.ptr) != 'u' || + if ((end - state.ptr) <= 3 || *(++ state.ptr) != 'u' || *(++ state.ptr) != 'l' || *(++ state.ptr) != 'l') { goto e_unknown_value; @@ -661,14 +668,14 @@ json_value * json_parse_ex (json_settings * settings, default: - if (isdigit (b) || b == '-') + if (isdigit ((unsigned char) b) || b == '-') { if (!new_value (&state, &top, &root, &alloc, json_integer)) goto e_alloc_failure; if (!state.first_pass) { - while (isdigit (b) || b == '+' || b == '-' + while (isdigit ((unsigned char) b) || b == '+' || b == '-' || b == 'e' || b == 'E' || b == '.') { if ( (++ state.ptr) == end) @@ -702,7 +709,7 @@ json_value * json_parse_ex (json_settings * settings, continue; } else - { snprintf (error, sizeof(error), "%u:%u: Unexpected %c when seeking value", line_and_col, b); + { sprintf (error, "%u:%u: Unexpected `%c` when seeking value", line_and_col, b); goto e_failed; } }; @@ -722,7 +729,7 @@ json_value * json_parse_ex (json_settings * settings, case '"': if (flags & flag_need_comma) - { snprintf (error, sizeof(error), "%u:%u: Expected , before \"", line_and_col); + { sprintf (error, "%u:%u: Expected `,` before `\"`", line_and_col); goto e_failed; } @@ -744,10 +751,10 @@ json_value * json_parse_ex (json_settings * settings, { flags &= ~ flag_need_comma; break; - } - /* FALLTHROUGH */ + } /* FALLTHRU */ + default: - snprintf (error, sizeof(error), "%u:%u: Unexpected `%c` in object", line_and_col, b); + sprintf (error, "%u:%u: Unexpected `%c` in object", line_and_col, b); goto e_failed; }; @@ -756,7 +763,7 @@ json_value * json_parse_ex (json_settings * settings, case json_integer: case json_double: - if (isdigit (b)) + if (isdigit ((unsigned char)b)) { ++ num_digits; @@ -765,7 +772,7 @@ json_value * json_parse_ex (json_settings * settings, if (! (flags & flag_num_e)) { if (flags & flag_num_zero) - { snprintf (error, sizeof(error), "%u:%u: Unexpected `0` before `%c`", line_and_col, b); + { sprintf (error, "%u:%u: Unexpected `0` before `%c`", line_and_col, b); goto e_failed; } @@ -780,10 +787,12 @@ json_value * json_parse_ex (json_settings * settings, } if (would_overflow(top->u.integer, b)) - { -- num_digits; + { + json_int_t integer = top->u.integer; + -- num_digits; -- state.ptr; top->type = json_double; - top->u.dbl = (double)top->u.integer; + top->u.dbl = (double)integer; continue; } @@ -813,13 +822,15 @@ json_value * json_parse_ex (json_settings * settings, } else if (b == '.' && top->type == json_integer) { + json_int_t integer = top->u.integer; + if (!num_digits) - { snprintf (error, sizeof(error), "%u:%u: Expected digit before `.`", line_and_col); + { sprintf (error, "%u:%u: Expected digit before `.`", line_and_col); goto e_failed; } top->type = json_double; - top->u.dbl = (double) top->u.integer; + top->u.dbl = (double) integer; flags |= flag_num_got_decimal; num_digits = 0; @@ -831,7 +842,7 @@ json_value * json_parse_ex (json_settings * settings, if (top->type == json_double) { if (!num_digits) - { snprintf (error, sizeof(error), "%u:%u: Expected digit after `.`", line_and_col); + { sprintf (error, "%u:%u: Expected digit after `.`", line_and_col); goto e_failed; } @@ -844,8 +855,9 @@ json_value * json_parse_ex (json_settings * settings, if (top->type == json_integer) { + json_int_t integer = top->u.integer; top->type = json_double; - top->u.dbl = (double) top->u.integer; + top->u.dbl = (double) integer; } num_digits = 0; @@ -857,11 +869,11 @@ json_value * json_parse_ex (json_settings * settings, else { if (!num_digits) - { snprintf (error, sizeof(error), "%u:%u: Expected digit after `e`", line_and_col); + { sprintf (error, "%u:%u: Expected digit after `e`", line_and_col); goto e_failed; } - top->u.dbl *= pow (10.0, ((flags & flag_num_e_negative) ? - num_e : num_e)); + top->u.dbl *= pow (10.0, (flags & flag_num_e_negative ? - num_e : num_e)); } if (flags & flag_num_negative) @@ -926,7 +938,7 @@ json_value * json_parse_ex (json_settings * settings, }; } - if ( (++ top->parent->u.array.length) > state.uint_max) + if ( (++ top->parent->u.array.length) > UINT_MAX - 8) goto e_overflow; top = top->parent; @@ -942,7 +954,7 @@ json_value * json_parse_ex (json_settings * settings, e_unknown_value: - snprintf (error, sizeof(error), "%u:%u: Unknown value", line_and_col); + sprintf (error, "%u:%u: Unknown value", line_and_col); goto e_failed; e_alloc_failure: @@ -952,7 +964,7 @@ e_alloc_failure: e_overflow: - snprintf (error, sizeof(error), "%u:%u: Too long (caught overflow)", line_and_col); + sprintf (error, "%u:%u: Too long (caught overflow)", line_and_col); goto e_failed; e_failed: diff --git a/src/json.h b/src/json.h index 4305ce6f..1f643161 100644 --- a/src/json.h +++ b/src/json.h @@ -1,7 +1,8 @@ + /* vim: set et ts=3 sw=3 sts=3 ft=c: * - * Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved. - * https://github.com/udp/json-parser + * Copyright (C) 2012-2021 the json-parser authors All rights reserved. + * https://github.com/json-parser/json-parser * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,15 +36,22 @@ #endif #ifndef json_int_t - #ifndef _MSC_VER - #include - #define json_int_t int64_t - #else + #undef JSON_INT_T_OVERRIDDEN + #if defined(_MSC_VER) #define json_int_t __int64 + #elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || (defined(__cplusplus) && __cplusplus >= 201103L) + /* C99 and C++11 */ + #include + #define json_int_t int_fast64_t + #else + /* C89 */ + #define json_int_t long #endif +#else + #define JSON_INT_T_OVERRIDDEN 1 #endif -#include +#include #ifdef __cplusplus @@ -56,7 +64,7 @@ typedef struct { - unsigned long max_memory; + unsigned long max_memory; /* should be size_t, but would modify the API */ int settings; /* Custom allocator support (leave null to use malloc/free) @@ -122,11 +130,11 @@ typedef struct _json_value json_object_entry * values; - #if defined(__cplusplus) && __cplusplus >= 201103L - decltype(values) begin () const + #if defined(__cplusplus) + json_object_entry * begin () const { return values; } - decltype(values) end () const + json_object_entry * end () const { return values + length; } #endif @@ -138,11 +146,11 @@ typedef struct _json_value unsigned int length; struct _json_value ** values; - #if defined(__cplusplus) && __cplusplus >= 201103L - decltype(values) begin () const + #if defined(__cplusplus) + _json_value ** begin () const { return values; } - decltype(values) end () const + _json_value ** end () const { return values + length; } #endif