From b5cccdb3821e5f667cd8fccd5bbcb73a0928a243 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 16 Sep 2024 13:12:05 +0200 Subject: [PATCH] json: add and use spa_json_str_object_find() Parse a string as a json object and copy the value with key as a string. --- pipewire-alsa/alsa-plugins/ctl_pipewire.c | 21 ++---------- pipewire-jack/src/pipewire-jack.c | 21 ++---------- spa/include/spa/utils/json.h | 26 +++++++++++++++ src/gst/gstpipewiredeviceprovider.c | 29 ++-------------- .../module-protocol-pulse/pulse-server.c | 24 ++------------ test/test-spa-json.c | 33 +++++++++++++++++++ 6 files changed, 68 insertions(+), 86 deletions(-) diff --git a/pipewire-alsa/alsa-plugins/ctl_pipewire.c b/pipewire-alsa/alsa-plugins/ctl_pipewire.c index be5342f02..6a5eff75e 100644 --- a/pipewire-alsa/alsa-plugins/ctl_pipewire.c +++ b/pipewire-alsa/alsa-plugins/ctl_pipewire.c @@ -1019,23 +1019,6 @@ static const struct global_info node_info = { }; /** metadata */ -static int json_object_find(const char *obj, const char *key, char *value, size_t len) -{ - struct spa_json it[1]; - const char *v; - int l, kl = strlen(key) + 3; - char k[kl]; - - if (spa_json_begin_object(&it[0], obj, strlen(obj)) <= 0) - return -EINVAL; - - 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; -} - static int metadata_property(void *data, uint32_t subject, const char *key, @@ -1048,14 +1031,14 @@ static int metadata_property(void *data, if (subject == PW_ID_CORE) { if (key == NULL || spa_streq(key, "default.audio.sink")) { if (value == NULL || - json_object_find(value, "name", + spa_json_str_object_find(value, strlen(value), "name", ctl->default_sink, sizeof(ctl->default_sink)) < 0) ctl->default_sink[0] = '\0'; pw_log_debug("found default sink: %s", ctl->default_sink); } if (key == NULL || spa_streq(key, "default.audio.source")) { if (value == NULL || - json_object_find(value, "name", + spa_json_str_object_find(value, strlen(value), "name", ctl->default_source, sizeof(ctl->default_source)) < 0) ctl->default_source[0] = '\0'; pw_log_debug("found default source: %s", ctl->default_source); diff --git a/pipewire-jack/src/pipewire-jack.c b/pipewire-jack/src/pipewire-jack.c index 91de4e8f3..fd2082835 100644 --- a/pipewire-jack/src/pipewire-jack.c +++ b/pipewire-jack/src/pipewire-jack.c @@ -3456,23 +3456,6 @@ static jack_uuid_t client_make_uuid(uint32_t id, bool monitor) return uuid; } -static int json_object_find(const char *obj, const char *key, char *value, size_t len) -{ - struct spa_json it[1]; - const char *v; - int l, kl = strlen(key) + 3; - char k[kl]; - - if (spa_json_begin_object(&it[0], obj, strlen(obj)) <= 0) - return -EINVAL; - - 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; -} - static int metadata_property(void *data, uint32_t id, const char *key, const char *type, const char *value) { @@ -3485,7 +3468,7 @@ static int metadata_property(void *data, uint32_t id, if (id == PW_ID_CORE) { if (key == NULL || spa_streq(key, "default.audio.sink")) { if (value != NULL) { - if (json_object_find(value, "name", + if (spa_json_str_object_find(value, strlen(value), "name", c->metadata->default_audio_sink, sizeof(c->metadata->default_audio_sink)) < 0) value = NULL; @@ -3495,7 +3478,7 @@ static int metadata_property(void *data, uint32_t id, } if (key == NULL || spa_streq(key, "default.audio.source")) { if (value != NULL) { - if (json_object_find(value, "name", + if (spa_json_str_object_find(value, strlen(value), "name", c->metadata->default_audio_source, sizeof(c->metadata->default_audio_source)) < 0) value = NULL; diff --git a/spa/include/spa/utils/json.h b/spa/include/spa/utils/json.h index 2e8764035..c34f34c85 100644 --- a/spa/include/spa/utils/json.h +++ b/spa/include/spa/utils/json.h @@ -145,6 +145,32 @@ static inline int spa_json_object_next(struct spa_json *iter, char *key, int max } } +static inline int spa_json_object_find(struct spa_json *iter, const char *key, const char **value) +{ + struct spa_json obj = SPA_JSON_SAVE(iter); + int res, len = strlen(key) + 3; + char k[len]; + + while ((res = spa_json_object_next(&obj, k, len, value)) > 0) + if (spa_streq(k, key)) + return res; + return -ENOENT; +} + +static inline int spa_json_str_object_find(const char *obj, size_t obj_len, + const char *key, char *value, size_t maxlen) +{ + struct spa_json iter; + int l; + const char *v; + + if (spa_json_begin_object(&iter, obj, obj_len) <= 0) + return -EINVAL; + if ((l = spa_json_object_find(&iter, key, &v)) <= 0) + return l; + return spa_json_parse_stringn(v, l, value, maxlen); +} + /* array */ static inline int spa_json_enter_array(struct spa_json *iter, struct spa_json *sub) { diff --git a/src/gst/gstpipewiredeviceprovider.c b/src/gst/gstpipewiredeviceprovider.c index cc8b48085..dc4f5234e 100644 --- a/src/gst/gstpipewiredeviceprovider.c +++ b/src/gst/gstpipewiredeviceprovider.c @@ -510,29 +510,6 @@ static const struct pw_proxy_events proxy_port_events = { .destroy = destroy_port, }; -static int json_object_find(const char *obj, const char *key, char *value, - size_t len) { - struct spa_json it[2]; - const char *v; - char k[128]; - - spa_json_init(&it[0], obj, strlen(obj)); - if (spa_json_enter_object(&it[0], &it[1]) <= 0) - return -EINVAL; - - while (spa_json_get_string(&it[1], 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; - } - } - return -ENOENT; -} - static int metadata_property(void *data, uint32_t id, const char *key, const char *type, const char *value) { GstPipeWireDeviceProvider *self = data; @@ -546,7 +523,7 @@ static int metadata_property(void *data, uint32_t id, const char *key, return 0; g_free(self->default_audio_source_name); - if (json_object_find(value, "name", name, sizeof(name)) >= 0) + if (spa_json_str_object_find(value, strlen(value), "name", name, sizeof(name)) >= 0) self->default_audio_source_name = g_strdup(name); return 0; } @@ -555,7 +532,7 @@ static int metadata_property(void *data, uint32_t id, const char *key, return 0; g_free(self->default_audio_sink_name); - if (json_object_find(value, "name", name, sizeof(name)) >= 0) + if (spa_json_str_object_find(value, strlen(value), "name", name, sizeof(name)) >= 0) self->default_audio_sink_name = g_strdup(name); return 0; } @@ -564,7 +541,7 @@ static int metadata_property(void *data, uint32_t id, const char *key, return 0; g_free(self->default_video_source_name); - if (json_object_find(value, "name", name, sizeof(name)) >= 0) + if (spa_json_str_object_find(value, strlen(value), "name", name, sizeof(name)) >= 0) self->default_video_source_name = g_strdup(name); return 0; } diff --git a/src/modules/module-protocol-pulse/pulse-server.c b/src/modules/module-protocol-pulse/pulse-server.c index 87f07846c..461f7cb58 100644 --- a/src/modules/module-protocol-pulse/pulse-server.c +++ b/src/modules/module-protocol-pulse/pulse-server.c @@ -928,26 +928,6 @@ static void manager_object_data_timeout(void *data, struct pw_manager_object *o, temporary_move_target_timeout(client, o); } -static int json_object_find(const char *obj, const char *key, char *value, size_t len) -{ - 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 ((l = spa_json_object_next(&it[0], k, sizeof(k), &v)) > 0) { - if (spa_streq(k, key)) { - if (spa_json_parse_stringn(v, l, value, len) <= 0) - continue; - return 0; - } - } - return -ENOENT; -} - static void manager_metadata(void *data, struct pw_manager_object *o, uint32_t subject, const char *key, const char *type, const char *value) { @@ -962,7 +942,7 @@ static void manager_metadata(void *data, struct pw_manager_object *o, if (key == NULL || spa_streq(key, "default.audio.sink")) { if (value != NULL) { - if (json_object_find(value, + if (spa_json_str_object_find(value, strlen(value), "name", name, sizeof(name)) < 0) value = NULL; else @@ -977,7 +957,7 @@ static void manager_metadata(void *data, struct pw_manager_object *o, } if (key == NULL || spa_streq(key, "default.audio.source")) { if (value != NULL) { - if (json_object_find(value, + if (spa_json_str_object_find(value, strlen(value), "name", name, sizeof(name)) < 0) value = NULL; else diff --git a/test/test-spa-json.c b/test/test-spa-json.c index 869a20409..b07acc00d 100644 --- a/test/test-spa-json.c +++ b/test/test-spa-json.c @@ -1065,6 +1065,38 @@ PWTEST(json_data) return PWTEST_PASS; } +PWTEST(json_object_find) +{ + const char *json = " { " + "\"foo\": \"bar\"," + "\"int-key\": 42," + "\"list-key\": []," + "\"obj-key\": {}," + "\"bool-key\": true," + "\"float-key\": 66.6" + " } "; + char value[128]; + + pwtest_int_eq(spa_json_str_object_find(json, strlen(json), "unknown-key", value, 128), -2); + pwtest_int_eq(spa_json_str_object_find("{", 1, "key", value, 128), -2); + pwtest_int_eq(spa_json_str_object_find("this is no json", 15, "key", value, 128), -22); + pwtest_int_eq(spa_json_str_object_find(json, strlen(json), "foo", value, 128), 1); + pwtest_str_eq(value, "bar"); + pwtest_int_eq(spa_json_str_object_find(json, strlen(json), "int-key", value, 128), 1); + pwtest_str_eq(value, "42"); + pwtest_int_eq(spa_json_str_object_find(json, strlen(json), "list-key", value, 128), 1); + pwtest_str_eq(value, "["); + pwtest_int_eq(spa_json_str_object_find(json, strlen(json), "obj-key", value, 128), 1); + pwtest_str_eq(value, "{"); + pwtest_int_eq(spa_json_str_object_find(json, strlen(json), "bool-key", value, 128), 1); + pwtest_str_eq(value, "true"); + pwtest_int_eq(spa_json_str_object_find(json, strlen(json), "float-key", value, 128), 1); + pwtest_str_eq(value, "66.6"); + + return PWTEST_PASS; +} + + PWTEST_SUITE(spa_json) { pwtest_add(json_abi, PWTEST_NOARG); @@ -1077,6 +1109,7 @@ PWTEST_SUITE(spa_json) pwtest_add(json_float_check, PWTEST_NOARG); pwtest_add(json_int, PWTEST_NOARG); pwtest_add(json_data, PWTEST_NOARG); + pwtest_add(json_object_find, PWTEST_NOARG); return PWTEST_PASS; }