spa: add spa_json_begin_array/object and relaxed versions

Add spa_json_begin_array/object to replace
spa_json_init+spa_json_begin_array/object

This function is better because it does not waste a useless spa_json
structure as an iterator. The relaxed versions also error out when the
container is mismatched because parsing a mismatched container is not
going to give any results anyway.
This commit is contained in:
Wim Taymans 2024-09-13 13:09:54 +02:00
parent feccb882b6
commit cd81b5f39a
51 changed files with 401 additions and 452 deletions

View file

@ -565,19 +565,18 @@ static int parse_spa_libs(void *user_data, const char *location,
{
struct data *d = user_data;
struct pw_context *context = d->context;
struct spa_json it[2];
struct spa_json it[1];
char key[512], value[512];
int res;
spa_json_init(&it[0], str, len);
if (spa_json_enter_object(&it[0], &it[1]) < 0) {
if (spa_json_begin_object(&it[0], str, len) < 0) {
pw_log_error("config file error: context.spa-libs is not an "
"object in '%.*s'", (int)len, str);
return -EINVAL;
}
while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) {
if (spa_json_get_string(&it[1], value, sizeof(value)) > 0) {
while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) {
if (spa_json_get_string(&it[0], value, sizeof(value)) > 0) {
if ((res = pw_context_add_spa_lib(context, key, value)) < 0) {
pw_log_error("error adding spa-libs for '%s' in '%.*s': %s",
key, (int)len, str, spa_strerror(res));
@ -752,27 +751,26 @@ static int parse_modules(void *user_data, const char *location,
{
struct data *d = user_data;
struct pw_context *context = d->context;
struct spa_json it[4];
struct spa_json it[3];
char key[512];
int res = 0, r;
spa_autofree char *s = strndup(str, len);
spa_json_init(&it[0], s, len);
if (spa_json_enter_array(&it[0], &it[1]) < 0) {
if (spa_json_begin_array(&it[0], s, len) < 0) {
pw_log_error("context.modules is not an array in '%.*s'",
(int)len, str);
return -EINVAL;
}
while ((r = spa_json_enter_object(&it[1], &it[2])) > 0) {
while ((r = spa_json_enter_object(&it[0], &it[1])) > 0) {
char *name = NULL, *args = NULL, *flags = NULL;
bool have_match = true;
while (spa_json_get_string(&it[2], key, sizeof(key)) > 0) {
while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) {
const char *val;
int l;
if ((l = spa_json_next(&it[2], &val)) <= 0) {
if ((l = spa_json_next(&it[1], &val)) <= 0) {
pw_log_warn("malformed module: key '%s' has no "
"value in '%.*s'", key, (int)len, str);
break;
@ -783,13 +781,13 @@ static int parse_modules(void *user_data, const char *location,
spa_json_parse_stringn(val, l, name, l+1);
} else if (spa_streq(key, "args")) {
if (spa_json_is_container(val, l))
l = spa_json_container_len(&it[2], val, l);
l = spa_json_container_len(&it[1], val, l);
args = (char*)val;
spa_json_parse_stringn(val, l, args, l+1);
} else if (spa_streq(key, "flags")) {
if (spa_json_is_container(val, l))
l = spa_json_container_len(&it[2], val, l);
l = spa_json_container_len(&it[1], val, l);
flags = (char*)val;
spa_json_parse_stringn(val, l, flags, l+1);
} else if (spa_streq(key, "condition")) {
@ -798,8 +796,8 @@ static int parse_modules(void *user_data, const char *location,
(int)len, str);
break;
}
spa_json_enter(&it[2], &it[3]);
have_match = find_match(&it[3], &context->properties->dict, true);
spa_json_enter(&it[1], &it[2]);
have_match = find_match(&it[2], &context->properties->dict, true);
} else {
pw_log_warn("unknown module key '%s' in '%.*s'", key,
(int)len, str);
@ -862,26 +860,25 @@ static int parse_objects(void *user_data, const char *location,
{
struct data *d = user_data;
struct pw_context *context = d->context;
struct spa_json it[4];
struct spa_json it[3];
char key[512];
int res = 0, r;
spa_autofree char *s = strndup(str, len);
spa_json_init(&it[0], s, len);
if (spa_json_enter_array(&it[0], &it[1]) < 0) {
if (spa_json_begin_array(&it[0], s, len) < 0) {
pw_log_error("config file error: context.objects is not an array");
return -EINVAL;
}
while ((r = spa_json_enter_object(&it[1], &it[2])) > 0) {
while ((r = spa_json_enter_object(&it[0], &it[1])) > 0) {
char *factory = NULL, *args = NULL, *flags = NULL;
bool have_match = true;
while (spa_json_get_string(&it[2], key, sizeof(key)) > 0) {
while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) {
const char *val;
int l;
if ((l = spa_json_next(&it[2], &val)) <= 0) {
if ((l = spa_json_next(&it[1], &val)) <= 0) {
pw_log_warn("malformed object: key '%s' has no "
"value in '%.*s'", key, (int)len, str);
break;
@ -892,13 +889,13 @@ static int parse_objects(void *user_data, const char *location,
spa_json_parse_stringn(val, l, factory, l+1);
} else if (spa_streq(key, "args")) {
if (spa_json_is_container(val, l))
l = spa_json_container_len(&it[2], val, l);
l = spa_json_container_len(&it[1], val, l);
args = (char*)val;
spa_json_parse_stringn(val, l, args, l+1);
} else if (spa_streq(key, "flags")) {
if (spa_json_is_container(val, l))
l = spa_json_container_len(&it[2], val, l);
l = spa_json_container_len(&it[1], val, l);
flags = (char*)val;
spa_json_parse_stringn(val, l, flags, l+1);
@ -908,8 +905,8 @@ static int parse_objects(void *user_data, const char *location,
(int)len, str);
break;
}
spa_json_enter(&it[2], &it[3]);
have_match = find_match(&it[3], &context->properties->dict, true);
spa_json_enter(&it[1], &it[2]);
have_match = find_match(&it[2], &context->properties->dict, true);
} else {
pw_log_warn("unknown object key '%s' in '%.*s'", key,
(int)len, str);
@ -1046,29 +1043,28 @@ static int parse_exec(void *user_data, const char *location,
{
struct data *d = user_data;
struct pw_context *context = d->context;
struct spa_json it[4];
struct spa_json it[3];
char key[512];
int r, res = 0;
spa_autofree char *s = strndup(str, len);
spa_json_init(&it[0], s, len);
if (spa_json_enter_array(&it[0], &it[1]) < 0) {
if (spa_json_begin_array(&it[0], s, len) < 0) {
pw_log_error("config file error: context.exec is not an array in '%.*s'",
(int)len, str);
return -EINVAL;
}
while ((r = spa_json_enter_object(&it[1], &it[2])) > 0) {
while ((r = spa_json_enter_object(&it[0], &it[1])) > 0) {
char *path = NULL;
const char *args_val = "[]";
int args_len = 2;
bool have_match = true;
while (spa_json_get_string(&it[2], key, sizeof(key)) > 0) {
while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) {
const char *val;
int l;
if ((l = spa_json_next(&it[2], &val)) <= 0) {
if ((l = spa_json_next(&it[1], &val)) <= 0) {
pw_log_warn("malformed exec: key '%s' has no "
"value in '%.*s'", key, (int)len, str);
break;
@ -1079,7 +1075,7 @@ static int parse_exec(void *user_data, const char *location,
spa_json_parse_stringn(val, l, path, l+1);
} else if (spa_streq(key, "args")) {
if (spa_json_is_container(val, l))
l = spa_json_container_len(&it[2], val, l);
l = spa_json_container_len(&it[1], val, l);
args_val = val;
args_len = l;
} else if (spa_streq(key, "condition")) {
@ -1088,8 +1084,8 @@ static int parse_exec(void *user_data, const char *location,
(int)len, str);
goto next;
}
spa_json_enter(&it[2], &it[3]);
have_match = find_match(&it[3], &context->properties->dict, true);
spa_json_enter(&it[1], &it[2]);
have_match = find_match(&it[2], &context->properties->dict, true);
} else {
pw_log_warn("unknown exec key '%s' in '%.*s'", key,
(int)len, str);
@ -1307,31 +1303,30 @@ int pw_conf_match_rules(const char *str, size_t len, const char *location,
void *data)
{
const char *val;
struct spa_json it[4], actions;
struct spa_json it[3], actions;
int r;
spa_json_init(&it[0], str, len);
if (spa_json_enter_array(&it[0], &it[1]) < 0) {
if (spa_json_begin_array(&it[0], str, len) < 0) {
pw_log_warn("expect array of match rules in: '%.*s'", (int)len, str);
return 0;
}
while ((r = spa_json_enter_object(&it[1], &it[2])) > 0) {
while ((r = spa_json_enter_object(&it[0], &it[1])) > 0) {
char key[64];
bool have_match = false, have_actions = false;
while (spa_json_get_string(&it[2], key, sizeof(key)) > 0) {
while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) {
if (spa_streq(key, "matches")) {
if (spa_json_enter_array(&it[2], &it[3]) < 0) {
if (spa_json_enter_array(&it[1], &it[2]) < 0) {
pw_log_warn("expected array as matches in '%.*s'",
(int)len, str);
break;
}
have_match = find_match(&it[3], props, false);
have_match = find_match(&it[2], props, false);
}
else if (spa_streq(key, "actions")) {
if (spa_json_enter_object(&it[2], &actions) > 0)
if (spa_json_enter_object(&it[1], &actions) > 0)
have_actions = true;
else
pw_log_warn("expected object as match actions in '%.*s'",
@ -1339,7 +1334,7 @@ int pw_conf_match_rules(const char *str, size_t len, const char *location,
}
else {
pw_log_warn("unknown match key '%s'", key);
if (spa_json_next(&it[2], &val) <= 0) {
if (spa_json_next(&it[1], &val) <= 0) {
pw_log_warn("malformed match rule: key '%s' has "
"no value in '%.*s'", key, (int)len, str);
break;

View file

@ -204,19 +204,18 @@ static int setup_data_loops(struct impl *impl)
lib_name = pw_properties_get(this->properties, "context.data-loop." PW_KEY_LIBRARY_NAME_SYSTEM);
if ((str = pw_properties_get(this->properties, "context.data-loops")) != NULL) {
struct spa_json it[4];
struct spa_json it[2];
char key[512];
int r, len = strlen(str);
spa_autofree char *s = strndup(str, len);
i = 0;
spa_json_init(&it[0], s, len);
if (spa_json_enter_array(&it[0], &it[1]) < 0) {
if (spa_json_begin_array(&it[0], s, len) < 0) {
pw_log_error("context.data-loops is not an array in '%s'", str);
res = -EINVAL;
goto exit;
}
while ((r = spa_json_enter_object(&it[1], &it[2])) > 0) {
while ((r = spa_json_enter_object(&it[0], &it[1])) > 0) {
char *props = NULL;
if (i >= MAX_LOOPS) {
@ -229,17 +228,17 @@ static int setup_data_loops(struct impl *impl)
pw_properties_update(pr, &this->properties->dict);
pw_properties_set(pr, PW_KEY_LIBRARY_NAME_SYSTEM, lib_name);
while (spa_json_get_string(&it[2], key, sizeof(key)) > 0) {
while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) {
const char *val;
int l;
if ((l = spa_json_next(&it[2], &val)) <= 0) {
if ((l = spa_json_next(&it[1], &val)) <= 0) {
pw_log_warn("malformed data-loop: key '%s' has no "
"value in '%.*s'", key, (int)len, str);
break;
}
if (spa_json_is_container(val, l))
l = spa_json_container_len(&it[2], val, l);
l = spa_json_container_len(&it[1], val, l);
props = (char*)val;
spa_json_parse_stringn(val, l, props, l+1);

View file

@ -1282,20 +1282,18 @@ int pw_impl_port_add(struct pw_impl_port *port, struct pw_impl_node *node)
channel_names = pw_properties_get(nprops, PW_KEY_NODE_CHANNELNAMES);
if (channel_names != NULL) {
struct spa_json it[2];
struct spa_json it[1];
char v[256];
uint32_t i;
spa_json_init(&it[0], channel_names, strlen(channel_names));
if (spa_json_enter_array(&it[0], &it[1]) <= 0)
spa_json_init(&it[1], channel_names, strlen(channel_names));
if (spa_json_begin_array_relax(&it[0], channel_names, strlen(channel_names)) > 0) {
for (i = 0; i < port->port_id + 1; i++)
if (spa_json_get_string(&it[0], v, sizeof(v)) <= 0)
break;
for (i = 0; i < port->port_id + 1; i++)
if (spa_json_get_string(&it[1], v, sizeof(v)) <= 0)
break;
if (i == port->port_id + 1 && strlen(v) > 0)
snprintf(position, sizeof(position), "%s", v);
if (i == port->port_id + 1 && strlen(v) > 0)
snprintf(position, sizeof(position), "%s", v);
}
}
if (pw_properties_get(port->properties, PW_KEY_PORT_NAME) == NULL) {

View file

@ -210,7 +210,7 @@ exit_noupdate:
static int update_string(struct pw_properties *props, const char *str, size_t size,
int *count, struct spa_error_location *loc)
{
struct spa_json it[2];
struct spa_json it[1];
char key[1024];
struct spa_error_location el;
bool err;
@ -220,29 +220,28 @@ static int update_string(struct pw_properties *props, const char *str, size_t si
if (props)
properties_init(&changes, 16);
spa_json_init(&it[0], str, size);
if (spa_json_enter_object(&it[0], &it[1]) <= 0)
spa_json_init(&it[1], str, size);
if ((res = spa_json_begin_object_relax(&it[0], str, size)) <= 0)
return res;
while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) {
while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) {
int len;
const char *value;
char *val = NULL;
if ((len = spa_json_next(&it[1], &value)) <= 0)
if ((len = spa_json_next(&it[0], &value)) <= 0)
break;
if (spa_json_is_null(value, len))
val = NULL;
else {
if (spa_json_is_container(value, len))
len = spa_json_container_len(&it[1], value, len);
len = spa_json_container_len(&it[0], value, len);
if (len <= 0)
break;
if (props) {
if ((val = malloc(len+1)) == NULL) {
it[1].state = SPA_JSON_ERROR_FLAG;
it[0].state = SPA_JSON_ERROR_FLAG;
break;
}
spa_json_parse_stringn(value, len, val, len+1);
@ -257,12 +256,12 @@ static int update_string(struct pw_properties *props, const char *str, size_t si
}
/* item changed or added, apply changes later */
if ((errno = -add_item(&changes, key, false, val, true) < 0)) {
it[1].state = SPA_JSON_ERROR_FLAG;
it[0].state = SPA_JSON_ERROR_FLAG;
break;
}
}
}
if ((err = spa_json_get_error(&it[1], str, &el))) {
if ((err = spa_json_get_error(&it[0], str, &el))) {
if (loc == NULL)
spa_debug_log_error_location(pw_log_get(), SPA_LOG_LEVEL_WARN,
&el, "error parsing more than %d properties: %s",

View file

@ -90,14 +90,13 @@ static bool uint32_array_contains(uint32_t *vals, uint32_t n_vals, uint32_t val)
static uint32_t parse_uint32_array(const char *str, uint32_t *vals, uint32_t max, uint32_t def)
{
uint32_t count = 0, r;
struct spa_json it[2];
struct spa_json it[1];
char v[256];
spa_json_init(&it[0], str, strlen(str));
if (spa_json_enter_array(&it[0], &it[1]) <= 0)
spa_json_init(&it[1], str, strlen(str));
if (spa_json_begin_array_relax(&it[0], str, strlen(str)) <= 0)
return 0;
while (spa_json_get_string(&it[1], v, sizeof(v)) > 0 &&
while (spa_json_get_string(&it[0], v, sizeof(v)) > 0 &&
count < max) {
if (spa_atou32(v, &r, 0))
vals[count++] = r;

View file

@ -27,15 +27,14 @@ do { \
static int parse_affinity(const char *affinity, cpu_set_t *set)
{
struct spa_json it[2];
struct spa_json it[1];
int v;
CPU_ZERO(set);
spa_json_init(&it[0], affinity, strlen(affinity));
if (spa_json_enter_array(&it[0], &it[1]) <= 0)
spa_json_init(&it[1], affinity, strlen(affinity));
if (spa_json_begin_array_relax(&it[0], affinity, strlen(affinity)) <= 0)
return 0;
while (spa_json_get_int(&it[1], &v) > 0) {
while (spa_json_get_int(&it[0], &v) > 0) {
if (v >= 0 && v < CPU_SETSIZE)
CPU_SET(v, set);
}

View file

@ -130,7 +130,7 @@ SPA_EXPORT
char **pw_strv_parse(const char *val, size_t len, int max_tokens, int *n_tokens)
{
struct pw_array arr;
struct spa_json it[2];
struct spa_json it[1];
int n = 0, l, res;
const char *value;
struct spa_error_location el;
@ -140,11 +140,10 @@ char **pw_strv_parse(const char *val, size_t len, int max_tokens, int *n_tokens)
pw_array_init(&arr, sizeof(char*) * 16);
spa_json_init(&it[0], val, len);
if (spa_json_enter_array(&it[0], &it[1]) <= 0)
spa_json_init(&it[1], val, len);
if (spa_json_begin_array_relax(&it[0], val, len) <= 0)
return NULL;
while ((l = spa_json_next(&it[1], &value)) > 0 && n + 1 < max_tokens) {
while ((l = spa_json_next(&it[0], &value)) > 0 && n + 1 < max_tokens) {
char *s;
if ((s = malloc(l+1)) == NULL)
@ -161,7 +160,7 @@ char **pw_strv_parse(const char *val, size_t len, int max_tokens, int *n_tokens)
if ((res = pw_array_add_ptr(&arr, NULL)) < 0)
goto error;
done:
if ((res = spa_json_get_error(&it[1], val, &el))) {
if ((res = spa_json_get_error(&it[0], val, &el))) {
spa_debug_log_error_location(pw_log_get(), SPA_LOG_LEVEL_WARN,
&el, "error parsing strv: %s", el.reason);
@ -179,7 +178,7 @@ done:
error_errno:
res = -errno;
error:
it[1].state = SPA_JSON_ERROR_FLAG;
it[0].state = SPA_JSON_ERROR_FLAG;
errno = -res;
goto done;
}