mirror of
https://github.com/mpv-player/mpv
synced 2024-12-25 16:33:02 +00:00
json: add some non-standard extensions
Also clarify this and previously existing differences to standard JSON in ipc.rst.
This commit is contained in:
parent
76bff1a000
commit
d36b85cfdf
@ -74,6 +74,12 @@ some wrapper like .NET's NamedPipeClientStream.)
|
||||
Protocol
|
||||
--------
|
||||
|
||||
The protocol uses UTF-8-only JSON as defined by RFC-8259. Unlike standard JSON,
|
||||
"\u" escape sequences are not allowed to construct surrogate pairs. To avoid
|
||||
getting conflicts, encode all text characters including and above codepoint
|
||||
U+0020 as UTF-8. mpv might output broken UTF-8 in corner cases (see "UTF-8"
|
||||
section below).
|
||||
|
||||
Clients can execute commands on the player by sending JSON messages of the
|
||||
following form:
|
||||
|
||||
@ -266,4 +272,28 @@ sometimes sends invalid JSON. If that is a problem for the client application's
|
||||
parser, it should filter the raw data for invalid UTF-8 sequences and perform
|
||||
the desired replacement, before feeding the data to its JSON parser.
|
||||
|
||||
mpv will not attempt to construct invalid UTF-8 with broken escape sequences.
|
||||
mpv will not attempt to construct invalid UTF-8 with broken "\u" escape
|
||||
sequences. This includes surrogate pairs.
|
||||
|
||||
JSON extensions
|
||||
---------------
|
||||
|
||||
The following non-standard extensions are supported:
|
||||
|
||||
- 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)
|
||||
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
{ objkey = "value\x0A" }
|
||||
|
||||
Is equivalent to:
|
||||
|
||||
::
|
||||
|
||||
{ "objkey": "value\n" }
|
||||
|
36
misc/json.c
36
misc/json.c
@ -22,7 +22,12 @@
|
||||
* 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/rfc8259
|
||||
*
|
||||
@ -45,6 +50,7 @@
|
||||
|
||||
#include "common/common.h"
|
||||
#include "misc/bstr.h"
|
||||
#include "misc/ctype.h"
|
||||
|
||||
#include "json.h"
|
||||
|
||||
@ -72,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, '"'))
|
||||
@ -122,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);
|
||||
|
16
test/json.c
16
test/json.c
@ -45,14 +45,24 @@ static const struct entry entries[] = {
|
||||
{ "[1,2,3]", "[1,2,3]",
|
||||
NODE_ARRAY(NODE_INT64(1), NODE_INT64(2), NODE_INT64(3))},
|
||||
{ "[ ]", "[]", NODE_ARRAY()},
|
||||
{ "[1,2,]", .expect_fail = true},
|
||||
{ "[1,,2]", .expect_fail = true},
|
||||
{ "[,]", .expect_fail = true},
|
||||
{ TEXT({"a":1, "b":2}), TEXT({"a":1,"b":2}),
|
||||
NODE_MAP(L("a", "b"), L(NODE_INT64(1), NODE_INT64(2)))},
|
||||
{ "{ }", "{}", NODE_MAP(L(), L())},
|
||||
{ TEXT({"a":b}), .expect_fail = true},
|
||||
{ TEXT({a:"b"}), .expect_fail = true},
|
||||
{ TEXT({"a":1,}), .expect_fail = true},
|
||||
{ TEXT({1a:"b"}), .expect_fail = true},
|
||||
|
||||
// non-standard extensions
|
||||
{ "[1,2,]", "[1,2]", NODE_ARRAY(NODE_INT64(1), NODE_INT64(2))},
|
||||
{ TEXT({a:"b"}), TEXT({"a":"b"}),
|
||||
NODE_MAP(L("a"), L(NODE_STR("b")))},
|
||||
{ TEXT({a="b"}), TEXT({"a":"b"}),
|
||||
NODE_MAP(L("a"), L(NODE_STR("b")))},
|
||||
{ TEXT({a ="b"}), TEXT({"a":"b"}),
|
||||
NODE_MAP(L("a"), L(NODE_STR("b")))},
|
||||
{ TEXT({_a12="b"}), TEXT({"_a12":"b"}),
|
||||
NODE_MAP(L("_a12"), L(NODE_STR("b")))},
|
||||
};
|
||||
|
||||
#define MAX_DEPTH 10
|
||||
|
Loading…
Reference in New Issue
Block a user