diff options
Diffstat (limited to 'misc/json.c')
-rw-r--r-- | misc/json.c | 59 |
1 files changed, 51 insertions, 8 deletions
diff --git a/misc/json.c b/misc/json.c index 4797fde4d0..d1b2afddb6 100644 --- a/misc/json.c +++ b/misc/json.c @@ -22,9 +22,14 @@ * doesn't verify what's passed to strtod(), and also prefers parsing numbers * as integers with stroll() if possible). * - * Does not support extensions like unquoted string literals. + * It has some non-standard extensions which shouldn't conflict with JSON: + * - a list or object item can have a trailing "," + * - object syntax accepts "=" in addition of ":" + * - object keys can be unquoted, if they start with a character in [A-Za-z_] + * and contain only characters in [A-Za-z0-9_] + * - byte escapes with "\xAB" are allowed (with AB being a 2 digit hex number) * - * Also see: http://tools.ietf.org/html/rfc4627 + * Also see: http://tools.ietf.org/html/rfc8259 * * JSON writer: * @@ -34,9 +39,6 @@ * to deal with somehow: either by using byte-strings for JSON, or by running * a "fixup" pass on the input data. The latter could for example change * invalid UTF-8 sequences to replacement characters. - * - * Currently, will insert \u literals for characters 0-31, '"', '\', and write - * everything else literally. */ #include <stdlib.h> @@ -48,6 +50,7 @@ #include "common/common.h" #include "misc/bstr.h" +#include "misc/ctype.h" #include "json.h" @@ -75,6 +78,24 @@ void json_skip_whitespace(char **src) eat_ws(src); } +static int read_id(void *ta_parent, struct mpv_node *dst, char **src) +{ + char *start = *src; + if (!mp_isalpha(**src) && **src != '_') + return -1; + while (mp_isalnum(**src) || **src == '_') + *src += 1; + if (**src == ' ') { + **src = '\0'; // we're allowed to mutate it => can avoid the strndup + *src += 1; + } else { + start = talloc_strndup(ta_parent, start, *src - start); + } + dst->format = MPV_FORMAT_STRING; + dst->u.string = start; + return 0; +} + static int read_str(void *ta_parent, struct mpv_node *dst, char **src) { if (!eat_c(src, '"')) @@ -125,12 +146,18 @@ static int read_sub(void *ta_parent, struct mpv_node *dst, char **src, if (list->num > 0 && !eat_c(src, ',')) return -1; // missing ',' eat_ws(src); + // non-standard extension: allow a trailing "," + if (eat_c(src, term)) + break; if (is_obj) { struct mpv_node keynode; - if (read_str(list, &keynode, src) < 0) + // non-standard extension: allow unquoted strings as keys + if (read_id(list, &keynode, src) < 0 && + read_str(list, &keynode, src) < 0) return -1; // key is not a string eat_ws(src); - if (!eat_c(src, ':')) + // non-standard extension: allow "=" instead of ":" + if (!eat_c(src, ':') && !eat_c(src, '=')) return -1; // ':' missing eat_ws(src); MP_TARRAY_GROW(list, list->keys, list->num); @@ -218,6 +245,14 @@ int json_parse(void *ta_parent, struct mpv_node *dst, char **src, int max_depth) #define APPEND(b, s) bstr_xappend(NULL, (b), bstr0(s)) +static const char special_escape[] = { + ['\b'] = 'b', + ['\f'] = 'f', + ['\n'] = 'n', + ['\r'] = 'r', + ['\t'] = 't', +}; + static void write_json_str(bstr *b, unsigned char *str) { APPEND(b, "\""); @@ -228,7 +263,15 @@ static void write_json_str(bstr *b, unsigned char *str) if (!cur[0]) break; bstr_xappend(NULL, b, (bstr){str, cur - str}); - bstr_xappend_asprintf(NULL, b, "\\u%04x", (unsigned char)cur[0]); + if (cur[0] == '\"') { + bstr_xappend(NULL, b, (bstr){"\\\"", 2}); + } else if (cur[0] == '\\') { + bstr_xappend(NULL, b, (bstr){"\\\\", 2}); + } else if (cur[0] < sizeof(special_escape) && special_escape[cur[0]]) { + bstr_xappend_asprintf(NULL, b, "\\%c", special_escape[cur[0]]); + } else { + bstr_xappend_asprintf(NULL, b, "\\u%04x", (unsigned char)cur[0]); + } str = cur + 1; } APPEND(b, str); |