From ce390d5b22c4777f1898ee431f2c6daa1605f24c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 13 Sep 2024 16:26:36 +0200 Subject: [PATCH] spa: add spa_json_object_next This gets the next key and value from an object. This function is better because it will skip key/value pairs that don't fit in the array to hold the key. The previous code patter would stop parsing the object as soon as a key larger than the available space was found. --- pipewire-alsa/alsa-plugins/ctl_pipewire.c | 15 ++-- pipewire-alsa/alsa-plugins/pcm_pipewire.c | 4 +- pipewire-jack/src/pipewire-jack.c | 15 ++-- spa/include/spa/utils/json-pod.h | 4 +- spa/include/spa/utils/json.h | 19 ++++- spa/plugins/audioconvert/audioadapter.c | 9 ++- spa/plugins/bluez5/quirks.c | 24 +++--- spa/tools/spa-json-dump.c | 4 +- src/modules/module-access.c | 9 +-- src/modules/module-avb/adp.c | 9 +-- src/modules/module-avb/maap.c | 11 +-- src/modules/module-filter-chain.c | 77 +++++++++---------- .../module-filter-chain/builtin_plugin.c | 57 ++++++-------- src/modules/module-filter-chain/sofa_plugin.c | 11 ++- src/modules/module-metadata.c | 11 +-- src/modules/module-protocol-native.c | 10 +-- src/modules/module-protocol-pulse/cmd.c | 13 ++-- .../modules/module-stream-restore.c | 17 ++-- .../module-protocol-pulse/pulse-server.c | 8 +- src/modules/module-protocol-pulse/server.c | 5 +- src/pipewire/conf.c | 77 +++++-------------- src/pipewire/context.c | 12 +-- src/pipewire/properties.c | 14 +--- src/tools/pw-dump.c | 5 +- 24 files changed, 171 insertions(+), 269 deletions(-) diff --git a/pipewire-alsa/alsa-plugins/ctl_pipewire.c b/pipewire-alsa/alsa-plugins/ctl_pipewire.c index 0958308e8..be5342f02 100644 --- a/pipewire-alsa/alsa-plugins/ctl_pipewire.c +++ b/pipewire-alsa/alsa-plugins/ctl_pipewire.c @@ -1023,20 +1023,15 @@ static int json_object_find(const char *obj, const char *key, char *value, size_ { struct spa_json it[1]; const char *v; - char k[128]; + int l, kl = strlen(key) + 3; + char k[kl]; if (spa_json_begin_object(&it[0], obj, strlen(obj)) <= 0) return -EINVAL; - while (spa_json_get_string(&it[0], k, sizeof(k)) > 0) { - if (spa_streq(k, key)) { - if (spa_json_get_string(&it[1], value, len) <= 0) - continue; - return 0; - } else { - if (spa_json_next(&it[1], &v) <= 0) - break; - } + while ((l = spa_json_object_next(&it[0], k, kl, &v)) > 0) { + if (spa_streq(k, key)) + return spa_json_parse_stringn(v, l, value, len); } return -ENOENT; } diff --git a/pipewire-alsa/alsa-plugins/pcm_pipewire.c b/pipewire-alsa/alsa-plugins/pcm_pipewire.c index 4c153670e..5f1f91053 100644 --- a/pipewire-alsa/alsa-plugins/pcm_pipewire.c +++ b/pipewire-alsa/alsa-plugins/pcm_pipewire.c @@ -1140,9 +1140,7 @@ static int parse_value(const char *str, struct param_info *info) info->type = TYPE_MIN_MAX; info->n_vals = 2; spa_json_enter(&it[0], &it[1]); - while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) { - if ((len = spa_json_next(&it[1], &val)) <= 0) - break; + while ((len = spa_json_object_next(&it[1], key, sizeof(key), &val)) > 0) { if (info->collect(val, len, &v) < 0) continue; if (spa_streq(key, "min")) diff --git a/pipewire-jack/src/pipewire-jack.c b/pipewire-jack/src/pipewire-jack.c index 28481e32e..91de4e8f3 100644 --- a/pipewire-jack/src/pipewire-jack.c +++ b/pipewire-jack/src/pipewire-jack.c @@ -3460,20 +3460,15 @@ static int json_object_find(const char *obj, const char *key, char *value, size_ { struct spa_json it[1]; const char *v; - char k[128]; + int l, kl = strlen(key) + 3; + char k[kl]; if (spa_json_begin_object(&it[0], obj, strlen(obj)) <= 0) return -EINVAL; - while (spa_json_get_string(&it[0], k, sizeof(k)) > 0) { - if (spa_streq(k, key)) { - if (spa_json_get_string(&it[0], value, len) <= 0) - continue; - return 0; - } else { - if (spa_json_next(&it[0], &v) <= 0) - break; - } + while ((l = spa_json_object_next(&it[0], k, kl, &v)) > 0) { + if (spa_streq(k, key)) + return spa_json_parse_stringn(v, l, value, len); } return -ENOENT; } diff --git a/spa/include/spa/utils/json-pod.h b/spa/include/spa/utils/json-pod.h index 7318e47fc..2a0813fd8 100644 --- a/spa/include/spa/utils/json-pod.h +++ b/spa/include/spa/utils/json-pod.h @@ -42,10 +42,8 @@ static inline int spa_json_to_pod_part(struct spa_pod_builder *b, uint32_t flags spa_pod_builder_push_object(b, &f[0], info->parent, id); spa_json_enter(iter, &it[0]); - while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) { + while ((l = spa_json_object_next(&it[0], key, sizeof(key), &v)) > 0) { const struct spa_type_info *pi; - if ((l = spa_json_next(&it[0], &v)) <= 0) - break; if ((pi = spa_debug_type_find_short(ti->values, key)) != NULL) type = pi->type; else if (!spa_atou32(key, &type, 0)) diff --git a/spa/include/spa/utils/json.h b/spa/include/spa/utils/json.h index b2299f2e7..b9ecbc53f 100644 --- a/spa/include/spa/utils/json.h +++ b/spa/include/spa/utils/json.h @@ -39,7 +39,7 @@ struct spa_json { uint32_t depth; }; -#define SPA_JSON_INIT(data,size) ((struct spa_json) { (data), (data)+(size), 0, 0, 0 }) +#define SPA_JSON_INIT(data,size) ((struct spa_json) { (data), (data)+(size), NULL, 0, 0 }) static inline void spa_json_init(struct spa_json * iter, const char *data, size_t size) { @@ -54,6 +54,8 @@ static inline void spa_json_enter(struct spa_json * iter, struct spa_json * sub) #define SPA_JSON_SAVE(iter) ((struct spa_json) { (iter)->cur, (iter)->end, NULL, (iter)->state, 0 }) +#define SPA_JSON_START(iter,p) ((struct spa_json) { (p), (iter)->end, NULL, 0, 0 }) + /** Get the next token. \a value points to the token and the return value * is the length. Returns -1 on parse error, 0 on end of input. */ static inline int spa_json_next(struct spa_json * iter, const char **value) @@ -594,7 +596,7 @@ static inline int spa_json_parse_stringn(const char *val, int len, char *result, { const char *p; if (maxlen <= len) - return -1; + return -ENOSPC; if (!spa_json_is_string(val, len)) { if (result != val) memmove(result, val, len); @@ -712,6 +714,19 @@ static inline int spa_json_encode_string(char *str, int size, const char *val) return len-1; } +static inline int spa_json_object_next(struct spa_json *iter, char *key, int maxkeylen, const char **value) +{ + int res1, res2; + while (true) { + res1 = spa_json_get_string(iter, key, maxkeylen); + if (res1 <= 0 && res1 != -ENOSPC) + return res1; + res2 = spa_json_next(iter, value); + if (res2 <= 0 || res1 != -ENOSPC) + return res2; + } +} + /** * \} */ diff --git a/spa/plugins/audioconvert/audioadapter.c b/spa/plugins/audioconvert/audioadapter.c index f05ac21b6..bbae3de2e 100644 --- a/spa/plugins/audioconvert/audioadapter.c +++ b/spa/plugins/audioconvert/audioadapter.c @@ -1825,20 +1825,21 @@ static int do_auto_port_config(struct impl *this, const char *str) #define POSITION_PRESERVE 0 #define POSITION_AUX 1 #define POSITION_UNKNOWN 2 - int res, position = POSITION_PRESERVE; + int l, res, position = POSITION_PRESERVE; struct spa_pod *param; bool have_format = false, monitor = false, control = false; struct spa_audio_info format = { 0, }; enum spa_param_port_config_mode mode = SPA_PARAM_PORT_CONFIG_MODE_none; struct spa_json it[1]; char key[1024], val[256]; + const char *v; if (spa_json_begin_object(&it[0], str, strlen(str)) <= 0) return -EINVAL; - while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) { - if (spa_json_get_string(&it[0], val, sizeof(val)) <= 0) - break; + while ((l = spa_json_object_next(&it[0], key, sizeof(key), &v)) > 0) { + if (spa_json_parse_stringn(v, l, val, sizeof(val)) <= 0) + continue; if (spa_streq(key, "mode")) { mode = spa_debug_type_find_type_short(spa_type_param_port_config_mode, val); diff --git a/spa/plugins/bluez5/quirks.c b/spa/plugins/bluez5/quirks.c index e204822c4..fc89e1b8b 100644 --- a/spa/plugins/bluez5/quirks.c +++ b/spa/plugins/bluez5/quirks.c @@ -87,26 +87,24 @@ static int do_match(const char *rules, struct spa_dict *dict, uint32_t *no_featu while (spa_json_enter_object(&rules_arr, &it[0]) > 0) { char key[256]; - int match = true; + int match = true, len; uint32_t no_features_cur = 0; + const char *value; - while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) { + while ((len = spa_json_object_next(&it[0], key, sizeof(key), &value)) > 0) { char val[4096]; - const char *str, *value; - int len; + const char *str; bool success = false; if (spa_streq(key, "no-features")) { - if (spa_json_enter_array(&it[0], &it[1]) > 0) { + if (spa_json_is_array(value, len) > 0) { + spa_json_enter(&it[0], &it[1]); while (spa_json_get_string(&it[1], val, sizeof(val)) > 0) no_features_cur |= parse_feature(val); } continue; } - if ((len = spa_json_next(&it[0], &value)) <= 0) - break; - if (spa_json_is_null(value, len)) { value = NULL; } else { @@ -161,17 +159,13 @@ static void load_quirks(struct spa_bt_quirks *this, const char *str, size_t len) struct spa_json rules; char key[1024]; struct spa_error_location loc; + int sz; + const char *value; if (spa_json_enter_object(&data, &rules) <= 0) spa_json_init(&rules, str, len); - while (spa_json_get_string(&rules, key, sizeof(key)) > 0) { - int sz; - const char *value; - - if ((sz = spa_json_next(&rules, &value)) <= 0) - break; - + while ((sz = spa_json_object_next(&rules, key, sizeof(key), &value)) > 0) { if (!spa_json_is_container(value, sz)) continue; diff --git a/spa/tools/spa-json-dump.c b/spa/tools/spa-json-dump.c index 62712bb72..a1f2e619a 100644 --- a/spa/tools/spa-json-dump.c +++ b/spa/tools/spa-json-dump.c @@ -82,14 +82,12 @@ static int dump(FILE *file, int indent, struct spa_json *it, const char *value, spa_json_enter(it, &sub); else sub = *it; - while (spa_json_get_string(&sub, key, sizeof(key)) > 0) { + while ((len = spa_json_object_next(&sub, key, sizeof(key), &value)) > 0) { fprintf(file, "%s\n%*s", count++ > 0 ? "," : "", indent+2, ""); encode_string(file, key, strlen(key)); fprintf(file, ": "); - if ((len = spa_json_next(&sub, &value)) <= 0) - break; res = dump(file, indent+2, &sub, value, len); if (res < 0) { if (toplevel) diff --git a/src/modules/module-access.c b/src/modules/module-access.c index 82e94722e..16da8300e 100644 --- a/src/modules/module-access.c +++ b/src/modules/module-access.c @@ -276,17 +276,14 @@ static int parse_socket_args(struct impl *impl, const char *str) { struct spa_json it[1]; char socket[PATH_MAX]; + const char *val; + int len; if (spa_json_begin_object(&it[0], str, strlen(str)) <= 0) return -EINVAL; - while (spa_json_get_string(&it[0], socket, sizeof(socket)) > 0) { + while ((len = spa_json_object_next(&it[0], socket, sizeof(socket), &val)) > 0) { char value[256]; - const char *val; - int len; - - if ((len = spa_json_next(&it[0], &val)) <= 0) - return -EINVAL; if (spa_json_parse_stringn(val, len, value, sizeof(value)) <= 0) return -EINVAL; diff --git a/src/modules/module-avb/adp.c b/src/modules/module-avb/adp.c index 9fa0d29d1..2275b7b02 100644 --- a/src/modules/module-avb/adp.c +++ b/src/modules/module-avb/adp.c @@ -286,18 +286,15 @@ static int do_discover(struct adp *adp, const char *args, FILE *out) struct spa_json it[1]; char key[128]; uint64_t entity_id = 0ULL; + int len; + const char *value; if (spa_json_begin_object(&it[0], args, strlen(args)) <= 0) return -EINVAL; - while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) { - int len; - const char *value; + while ((len = spa_json_object_next(&it[0], key, sizeof(key), &value)) > 0) { uint64_t id_val; - if ((len = spa_json_next(&it[0], &value)) <= 0) - break; - if (spa_json_is_null(value, len)) continue; diff --git a/src/modules/module-avb/maap.c b/src/modules/module-avb/maap.c index a721e3752..2ba40cd33 100644 --- a/src/modules/module-avb/maap.c +++ b/src/modules/module-avb/maap.c @@ -255,7 +255,8 @@ static int load_state(struct maap *maap) char key[512]; struct spa_json it[2]; bool have_offset = false; - int count = 0, offset = 0; + int count = 0, offset = 0, len; + const char *val; snprintf(key, sizeof(key), "maap.%s", maap->server->ifname); pw_conf_load_state("module-avb", key, maap->props); @@ -269,13 +270,7 @@ static int load_state(struct maap *maap) if (spa_json_enter_object(&it[0], &it[1]) <= 0) return 0; - while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) { - const char *val; - int len; - - if ((len = spa_json_next(&it[1], &val)) <= 0) - break; - + while ((len = spa_json_object_next(&it[1], key, sizeof(key), &val)) > 0) { if (spa_streq(key, "start")) { uint8_t addr[6]; if (avb_utils_parse_addr(val, len, addr) >= 0 && diff --git a/src/modules/module-filter-chain.c b/src/modules/module-filter-chain.c index a7873d2b7..c1c2794a3 100644 --- a/src/modules/module-filter-chain.c +++ b/src/modules/module-filter-chain.c @@ -1913,14 +1913,12 @@ done: static int parse_control(struct node *node, struct spa_json *control) { char key[256]; + const char *val; + int len; - while (spa_json_get_string(control, key, sizeof(key)) > 0) { + while ((len = spa_json_object_next(control, key, sizeof(key), &val)) > 0) { float fl; - const char *val; - int res, len; - - if ((len = spa_json_next(control, &val)) < 0) - break; + int res; if (spa_json_parse_float(val, len, &fl) <= 0) { pw_log_warn("control '%s' expects a number, ignoring", key); @@ -1946,29 +1944,28 @@ static int parse_link(struct graph *graph, struct spa_json *json) struct node *def_in_node, *def_out_node; struct port *in_port, *out_port; struct link *link; + int len; if (spa_list_is_empty(&graph->node_list)) { pw_log_error("can't make links in graph without nodes"); return -EINVAL; } - while (spa_json_get_string(json, key, sizeof(key)) > 0) { + while ((len = spa_json_object_next(json, key, sizeof(key), &val)) > 0) { if (spa_streq(key, "output")) { - if (spa_json_get_string(json, output, sizeof(output)) <= 0) { + if (spa_json_parse_stringn(val, len, output, sizeof(output)) <= 0) { pw_log_error("output expects a string"); return -EINVAL; } } else if (spa_streq(key, "input")) { - if (spa_json_get_string(json, input, sizeof(input)) <= 0) { + if (spa_json_parse_stringn(val, len, input, sizeof(input)) <= 0) { pw_log_error("input expects a string"); return -EINVAL; } } else { pw_log_error("unexpected link key '%s'", key); - if (spa_json_next(json, &val) < 0) - break; } } def_out_node = spa_list_first(&graph->node_list, struct node, link); @@ -2049,40 +2046,39 @@ static int parse_volume(struct graph *graph, struct spa_json *json, bool capture struct port *port; struct volume *vol = capture ? &graph->capture_volume : &graph->playback_volume; + int len; if (spa_list_is_empty(&graph->node_list)) { pw_log_error("can't set volume in graph without nodes"); return -EINVAL; } - while (spa_json_get_string(json, key, sizeof(key)) > 0) { + while ((len = spa_json_object_next(json, key, sizeof(key), &val)) > 0) { if (spa_streq(key, "control")) { - if (spa_json_get_string(json, control, sizeof(control)) <= 0) { + if (spa_json_parse_stringn(val, len, control, sizeof(control)) <= 0) { pw_log_error("control expects a string"); return -EINVAL; } } else if (spa_streq(key, "min")) { - if (spa_json_get_float(json, &min) <= 0) { + if (spa_json_parse_float(val, len, &min) <= 0) { pw_log_error("min expects a float"); return -EINVAL; } } else if (spa_streq(key, "max")) { - if (spa_json_get_float(json, &max) <= 0) { + if (spa_json_parse_float(val, len, &max) <= 0) { pw_log_error("max expects a float"); return -EINVAL; } } else if (spa_streq(key, "scale")) { - if (spa_json_get_string(json, scale, sizeof(scale)) <= 0) { + if (spa_json_parse_stringn(val, len, scale, sizeof(scale)) <= 0) { pw_log_error("scale expects a string"); return -EINVAL; } } else { pw_log_error("unexpected volume key '%s'", key); - if (spa_json_next(json, &val) < 0) - break; } } if (capture) @@ -2144,44 +2140,41 @@ static int load_node(struct graph *graph, struct spa_json *json) bool have_control = false; bool have_config = false; uint32_t i; - int res; + int res, len; - while (spa_json_get_string(json, key, sizeof(key)) > 0) { + while ((len = spa_json_object_next(json, key, sizeof(key), &val)) > 0) { if (spa_streq("type", key)) { - if (spa_json_get_string(json, type, sizeof(type)) <= 0) { + if (spa_json_parse_stringn(val, len, type, sizeof(type)) <= 0) { pw_log_error("type expects a string"); return -EINVAL; } } else if (spa_streq("name", key)) { - if (spa_json_get_string(json, name, sizeof(name)) <= 0) { + if (spa_json_parse_stringn(val, len, name, sizeof(name)) <= 0) { pw_log_error("name expects a string"); return -EINVAL; } } else if (spa_streq("plugin", key)) { - if (spa_json_get_string(json, plugin, sizeof(plugin)) <= 0) { + if (spa_json_parse_stringn(val, len, plugin, sizeof(plugin)) <= 0) { pw_log_error("plugin expects a string"); return -EINVAL; } } else if (spa_streq("label", key)) { - if (spa_json_get_string(json, label, sizeof(label)) <= 0) { + if (spa_json_parse_stringn(val, len, label, sizeof(label)) <= 0) { pw_log_error("label expects a string"); return -EINVAL; } } else if (spa_streq("control", key)) { - if (spa_json_enter_object(json, &control) <= 0) { + if (!spa_json_is_object(val, len)) { pw_log_error("control expects an object"); return -EINVAL; } + spa_json_enter(json, &control); have_control = true; } else if (spa_streq("config", key)) { - config = SPA_JSON_SAVE(json); + config = SPA_JSON_START(json, val); have_config = true; - if (spa_json_next(json, &val) < 0) - break; } else { pw_log_warn("unexpected node key '%s'", key); - if (spa_json_next(json, &val) < 0) - break; } } if (spa_streq(type, "builtin")) @@ -2720,7 +2713,7 @@ static int load_graph(struct graph *graph, struct pw_properties *props) struct spa_json nodes, *pnodes = NULL, links, *plinks = NULL; const char *json, *val; char key[256]; - int res; + int res, len; spa_list_init(&graph->node_list); spa_list_init(&graph->link_list); @@ -2735,52 +2728,56 @@ static int load_graph(struct graph *graph, struct pw_properties *props) return -EINVAL; } - while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) { + while ((len = spa_json_object_next(&it[0], key, sizeof(key), &val)) > 0) { if (spa_streq("nodes", key)) { - if (spa_json_enter_array(&it[0], &nodes) <= 0) { + if (!spa_json_is_array(val, len)) { pw_log_error("nodes expects an array"); return -EINVAL; } + spa_json_enter(&it[0], &nodes); pnodes = &nodes; } else if (spa_streq("links", key)) { - if (spa_json_enter_array(&it[0], &links) <= 0) { + if (!spa_json_is_array(val, len)) { pw_log_error("links expects an array"); return -EINVAL; } + spa_json_enter(&it[0], &links); plinks = &links; } else if (spa_streq("inputs", key)) { - if (spa_json_enter_array(&it[0], &inputs) <= 0) { + if (!spa_json_is_array(val, len)) { pw_log_error("inputs expects an array"); return -EINVAL; } + spa_json_enter(&it[0], &inputs); pinputs = &inputs; } else if (spa_streq("outputs", key)) { - if (spa_json_enter_array(&it[0], &outputs) <= 0) { + if (!spa_json_is_array(val, len)) { pw_log_error("outputs expects an array"); return -EINVAL; } + spa_json_enter(&it[0], &outputs); poutputs = &outputs; } else if (spa_streq("capture.volumes", key)) { - if (spa_json_enter_array(&it[0], &cvolumes) <= 0) { + if (!spa_json_is_array(val, len)) { pw_log_error("capture.volumes expects an array"); return -EINVAL; } + spa_json_enter(&it[0], &cvolumes); pcvolumes = &cvolumes; } else if (spa_streq("playback.volumes", key)) { - if (spa_json_enter_array(&it[0], &pvolumes) <= 0) { + if (!spa_json_is_array(val, len)) { pw_log_error("playback.volumes expects an array"); return -EINVAL; } + spa_json_enter(&it[0], &pvolumes); ppvolumes = &pvolumes; } else { pw_log_warn("unexpected graph key '%s'", key); - if (spa_json_next(&it[0], &val) < 0) - break; } } if (pnodes == NULL) { diff --git a/src/modules/module-filter-chain/builtin_plugin.c b/src/modules/module-filter-chain/builtin_plugin.c index 132923c71..d60c901be 100644 --- a/src/modules/module-filter-chain/builtin_plugin.c +++ b/src/modules/module-filter-chain/builtin_plugin.c @@ -282,6 +282,7 @@ static void *bq_instantiate(const struct fc_descriptor * Descriptor, const char *val; char key[256]; uint32_t best_rate = 0; + int len; impl = calloc(1, sizeof(*impl)); if (impl == NULL) @@ -303,64 +304,63 @@ static void *bq_instantiate(const struct fc_descriptor * Descriptor, goto error; } - while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) { + while ((len = spa_json_object_next(&it[0], key, sizeof(key), &val)) > 0) { if (spa_streq(key, "coefficients")) { - if (spa_json_enter_array(&it[0], &it[1]) <= 0) { + if (!spa_json_is_array(val, len)) { pw_log_error("biquads:coefficients require an array"); goto error; } + spa_json_enter(&it[0], &it[1]); while (spa_json_enter_object(&it[1], &it[2]) > 0) { int32_t rate = 0; float b0 = 1.0f, b1 = 0.0f, b2 = 0.0f; float a0 = 1.0f, a1 = 0.0f, a2 = 0.0f; - while (spa_json_get_string(&it[2], key, sizeof(key)) > 0) { + while ((len = spa_json_object_next(&it[2], key, sizeof(key), &val)) > 0) { if (spa_streq(key, "rate")) { - if (spa_json_get_int(&it[2], &rate) <= 0) { + if (spa_json_parse_int(val, len, &rate) <= 0) { pw_log_error("biquads:rate requires a number"); goto error; } } else if (spa_streq(key, "b0")) { - if (spa_json_get_float(&it[2], &b0) <= 0) { + if (spa_json_parse_float(val, len, &b0) <= 0) { pw_log_error("biquads:b0 requires a float"); goto error; } } else if (spa_streq(key, "b1")) { - if (spa_json_get_float(&it[2], &b1) <= 0) { + if (spa_json_parse_float(val, len, &b1) <= 0) { pw_log_error("biquads:b1 requires a float"); goto error; } } else if (spa_streq(key, "b2")) { - if (spa_json_get_float(&it[2], &b2) <= 0) { + if (spa_json_parse_float(val, len, &b2) <= 0) { pw_log_error("biquads:b2 requires a float"); goto error; } } else if (spa_streq(key, "a0")) { - if (spa_json_get_float(&it[2], &a0) <= 0) { + if (spa_json_parse_float(val, len, &a0) <= 0) { pw_log_error("biquads:a0 requires a float"); goto error; } } else if (spa_streq(key, "a1")) { - if (spa_json_get_float(&it[2], &a1) <= 0) { + if (spa_json_parse_float(val, len, &a1) <= 0) { pw_log_error("biquads:a1 requires a float"); goto error; } } else if (spa_streq(key, "a2")) { - if (spa_json_get_float(&it[2], &a2) <= 0) { + if (spa_json_parse_float(val, len, &a2) <= 0) { pw_log_error("biquads:a0 requires a float"); goto error; } } else { pw_log_warn("biquads: ignoring coefficients key: '%s'", key); - if (spa_json_next(&it[2], &val) < 0) - break; } } if (labs((long)rate - (long)SampleRate) < @@ -372,8 +372,6 @@ static void *bq_instantiate(const struct fc_descriptor * Descriptor, } else { pw_log_warn("biquads: ignoring config key: '%s'", key); - if (spa_json_next(&it[0], &val) < 0) - break; } } @@ -885,36 +883,32 @@ static void * convolver_instantiate(const struct fc_descriptor * Descriptor, return NULL; } - while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) { + while ((len = spa_json_object_next(&it[0], key, sizeof(key), &val)) > 0) { if (spa_streq(key, "blocksize")) { - if (spa_json_get_int(&it[0], &blocksize) <= 0) { + if (spa_json_parse_int(val, len, &blocksize) <= 0) { pw_log_error("convolver:blocksize requires a number"); return NULL; } } else if (spa_streq(key, "tailsize")) { - if (spa_json_get_int(&it[0], &tailsize) <= 0) { + if (spa_json_parse_int(val, len, &tailsize) <= 0) { pw_log_error("convolver:tailsize requires a number"); return NULL; } } else if (spa_streq(key, "gain")) { - if (spa_json_get_float(&it[0], &gain) <= 0) { + if (spa_json_parse_float(val, len, &gain) <= 0) { pw_log_error("convolver:gain requires a number"); return NULL; } } else if (spa_streq(key, "delay")) { - if (spa_json_get_int(&it[0], &delay) <= 0) { + if (spa_json_parse_int(val, len, &delay) <= 0) { pw_log_error("convolver:delay requires a number"); return NULL; } } else if (spa_streq(key, "filename")) { - if ((len = spa_json_next(&it[0], &val)) <= 0) { - pw_log_error("convolver:filename requires a string or an array"); - return NULL; - } if (spa_json_is_array(val, len)) { spa_json_enter(&it[0], &it[1]); while (spa_json_get_string(&it[1], v, sizeof(v)) > 0 && @@ -931,33 +925,31 @@ static void * convolver_instantiate(const struct fc_descriptor * Descriptor, } } else if (spa_streq(key, "offset")) { - if (spa_json_get_int(&it[0], &offset) <= 0) { + if (spa_json_parse_int(val, len, &offset) <= 0) { pw_log_error("convolver:offset requires a number"); return NULL; } } else if (spa_streq(key, "length")) { - if (spa_json_get_int(&it[0], &length) <= 0) { + if (spa_json_parse_int(val, len, &length) <= 0) { pw_log_error("convolver:length requires a number"); return NULL; } } else if (spa_streq(key, "channel")) { - if (spa_json_get_int(&it[0], &channel) <= 0) { + if (spa_json_parse_int(val, len, &channel) <= 0) { pw_log_error("convolver:channel requires a number"); return NULL; } } else if (spa_streq(key, "resample_quality")) { - if (spa_json_get_int(&it[0], &resample_quality) <= 0) { + if (spa_json_parse_int(val, len, &resample_quality) <= 0) { pw_log_error("convolver:resample_quality requires a number"); return NULL; } } else { pw_log_warn("convolver: ignoring config key: '%s'", key); - if (spa_json_next(&it[0], &val) < 0) - break; } } if (filenames[0] == NULL) { @@ -1099,6 +1091,7 @@ static void *delay_instantiate(const struct fc_descriptor * Descriptor, const char *val; char key[256]; float max_delay = 1.0f; + int len; if (config == NULL) { pw_log_error("delay: requires a config section"); @@ -1111,16 +1104,14 @@ static void *delay_instantiate(const struct fc_descriptor * Descriptor, return NULL; } - while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) { + while ((len = spa_json_object_next(&it[0], key, sizeof(key), &val)) > 0) { if (spa_streq(key, "max-delay")) { - if (spa_json_get_float(&it[0], &max_delay) <= 0) { + if (spa_json_parse_float(val, len, &max_delay) <= 0) { pw_log_error("delay:max-delay requires a number"); return NULL; } } else { pw_log_warn("delay: ignoring config key: '%s'", key); - if (spa_json_next(&it[0], &val) < 0) - break; } } if (max_delay <= 0.0f) diff --git a/src/modules/module-filter-chain/sofa_plugin.c b/src/modules/module-filter-chain/sofa_plugin.c index 5645bd106..7306c06bb 100644 --- a/src/modules/module-filter-chain/sofa_plugin.c +++ b/src/modules/module-filter-chain/sofa_plugin.c @@ -40,6 +40,7 @@ static void * spatializer_instantiate(const struct fc_descriptor * Descriptor, const char *val; char key[256]; char filename[PATH_MAX] = ""; + int len; errno = EINVAL; if (config == NULL) { @@ -58,30 +59,28 @@ static void * spatializer_instantiate(const struct fc_descriptor * Descriptor, return NULL; } - while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) { + while ((len = spa_json_object_next(&it[0], key, sizeof(key), &val)) > 0) { if (spa_streq(key, "blocksize")) { - if (spa_json_get_int(&it[0], &impl->blocksize) <= 0) { + if (spa_json_parse_int(val, len, &impl->blocksize) <= 0) { pw_log_error("spatializer:blocksize requires a number"); errno = EINVAL; goto error; } } else if (spa_streq(key, "tailsize")) { - if (spa_json_get_int(&it[0], &impl->tailsize) <= 0) { + if (spa_json_parse_int(val, len, &impl->tailsize) <= 0) { pw_log_error("spatializer:tailsize requires a number"); errno = EINVAL; goto error; } } else if (spa_streq(key, "filename")) { - if (spa_json_get_string(&it[0], filename, sizeof(filename)) <= 0) { + if (spa_json_parse_stringn(val, len, filename, sizeof(filename)) <= 0) { pw_log_error("spatializer:filename requires a string"); errno = EINVAL; goto error; } } - else if (spa_json_next(&it[0], &val) < 0) - break; } if (!filename[0]) { pw_log_error("spatializer:filename was not given"); diff --git a/src/modules/module-metadata.c b/src/modules/module-metadata.c index b813327ac..b6588f6fc 100644 --- a/src/modules/module-metadata.c +++ b/src/modules/module-metadata.c @@ -73,15 +73,10 @@ static int fill_metadata(struct pw_metadata *metadata, const char *str) while (spa_json_enter_object(&it[0], &it[1]) > 0) { char key[256], *k = NULL, *v = NULL, *t = NULL; - int id = 0; - - while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) { - int len; - const char *val; - - if ((len = spa_json_next(&it[1], &val)) <= 0) - return -EINVAL; + int id = 0, len; + const char *val; + while ((len = spa_json_object_next(&it[1], key, sizeof(key), &val)) > 0) { if (spa_streq(key, "id")) { if (spa_json_parse_int(val, len, &id) <= 0) return -EINVAL; diff --git a/src/modules/module-protocol-native.c b/src/modules/module-protocol-native.c index d20b3d854..66b93fdac 100644 --- a/src/modules/module-protocol-native.c +++ b/src/modules/module-protocol-native.c @@ -1689,6 +1689,8 @@ static int create_servers(struct pw_protocol *this, struct pw_impl_core *core, char key[256]; char name[PATH_MAX]; char selinux_context[PATH_MAX]; + const char *value; + int len; info.uid = getuid(); info.gid = getgid(); @@ -1696,13 +1698,7 @@ static int create_servers(struct pw_protocol *this, struct pw_impl_core *core, pw_properties_clear(p); pw_properties_update(p, &props->dict); - while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) { - const char *value; - int len; - - if ((len = spa_json_next(&it[1], &value)) <= 0) - goto error_invalid; - + while ((len = spa_json_object_next(&it[1], key, sizeof(key), &value)) > 0) { if (spa_streq(key, "name")) { if (spa_json_parse_stringn(value, len, name, sizeof(name)) < 0) goto error_invalid; diff --git a/src/modules/module-protocol-pulse/cmd.c b/src/modules/module-protocol-pulse/cmd.c index bd7506460..8f5200c6f 100644 --- a/src/modules/module-protocol-pulse/cmd.c +++ b/src/modules/module-protocol-pulse/cmd.c @@ -80,14 +80,10 @@ static int parse_cmd(void *user_data, const char *location, while (spa_json_enter_object(&it[0], &it[1]) > 0) { char *cmd = NULL, *args = NULL, *flags = NULL; + const char *val; + int len; - while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) { - const char *val; - int len; - - if ((len = spa_json_next(&it[1], &val)) <= 0) - break; - + while ((len = spa_json_object_next(&it[1], key, sizeof(key), &val)) > 0) { if (spa_streq(key, "cmd")) { cmd = (char*)val; spa_json_parse_stringn(val, len, cmd, len+1); @@ -99,6 +95,8 @@ static int parse_cmd(void *user_data, const char *location, len = spa_json_container_len(&it[1], val, len); flags = (char*)val; spa_json_parse_stringn(val, len, flags, len+1); + } else { + pw_log_warn("unknown pulse.cmd key %s", key); } } if (cmd != NULL) @@ -106,7 +104,6 @@ static int parse_cmd(void *user_data, const char *location, if (res < 0) break; } - return res; } diff --git a/src/modules/module-protocol-pulse/modules/module-stream-restore.c b/src/modules/module-protocol-pulse/modules/module-stream-restore.c index ab689285d..bdb9cfd7d 100644 --- a/src/modules/module-protocol-pulse/modules/module-stream-restore.c +++ b/src/modules/module-protocol-pulse/modules/module-stream-restore.c @@ -185,6 +185,7 @@ static int do_extension_stream_restore_read(struct module *module, struct client struct volume vol = VOLUME_INIT; struct channel_map map = CHANNEL_MAP_INIT; float volume = 0.0f; + int len; if (key_to_name(item->key, name, sizeof(name)) < 0) continue; @@ -194,29 +195,31 @@ static int do_extension_stream_restore_read(struct module *module, struct client if (spa_json_begin_object(&it[0], item->value, strlen(item->value)) <= 0) continue; - while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) { + while ((len = spa_json_object_next(&it[0], key, sizeof(key), &value)) > 0) { if (spa_streq(key, "volume")) { - if (spa_json_get_float(&it[0], &volume) <= 0) + if (spa_json_parse_float(value, len, &volume) <= 0) continue; } else if (spa_streq(key, "mute")) { - if (spa_json_get_bool(&it[0], &mute) <= 0) + if (spa_json_parse_bool(value, len, &mute) <= 0) continue; } else if (spa_streq(key, "volumes")) { vol = VOLUME_INIT; - if (spa_json_enter_array(&it[0], &it[1]) <= 0) + if (!spa_json_is_array(value, len)) continue; + spa_json_enter(&it[0], &it[1]); for (vol.channels = 0; vol.channels < CHANNELS_MAX; vol.channels++) { if (spa_json_get_float(&it[1], &vol.values[vol.channels]) <= 0) break; } } else if (spa_streq(key, "channels")) { - if (spa_json_enter_array(&it[0], &it[1]) <= 0) + if (!spa_json_is_array(value, len)) continue; + spa_json_enter(&it[0], &it[1]); for (map.channels = 0; map.channels < CHANNELS_MAX; map.channels++) { char chname[16]; if (spa_json_get_string(&it[1], chname, sizeof(chname)) <= 0) @@ -225,11 +228,9 @@ static int do_extension_stream_restore_read(struct module *module, struct client } } else if (spa_streq(key, "target-node")) { - if (spa_json_get_string(&it[0], device_name, sizeof(device_name)) <= 0) + if (spa_json_parse_stringn(value, len, device_name, sizeof(device_name)) <= 0) continue; } - else if (spa_json_next(&it[0], &value) <= 0) - break; } message_put(reply, TAG_STRING, name, diff --git a/src/modules/module-protocol-pulse/pulse-server.c b/src/modules/module-protocol-pulse/pulse-server.c index 1297add4d..87f07846c 100644 --- a/src/modules/module-protocol-pulse/pulse-server.c +++ b/src/modules/module-protocol-pulse/pulse-server.c @@ -933,18 +933,16 @@ static int json_object_find(const char *obj, const char *key, char *value, size_ struct spa_json it[1]; const char *v; char k[128]; + int l; if (spa_json_begin_object(&it[0], obj, strlen(obj)) <= 0) return -EINVAL; - while (spa_json_get_string(&it[0], k, sizeof(k)) > 0) { + while ((l = spa_json_object_next(&it[0], k, sizeof(k), &v)) > 0) { if (spa_streq(k, key)) { - if (spa_json_get_string(&it[0], value, len) <= 0) + if (spa_json_parse_stringn(v, l, value, len) <= 0) continue; return 0; - } else { - if (spa_json_next(&it[0], &v) <= 0) - break; } } return -ENOENT; diff --git a/src/modules/module-protocol-pulse/server.c b/src/modules/module-protocol-pulse/server.c index 51e8b7cfa..291007832 100644 --- a/src/modules/module-protocol-pulse/server.c +++ b/src/modules/module-protocol-pulse/server.c @@ -997,10 +997,7 @@ int servers_create_and_start(struct impl *impl, const char *addresses, struct pw if (spa_json_is_object(v, len)) { spa_json_enter(&it[0], &it[1]); - while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) { - if ((len = spa_json_next(&it[1], &v)) <= 0) - break; - + while ((len = spa_json_object_next(&it[1], key, sizeof(key), &v)) > 0) { if (spa_streq(key, "address")) { spa_json_parse_stringn(v, len, addr_str, sizeof(addr_str)); } else if (spa_streq(key, "max-clients")) { diff --git a/src/pipewire/conf.c b/src/pipewire/conf.c index 108af4fc5..bd773bee8 100644 --- a/src/pipewire/conf.c +++ b/src/pipewire/conf.c @@ -640,16 +640,10 @@ static bool find_match(struct spa_json *arr, const struct spa_dict *props, bool int match = 0, fail = 0; int len; - while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) { + while ((len = spa_json_object_next(&it[0], key, sizeof(key), &value)) > 0) { bool success = false, is_null, reg = false, parse_string = true; int skip = 0; - if ((len = spa_json_next(&it[0], &value)) <= 0) { - pw_log_warn("malformed match rule: key '%s' has " - "no value in '%.*s'", key, az, as); - break; - } - /* first decode a string, when there was a string, we assume it * can not be null but the "null" string, unless there is a modifier, * see below. */ @@ -765,17 +759,10 @@ static int parse_modules(void *user_data, const char *location, while ((r = spa_json_enter_object(&it[0], &it[1])) > 0) { char *name = NULL, *args = NULL, *flags = NULL; bool have_match = true; + const char *val; + int l; - while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) { - const char *val; - int l; - - 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; - } - + while ((l = spa_json_object_next(&it[1], key, sizeof(key), &val)) > 0) { if (spa_streq(key, "name")) { name = (char*)val; spa_json_parse_stringn(val, l, name, l+1); @@ -873,17 +860,10 @@ static int parse_objects(void *user_data, const char *location, while ((r = spa_json_enter_object(&it[0], &it[1])) > 0) { char *factory = NULL, *args = NULL, *flags = NULL; bool have_match = true; + const char *val; + int l; - while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) { - const char *val; - int l; - - 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; - } - + while ((l = spa_json_object_next(&it[1], key, sizeof(key), &val)) > 0) { if (spa_streq(key, "factory")) { factory = (char*)val; spa_json_parse_stringn(val, l, factory, l+1); @@ -1056,20 +1036,11 @@ static int parse_exec(void *user_data, const char *location, while ((r = spa_json_enter_object(&it[0], &it[1])) > 0) { char *path = NULL; - const char *args_val = "[]"; - int args_len = 2; + const char *args_val = "[]", *val; + int args_len = 2, l; bool have_match = true; - while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) { - const char *val; - int l; - - 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; - } - + while ((l = spa_json_object_next(&it[1], key, sizeof(key), &val)) > 0) { if (spa_streq(key, "path")) { path = (char*)val; spa_json_parse_stringn(val, l, path, l+1); @@ -1314,31 +1285,30 @@ int pw_conf_match_rules(const char *str, size_t len, const char *location, while ((r = spa_json_enter_object(&it[0], &it[1])) > 0) { char key[64]; bool have_match = false, have_actions = false; + int res, l; - while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) { + while ((l = spa_json_object_next(&it[1], key, sizeof(key), &val)) > 0) { if (spa_streq(key, "matches")) { - if (spa_json_enter_array(&it[1], &it[2]) < 0) { + if (!spa_json_is_array(val, l)) { pw_log_warn("expected array as matches in '%.*s'", (int)len, str); break; } + spa_json_enter(&it[1], &it[2]); have_match = find_match(&it[2], props, false); } else if (spa_streq(key, "actions")) { - if (spa_json_enter_object(&it[1], &actions) > 0) - have_actions = true; - else + if (!spa_json_is_object(val, l)) { pw_log_warn("expected object as match actions in '%.*s'", (int)len, str); + } else { + have_actions = true; + spa_json_enter(&it[1], &actions); + } } else { pw_log_warn("unknown match key '%s'", key); - 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; - } } } if (!have_match) @@ -1348,16 +1318,9 @@ int pw_conf_match_rules(const char *str, size_t len, const char *location, continue; } - while (spa_json_get_string(&actions, key, sizeof(key)) > 0) { - int res, len; + while ((len = spa_json_object_next(&actions, key, sizeof(key), &val)) > 0) { pw_log_debug("action %s", key); - if ((len = spa_json_next(&actions, &val)) <= 0) { - pw_log_warn("malformed action: key '%s' has no value in '%.*s'", - key, (int)len, str); - break; - } - if (spa_json_is_container(val, len)) len = spa_json_container_len(&actions, val, len); diff --git a/src/pipewire/context.c b/src/pipewire/context.c index 28ba56d4e..ecc8823d6 100644 --- a/src/pipewire/context.c +++ b/src/pipewire/context.c @@ -217,6 +217,8 @@ static int setup_data_loops(struct impl *impl) } while ((r = spa_json_enter_object(&it[0], &it[1])) > 0) { char *props = NULL; + const char *val; + int l; if (i >= MAX_LOOPS) { pw_log_warn("too many context.data-loops, using first %d", @@ -228,15 +230,7 @@ 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[1], key, sizeof(key)) > 0) { - const char *val; - int l; - - 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; - } + while ((l = spa_json_object_next(&it[1], key, sizeof(key), &val)) > 0) { if (spa_json_is_container(val, l)) l = spa_json_container_len(&it[1], val, l); diff --git a/src/pipewire/properties.c b/src/pipewire/properties.c index 4f24203c6..c36f60b71 100644 --- a/src/pipewire/properties.c +++ b/src/pipewire/properties.c @@ -214,8 +214,9 @@ static int update_string(struct pw_properties *props, const char *str, size_t si char key[1024]; struct spa_error_location el; bool err; - int res, cnt = 0; + int len, res, cnt = 0; struct properties changes; + const char *value; if (props) properties_init(&changes, 16); @@ -223,14 +224,9 @@ static int update_string(struct pw_properties *props, const char *str, size_t si if ((res = spa_json_begin_object_relax(&it[0], str, size)) <= 0) return res; - while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) { - int len; - const char *value; + while ((len = spa_json_object_next(&it[0], key, sizeof(key), &value)) > 0) { char *val = NULL; - if ((len = spa_json_next(&it[0], &value)) <= 0) - break; - if (spa_json_is_null(value, len)) val = NULL; else { @@ -887,14 +883,12 @@ static int dump(struct dump_config *c, int indent, struct spa_json *it, const ch fprintf(file, "{"); spa_json_enter(it, &sub); indent += c->indent; - while (spa_json_get_string(&sub, key, sizeof(key)) > 0) { + while ((len = spa_json_object_next(&sub, key, sizeof(key), &value)) > 0) { fprintf(file, "%s%s%*s", count++ > 0 ? "," : "", c->sep, indent, ""); encode_string(c, KEY(c), key, strlen(key), NORMAL(c)); fprintf(file, ": "); - if ((len = spa_json_next(&sub, &value)) <= 0) - break; dump(c, indent, &sub, value, len); } indent -= c->indent; diff --git a/src/tools/pw-dump.c b/src/tools/pw-dump.c index fe5a10419..c8e379c07 100644 --- a/src/tools/pw-dump.c +++ b/src/tools/pw-dump.c @@ -1126,11 +1126,8 @@ static void json_dump_val(struct data *d, const char *key, struct spa_json *it, char val[1024]; put_begin(d, key, "{", STATE_SIMPLE); spa_json_enter(it, &sub); - while (spa_json_get_string(&sub, val, sizeof(val)) > 0) { - if ((len = spa_json_next(&sub, &value)) <= 0) - break; + while ((len = spa_json_object_next(&sub, val, sizeof(val), &value)) > 0) json_dump_val(d, val, &sub, value, len); - } put_end(d, "}", STATE_SIMPLE); } else if (spa_json_is_string(value, len)) { put_encoded_string(d, key, strndupa(value, len));