diff --git a/misc/json.c b/misc/json.c index 4797fde4d0..9cc0730e4d 100644 --- a/misc/json.c +++ b/misc/json.c @@ -24,7 +24,7 @@ * * Does not support extensions like unquoted string literals. * - * Also see: http://tools.ietf.org/html/rfc4627 + * Also see: http://tools.ietf.org/html/rfc8259 * * JSON writer: * @@ -34,9 +34,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 @@ -218,6 +215,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 +233,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); diff --git a/test/json.c b/test/json.c index 74fd20d748..d624f61cca 100644 --- a/test/json.c +++ b/test/json.c @@ -40,7 +40,8 @@ static const struct entry entries[] = { { "abc", .expect_fail = true}, { " 123 ", "123", NODE_INT64(123)}, { "123.25", "123.250000", NODE_FLOAT(123.25)}, - { TEXT("a\n\\"), TEXT("a\u000a\u005c"), NODE_STR("a\n\\")}, + { TEXT("a\n\\\/\\\""), TEXT("a\n\\/\\\""), NODE_STR("a\n\\/\\\"")}, + { TEXT("a\u2c29"), TEXT("aⰩ"), NODE_STR("a\342\260\251")}, { "[1,2,3]", "[1,2,3]", NODE_ARRAY(NODE_INT64(1), NODE_INT64(2), NODE_INT64(3))}, { "[ ]", "[]", NODE_ARRAY()},