diff --git a/src/pipewire/properties.c b/src/pipewire/properties.c index 132acb97e..5312741f5 100644 --- a/src/pipewire/properties.c +++ b/src/pipewire/properties.c @@ -99,7 +99,7 @@ struct pw_properties *pw_properties_new(const char *key, ...) va_start(varargs, key); while (key != NULL) { value = va_arg(varargs, char *); - if (value) + if (value && key[0]) add_func(&impl->this, strdup(key), strdup(value)); key = va_arg(varargs, char *); } @@ -125,9 +125,10 @@ struct pw_properties *pw_properties_new_dict(const struct spa_dict *dict) return NULL; for (i = 0; i < dict->n_items; i++) { - if (dict->items[i].key != NULL && dict->items[i].value != NULL) - add_func(&impl->this, strdup(dict->items[i].key), - strdup(dict->items[i].value)); + const struct spa_dict_item *it = &dict->items[i]; + if (it->key != NULL && it->key[0] && it->value != NULL) + add_func(&impl->this, strdup(it->key), + strdup(it->value)); } return &impl->this; @@ -159,15 +160,20 @@ pw_properties_new_string(const char *str) while (s) { char *val, *eq; - val = strndup(s, len); + if ((val = strndup(s, len)) == NULL) + goto no_mem; + eq = strchr(val, '='); - if (eq) { + if (eq && eq != val) { *eq = '\0'; add_func(&impl->this, val, strdup(eq+1)); } s = pw_split_walk(str, " \t\n\r", &len, &state); } return &impl->this; + no_mem: + pw_properties_free(&impl->this); + return NULL; } /** Copy a properties object @@ -239,7 +245,12 @@ void pw_properties_free(struct pw_properties *properties) static int do_replace(struct pw_properties *properties, const char *key, char *value, bool copy) { struct properties *impl = SPA_CONTAINER_OF(properties, struct properties, this); - int index = find_index(properties, key); + int index; + + if (key == NULL || key[0] == 0) + return 0; + + index = find_index(properties, key); if (index == -1) { if (value == NULL) diff --git a/src/tests/test-properties.c b/src/tests/test-properties.c index 8c543a130..9162f5550 100644 --- a/src/tests/test-properties.c +++ b/src/tests/test-properties.c @@ -36,6 +36,7 @@ static void test_empty(void) props = pw_properties_new(NULL, NULL); spa_assert(props != NULL); + spa_assert(props->flags == 0); spa_assert(props->dict.n_items == 0); spa_assert(pw_properties_get(props, NULL) == NULL); @@ -45,6 +46,7 @@ static void test_empty(void) pw_properties_clear(props); spa_assert(props->dict.n_items == 0); spa_assert(pw_properties_get(props, NULL) == NULL); + spa_assert(pw_properties_get(props, "") == NULL); spa_assert(pw_properties_get(props, "unknown") == NULL); spa_assert(pw_properties_iterate(props, &state) == NULL); @@ -54,6 +56,7 @@ static void test_empty(void) spa_assert(copy->dict.n_items == 0); spa_assert(pw_properties_get(copy, NULL) == NULL); + spa_assert(pw_properties_get(copy, "") == NULL); spa_assert(pw_properties_get(copy, "unknown") == NULL); spa_assert(pw_properties_iterate(copy, &state) == NULL); @@ -67,6 +70,8 @@ static void test_set(void) const char *str; props = pw_properties_new(NULL, NULL); + spa_assert(props != NULL); + spa_assert(props->flags == 0); spa_assert(pw_properties_set(props, "foo", "bar") == 1); spa_assert(props->dict.n_items == 1); @@ -90,6 +95,9 @@ static void test_set(void) spa_assert(props->dict.n_items == 2); spa_assert(pw_properties_get(props, "him") == NULL); + spa_assert(pw_properties_set(props, "", "invalid") == 0); + spa_assert(pw_properties_set(props, NULL, "invalid") == 0); + str = pw_properties_iterate(props, &state); spa_assert(str != NULL && (!strcmp(str, "foo") || !strcmp(str, "bar"))); str = pw_properties_iterate(props, &state); @@ -140,11 +148,175 @@ static void test_set(void) pw_properties_free(copy); } +static void test_setf(void) +{ + struct pw_properties *props; + + props = pw_properties_new(NULL, NULL); + spa_assert(pw_properties_setf(props, "foo", "%d.%08x", 657, 0x89342) == 1); + spa_assert(props->dict.n_items == 1); + spa_assert(!strcmp(pw_properties_get(props, "foo"), "657.00089342")); + + spa_assert(pw_properties_setf(props, "", "%f", 189.45f) == 0); + spa_assert(pw_properties_setf(props, NULL, "%f", 189.45f) == 0); + spa_assert(props->dict.n_items == 1); + + pw_properties_free(props); +} + +static void test_new(void) +{ + struct pw_properties *props; + + props = pw_properties_new("foo", "bar", "bar", "baz", "", "invalid", "him", "too", NULL); + spa_assert(props != NULL); + spa_assert(props->flags == 0); + spa_assert(props->dict.n_items == 3); + + spa_assert(!strcmp(pw_properties_get(props, "foo"), "bar")); + spa_assert(!strcmp(pw_properties_get(props, "bar"), "baz")); + spa_assert(!strcmp(pw_properties_get(props, "him"), "too")); + + pw_properties_free(props); +} + +static void test_new_dict(void) +{ + struct pw_properties *props; + struct spa_dict_item items[5]; + + items[0] = SPA_DICT_ITEM_INIT("foo", "bar"); + items[1] = SPA_DICT_ITEM_INIT("bar", "baz"); + items[3] = SPA_DICT_ITEM_INIT("", "invalid"); + items[4] = SPA_DICT_ITEM_INIT(NULL, "invalid"); + items[2] = SPA_DICT_ITEM_INIT("him", "too"); + + props = pw_properties_new_dict(&SPA_DICT_INIT_ARRAY(items)); + spa_assert(props != NULL); + spa_assert(props->flags == 0); + spa_assert(props->dict.n_items == 3); + + spa_assert(!strcmp(pw_properties_get(props, "foo"), "bar")); + spa_assert(!strcmp(pw_properties_get(props, "bar"), "baz")); + spa_assert(!strcmp(pw_properties_get(props, "him"), "too")); + + pw_properties_free(props); +} + +static void test_new_string(void) +{ + struct pw_properties *props; + + props = pw_properties_new_string("foo=bar bar=baz ignore him=too empty= =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")); + spa_assert(!strcmp(pw_properties_get(props, "bar"), "baz")); + spa_assert(!strcmp(pw_properties_get(props, "him"), "too")); + spa_assert(!strcmp(pw_properties_get(props, "empty"), "")); + + pw_properties_free(props); +} + +static void test_update(void) +{ + struct pw_properties *props; + struct spa_dict_item items[5]; + + props = pw_properties_new(NULL, NULL); + spa_assert(props != NULL); + spa_assert(props->flags == 0); + spa_assert(props->dict.n_items == 0); + + items[0] = SPA_DICT_ITEM_INIT("foo", "bar"); + items[1] = SPA_DICT_ITEM_INIT("bar", "baz"); + items[3] = SPA_DICT_ITEM_INIT("", "invalid"); + items[4] = SPA_DICT_ITEM_INIT(NULL, "invalid"); + items[2] = SPA_DICT_ITEM_INIT("him", "too"); + spa_assert(pw_properties_update(props, &SPA_DICT_INIT_ARRAY(items)) == 3); + spa_assert(props->dict.n_items == 3); + + spa_assert(!strcmp(pw_properties_get(props, "foo"), "bar")); + spa_assert(!strcmp(pw_properties_get(props, "bar"), "baz")); + spa_assert(!strcmp(pw_properties_get(props, "him"), "too")); + + items[0] = SPA_DICT_ITEM_INIT("foo", "bar"); + items[1] = SPA_DICT_ITEM_INIT("bar", "baz"); + spa_assert(pw_properties_update(props, &SPA_DICT_INIT(items, 2)) == 0); + spa_assert(props->dict.n_items == 3); + spa_assert(!strcmp(pw_properties_get(props, "foo"), "bar")); + spa_assert(!strcmp(pw_properties_get(props, "bar"), "baz")); + spa_assert(!strcmp(pw_properties_get(props, "him"), "too")); + + items[0] = SPA_DICT_ITEM_INIT("bar", "bear"); + items[1] = SPA_DICT_ITEM_INIT("him", "too"); + spa_assert(pw_properties_update(props, &SPA_DICT_INIT(items, 2)) == 1); + spa_assert(props->dict.n_items == 3); + spa_assert(!strcmp(pw_properties_get(props, "foo"), "bar")); + spa_assert(!strcmp(pw_properties_get(props, "bar"), "bear")); + spa_assert(!strcmp(pw_properties_get(props, "him"), "too")); + + items[0] = SPA_DICT_ITEM_INIT("bar", "bear"); + items[1] = SPA_DICT_ITEM_INIT("him", NULL); + spa_assert(pw_properties_update(props, &SPA_DICT_INIT(items, 2)) == 1); + spa_assert(props->dict.n_items == 2); + spa_assert(!strcmp(pw_properties_get(props, "foo"), "bar")); + spa_assert(!strcmp(pw_properties_get(props, "bar"), "bear")); + spa_assert(pw_properties_get(props, "him") == NULL); + + items[0] = SPA_DICT_ITEM_INIT("foo", NULL); + items[1] = SPA_DICT_ITEM_INIT("bar", "beer"); + items[2] = SPA_DICT_ITEM_INIT("him", "her"); + spa_assert(pw_properties_update(props, &SPA_DICT_INIT(items, 3)) == 3); + spa_assert(props->dict.n_items == 2); + spa_assert(pw_properties_get(props, "foo") == NULL); + spa_assert(!strcmp(pw_properties_get(props, "bar"), "beer")); + spa_assert(!strcmp(pw_properties_get(props, "him"), "her")); + + pw_properties_free(props); +} + +static void test_parse(void) +{ + spa_assert(pw_properties_parse_bool("true") == true); + spa_assert(pw_properties_parse_bool("1") == true); + spa_assert(pw_properties_parse_bool("false") == false); + spa_assert(pw_properties_parse_bool("0") == false); + + spa_assert(pw_properties_parse_int("10") == 10); + spa_assert(pw_properties_parse_int("-5") == -5); + spa_assert(pw_properties_parse_int("0700") == 0700); + spa_assert(pw_properties_parse_int("0x700") == 0x700); + spa_assert(pw_properties_parse_int("invalid") == 0); + + spa_assert(pw_properties_parse_int64("10") == 10); + spa_assert(pw_properties_parse_int64("-5") == -5); + spa_assert(pw_properties_parse_int64("0732") == 0732); + spa_assert(pw_properties_parse_int64("0x732") == 0x732); + spa_assert(pw_properties_parse_int64("invalid") == 0); + + spa_assert(pw_properties_parse_uint64("10") == 10); + spa_assert(pw_properties_parse_uint64("0713") == 0713); + spa_assert(pw_properties_parse_uint64("0x713") == 0x713); + spa_assert(pw_properties_parse_uint64("invalid") == 0); + + spa_assert(pw_properties_parse_float("1.234") == 1.234f); + spa_assert(pw_properties_parse_double("1.234") == 1.234); +} + int main(int argc, char *argv[]) { test_abi(); test_empty(); test_set(); + test_setf(); + test_new(); + test_new_dict(); + test_new_string(); + test_update(); + test_parse(); return 0; }