properties: support properties from json object sting

Make pw_properties_new_string() work with a json object string.
This makes it possible to specify property strings as more complex
objects and escape characters.
This commit is contained in:
Wim Taymans 2020-11-28 20:25:39 +01:00
parent 62cdec8448
commit 6e4c138238
3 changed files with 96 additions and 20 deletions

View file

@ -33,7 +33,9 @@ extern "C" {
#include <stddef.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <spa/utils/defs.h>
/* a simple JSON compatible tokenizer */
struct spa_json {
@ -169,6 +171,20 @@ static inline int spa_json_enter_container(struct spa_json *iter, struct spa_jso
return 1;
}
static inline int spa_json_is_container(const char *val, int len)
{
return len > 0 && (*val == '{' || *val == '[');
}
static inline int spa_json_container_len(struct spa_json *iter, const char *value, int len)
{
const char *val;
struct spa_json sub;
spa_json_enter(iter, &sub);
while (spa_json_next(&sub, &val) > 0);
return sub.cur + 1 - value;
}
/* object */
static inline int spa_json_is_object(const char *val, int len)
{
@ -321,6 +337,7 @@ static inline int spa_json_encode_string(char *str, int size, const char *val)
}
__PUT('"');
__PUT('\0');
#undef __PUT
return len-1;
}

View file

@ -24,6 +24,7 @@
#include <stdio.h>
#include <stdarg.h>
#include <spa/utils/json.h>
#include "pipewire/array.h"
#include "pipewire/utils.h"
@ -144,23 +145,11 @@ struct pw_properties *pw_properties_new_dict(const struct spa_dict *dict)
return &impl->this;
}
/** Make a new properties object from the given str
*
* \a str should be a whitespace separated list of key=value
* strings.
*
* \param args a property description
* \return a new properties object
*
* \memberof pw_properties
*/
SPA_EXPORT
struct pw_properties *
pw_properties_new_string(const char *str)
static struct pw_properties *
properties_new_string(const char *str)
{
struct properties *impl;
const char *state = NULL, *s = NULL;
const char *state = NULL, *s = NULL;
size_t len;
int res;
@ -172,10 +161,8 @@ pw_properties_new_string(const char *str)
while (s) {
char *val, *eq;
if ((val = strndup(s, len)) == NULL) {
res = -errno;
goto no_mem;
}
if ((val = strndup(s, len)) == NULL)
goto error_errno;
eq = strchr(val, '=');
if (eq && eq != val) {
@ -188,7 +175,61 @@ pw_properties_new_string(const char *str)
}
return &impl->this;
no_mem:
error_errno:
res = -errno;
pw_properties_free(&impl->this);
errno = -res;
return NULL;
}
/** Make a new properties object from the given str
*
* \a str should be a whitespace separated list of key=value
* strings or a json object.
*
* \param args a property description
* \return a new properties object
*
* \memberof pw_properties
*/
SPA_EXPORT
struct pw_properties *
pw_properties_new_string(const char *object)
{
struct properties *impl;
struct spa_json it[2];
char key[256], *val;
int res;
spa_json_init(&it[0], object, strlen(object));
if (spa_json_enter_object(&it[0], &it[1]) < 0)
return properties_new_string(object);
impl = properties_new(16);
if (impl == NULL)
return NULL;
while (spa_json_get_string(&it[1], key, sizeof(key)-1)) {
int len;
const char *value;
if ((len = spa_json_next(&it[1], &value)) <= 0)
break;
if (spa_json_is_container(value, len))
len = spa_json_container_len(&it[1], value, len);
if ((val = strndup(value, len)) == NULL)
goto error_errno;
if (spa_json_is_string(value, len))
spa_json_parse_string(value, len, val);
add_func(&impl->this, strdup(key), val);
}
return &impl->this;
error_errno:
res = errno;
pw_properties_free(&impl->this);
errno = -res;
return NULL;

View file

@ -310,6 +310,23 @@ static void test_parse(void)
spa_assert(pw_properties_parse_double("1.234") == 1.234);
}
static void test_new_json(void)
{
struct pw_properties *props;
props = pw_properties_new_string("{ \"foo\": \"bar\\n\\t\", \"bar\": 1.8, \"empty\": [ \"foo\", \"bar\" ], \"\": \"gg\"");
spa_assert(props != NULL);
spa_assert(props->flags == 0);
spa_assert(props->dict.n_items == 4);
spa_assert(!strcmp(pw_properties_get(props, "foo"), "bar\n\t"));
spa_assert(!strcmp(pw_properties_get(props, "bar"), "1.8"));
fprintf(stderr, "'%s'\n", pw_properties_get(props, "empty"));
spa_assert(!strcmp(pw_properties_get(props, "empty"), "[ \"foo\", \"bar\" ]"));
pw_properties_free(props);
}
int main(int argc, char *argv[])
{
test_abi();
@ -321,6 +338,7 @@ int main(int argc, char *argv[])
test_new_string();
test_update();
test_parse();
test_new_json();
return 0;
}