wireplumber/lib/wp/properties.c

1003 lines
30 KiB
C
Raw Normal View History

/* WirePlumber
*
* Copyright © 2019 Collabora Ltd.
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
/*!
* @file properties.c
*/
/*!
* @struct WpProperties
* @section properties_section Properties
2020-02-17 15:39:19 +02:00
*
* @brief [WpProperties](@ref properties_section) is a data structure that contains
* string key-value pairs, which are used to send/receive/attach arbitrary properties
* to PipeWire objects.
2020-02-17 15:39:19 +02:00
*
* This could be thought of as a hash table with strings as both keys and
* values. However, the reason that this class exists instead of using
* <a href="https://developer.gnome.org/glib/stable/glib-Hash-Tables.html#GHashTable">
* GHashTable</a> directly is that in reality it wraps the PipeWire native
2020-02-17 15:39:19 +02:00
* `struct spa_dict` and `struct pw_properties` and therefore it can be
* easily passed to PipeWire function calls that require a `struct spa_dict *`
* or a `struct pw_properties *` as arguments. Or alternatively, it can easily
* wrap a `struct spa_dict *` or a `struct pw_properties *` that was given
* from the PipeWire API without necessarily doing an expensive copy operation.
*
* [WpProperties](@ref properties_section) normally wraps a `struct pw_properties`,
* unless it was created with wp_properties_new_wrap_dict(), in which case it wraps a
2020-02-17 15:39:19 +02:00
* `struct spa_dict` and it is immutable (you cannot add/remove/modify any
* key-value pair).
*
* In most cases, it actually owns the `struct pw_properties`
* internally and manages its lifetime. The exception to that rule is when
* [WpProperties](@ref properties_section) is constructed with wp_properties_new_wrap(),
* in which case the ownership of the `struct pw_properties` remains outside. This must
2020-02-17 15:39:19 +02:00
* be used with care, as the `struct pw_properties` may be free'ed externally.
*
* [WpProperties](@ref properties_section) is reference-counted with wp_properties_ref() and
2020-02-17 15:39:19 +02:00
* wp_properties_unref().
*
2020-02-17 15:39:19 +02:00
*/
#define G_LOG_DOMAIN "wp-properties"
#include "properties.h"
#include <errno.h>
#include <pipewire/properties.h>
enum {
FLAG_IS_DICT = (1<<1),
FLAG_NO_OWNERSHIP = (1<<2),
};
/*!
* @brief
* @em ref
* @em flags
*/
struct _WpProperties
{
grefcount ref;
guint32 flags;
union {
struct pw_properties *props;
const struct spa_dict *dict;
};
};
G_DEFINE_BOXED_TYPE(WpProperties, wp_properties, wp_properties_ref, wp_properties_unref)
/*!
* @memberof WpProperties
* @brief Creates a new empty properties set
2020-02-17 15:39:19 +02:00
*
* @returns (transfer full): the newly constructed properties set
2020-02-17 15:39:19 +02:00
*/
WpProperties *
wp_properties_new_empty (void)
{
WpProperties * self = g_slice_new0 (WpProperties);
g_ref_count_init (&self->ref);
self->flags = 0;
self->props = pw_properties_new (NULL, NULL);
return self;
}
/*!
* @memberof WpProperties
* @param key: a property name
2020-02-17 15:39:19 +02:00
* @...: a property value, followed by any number of further property
* key-value pairs, followed by %NULL
*
* @brief Constructs a new properties set that contains the given properties
2020-02-17 15:39:19 +02:00
*
* @returns (transfer full): the newly constructed properties set
2020-02-17 15:39:19 +02:00
*/
WpProperties *
wp_properties_new (const gchar * key, ...)
{
WpProperties * self;
va_list varargs;
va_start(varargs, key);
self = wp_properties_new_valist (key, varargs);
va_end(varargs);
return self;
}
/*!
* @memberof WpProperties
* @param key: a property name
* @param args: the variable arguments passed to wp_properties_new()
2020-02-17 15:39:19 +02:00
*
* @brief This is the `va_list` version of wp_properties_new()
2020-02-17 15:39:19 +02:00
*
* @returns (transfer full): the newly constructed properties set
2020-02-17 15:39:19 +02:00
*/
WpProperties *
2020-02-17 15:39:19 +02:00
wp_properties_new_valist (const gchar * key, va_list args)
{
WpProperties * self = wp_properties_new_empty ();
const gchar *value;
while (key != NULL) {
2020-02-17 15:39:19 +02:00
value = va_arg(args, gchar *);
if (value && key[0])
wp_properties_set (self, key, value);
2020-02-17 15:39:19 +02:00
key = va_arg(args, gchar *);
}
return self;
}
/*!
* @memberof WpProperties
* @param str: a string containing a whitespace separated list of key=value pairs
2020-02-17 15:39:19 +02:00
* (ex. "key1=value1 key2=value2")
*
* @brief Constructs a new properties set that contains the properties that can
2020-02-17 15:39:19 +02:00
* be parsed from the given string
*
* @returns (transfer full): the newly constructed properties set
2020-02-17 15:39:19 +02:00
*/
WpProperties *
wp_properties_new_string (const gchar * str)
{
WpProperties * self;
g_return_val_if_fail (str != NULL, NULL);
self = g_slice_new0 (WpProperties);
g_ref_count_init (&self->ref);
self->flags = 0;
self->props = pw_properties_new_string (str);
return self;
}
/*!
* @memberof WpProperties
* @param props: a native `pw_properties` structure to wrap
2020-02-17 15:39:19 +02:00
*
* @brief Constructs a new [WpProperties](@ref properties_section) that wraps the given @em props structure,
* allowing reading properties on that @em props structure through
* the [WpProperties](@ref properties_section) API.
2020-02-17 15:39:19 +02:00
*
* Care must be taken when using this function, since the returned [WpProperties](@ref properties_section)
* object does not own the @em props structure. Therefore, if the owner decides
* to free @em props, the returned [WpProperties](@ref properties_section) will crash when used. In addition,
* the returned [WpProperties](@ref properties_section) object will not try to free @em props when destroyed.
2020-02-17 15:39:19 +02:00
*
* Furthermore, note that the returned [WpProperties](@ref properties_section) object is immutable. That
* means that you cannot add or modify any properties on it, unless you make
* a copy first.
*
* @returns (transfer full): the newly constructed properties set
2020-02-17 15:39:19 +02:00
*/
WpProperties *
wp_properties_new_wrap (const struct pw_properties * props)
{
WpProperties * self;
g_return_val_if_fail (props != NULL, NULL);
self = g_slice_new0 (WpProperties);
g_ref_count_init (&self->ref);
self->flags = FLAG_NO_OWNERSHIP;
self->props = (struct pw_properties *) props;
return self;
}
/*!
* @memberof WpProperties
* @param props: a native `pw_properties` structure to wrap
2020-02-17 15:39:19 +02:00
*
* @brief Constructs a new [WpProperties](@ref properties_section) that wraps the given @em props structure,
* allowing reading & writing properties on that @em props structure through
* the [WpProperties](@ref properties_section) API.
2020-02-17 15:39:19 +02:00
*
* In constrast with wp_properties_new_wrap(), this function assumes ownership
* of the @em props structure, so it will try to free @em props when it is destroyed.
2020-02-17 15:39:19 +02:00
*
* @returns (transfer full): the newly constructed properties set
2020-02-17 15:39:19 +02:00
*/
WpProperties *
wp_properties_new_take (struct pw_properties * props)
{
WpProperties * self;
g_return_val_if_fail (props != NULL, NULL);
self = g_slice_new0 (WpProperties);
g_ref_count_init (&self->ref);
self->flags = 0;
self->props = props;
return self;
}
/*!
* @memberof WpProperties
* @param props: a native `pw_properties` structure to copy
2020-02-17 15:39:19 +02:00
*
* @brief Constructs a new [WpProperties](@ref properties_section) that contains a copy of all the properties
* contained in the given @em props structure.
2020-02-17 15:39:19 +02:00
*
* @returns (transfer full): the newly constructed properties set
2020-02-17 15:39:19 +02:00
*/
WpProperties *
wp_properties_new_copy (const struct pw_properties * props)
{
WpProperties * self;
g_return_val_if_fail (props != NULL, NULL);
self = g_slice_new0 (WpProperties);
g_ref_count_init (&self->ref);
self->flags = 0;
self->props = pw_properties_copy (props);
return self;
}
/*!
* @memberof WpProperties
* @param dict: a native `spa_dict` structure to wrap
2020-02-17 15:39:19 +02:00
*
* @brief Constructs a new [WpProperties](@ref properties_section) that wraps the given @em dict structure,
* allowing reading properties from that @em dict through the [WpProperties](@ref properties_section) API.
2020-02-17 15:39:19 +02:00
*
* Note that the returned object does not own the @em dict, so care must be taken
* not to free it externally while this [WpProperties](@ref properties_section) object is alive.
2020-02-17 15:39:19 +02:00
*
* In addition, note that the returned [WpProperties](@ref properties_section) object is immutable. That
2020-02-17 15:39:19 +02:00
* means that you cannot add or modify any properties on it, since there is
* no defined method for modifying a `struct spa_dict`. If you need to change
* this properties set later, you should make a copy with wp_properties_copy().
*
* @returns (transfer full): the newly constructed properties set
2020-02-17 15:39:19 +02:00
*/
WpProperties *
wp_properties_new_wrap_dict (const struct spa_dict * dict)
{
WpProperties * self;
g_return_val_if_fail (dict != NULL, NULL);
self = g_slice_new0 (WpProperties);
g_ref_count_init (&self->ref);
self->flags = FLAG_NO_OWNERSHIP | FLAG_IS_DICT;
self->dict = dict;
return self;
}
/*!
* @memberof WpProperties
* @param dict: a native `spa_dict` structure to copy
2020-02-17 15:39:19 +02:00
*
* @brief Constructs a new [WpProperties](@ref properties_section) that contains a copy of all the properties
* contained in the given @em dict structure.
2020-02-17 15:39:19 +02:00
*
* @returns (transfer full): the newly constructed properties set
2020-02-17 15:39:19 +02:00
*/
WpProperties *
wp_properties_new_copy_dict (const struct spa_dict * dict)
{
WpProperties * self;
g_return_val_if_fail (dict != NULL, NULL);
self = g_slice_new0 (WpProperties);
g_ref_count_init (&self->ref);
self->flags = 0;
self->props = pw_properties_new_dict (dict);
return self;
}
/*!
* @memberof WpProperties
* @param other: a properties object
2020-02-17 15:39:19 +02:00
*
* @brief Constructs and returns a new [WpProperties](@ref properties_section) object that contains a copy
* of all the properties contained in @em other.
2020-02-17 15:39:19 +02:00
*
* @returns (transfer full): the newly constructed properties set
2020-02-17 15:39:19 +02:00
*/
WpProperties *
wp_properties_copy (WpProperties * other)
{
return wp_properties_new_copy_dict (wp_properties_peek_dict (other));
}
static void
wp_properties_free (WpProperties * self)
{
if (!(self->flags & FLAG_NO_OWNERSHIP))
pw_properties_free (self->props);
g_slice_free (WpProperties, self);
}
/*!
* @memberof WpProperties
* @param self: a properties object
2020-02-17 15:39:19 +02:00
*
* @returns (transfer full): @em self with an additional reference count on it
2020-02-17 15:39:19 +02:00
*/
WpProperties *
wp_properties_ref (WpProperties * self)
{
g_ref_count_inc (&self->ref);
return self;
}
/*!
* @memberof WpProperties
* @param self: (transfer full): a properties object
2020-02-17 15:39:19 +02:00
*
* @brief Decreases the reference count on @em self and frees it when the ref count
2020-02-17 15:39:19 +02:00
* reaches zero.
*/
void
wp_properties_unref (WpProperties * self)
{
if (g_ref_count_dec (&self->ref))
wp_properties_free (self);
}
/*!
* @memberof WpProperties
* @param self: (transfer full): a properties object
*
* @brief Ensures that the given properties set is uniquely owned, which means:
* - its reference count is 1
* - it is not wrapping a native `spa_dict` or `pw_properties` object
*
* If @em self is not uniquely owned already, then it is unrefed and a copy of
* it is returned instead. You should always consider @em self as unsafe to use
* after this call and you should use the returned object instead.
*
* @returns (transfer full): the uniquely owned properties object
*/
WpProperties *
wp_properties_ensure_unique_owner (WpProperties * self)
{
if (!g_ref_count_compare (&self->ref, 1) ||
self->flags & (FLAG_IS_DICT | FLAG_NO_OWNERSHIP))
{
WpProperties *copy = wp_properties_copy (self);
wp_properties_unref (self);
return copy;
}
return self;
}
/*!
* @memberof WpProperties
* @param self: a properties object
* @param props: a properties set that contains properties to update
*
* @brief Updates (adds new or modifies existing) properties in @em self, using the
* given @em props as a source. Any properties that are not contained in @em props
* are left untouched.
*
* @returns the number of properties that were changed
*/
gint
wp_properties_update (WpProperties * self, WpProperties * props)
{
g_return_val_if_fail (self != NULL, -EINVAL);
g_return_val_if_fail (!(self->flags & FLAG_IS_DICT), -EINVAL);
g_return_val_if_fail (!(self->flags & FLAG_NO_OWNERSHIP), -EINVAL);
return pw_properties_update (self->props, wp_properties_peek_dict (props));
}
/*!
* @memberof WpProperties
* @param self: a properties object
* @param dict: a `spa_dict` that contains properties to update
2020-02-17 15:39:19 +02:00
*
* @brief Updates (adds new or modifies existing) properties in @em self, using the
* given @em dict as a source. Any properties that are not contained in @em dict
2020-02-17 15:39:19 +02:00
* are left untouched.
*
* @returns the number of properties that were changed
2020-02-17 15:39:19 +02:00
*/
gint
wp_properties_update_from_dict (WpProperties * self,
const struct spa_dict * dict)
{
g_return_val_if_fail (self != NULL, -EINVAL);
g_return_val_if_fail (!(self->flags & FLAG_IS_DICT), -EINVAL);
g_return_val_if_fail (!(self->flags & FLAG_NO_OWNERSHIP), -EINVAL);
return pw_properties_update (self->props, dict);
}
/*!
* @memberof WpProperties
* @param self: a properties object
* @param props: a properties set that contains properties to add
*
* @brief Adds new properties in @em self, using the given @em props as a source.
* Properties (keys) from @em props that are already contained in @em self
* are not modified, unlike what happens with wp_properties_update().
* Properties in @em self that are not contained in @em props are left untouched.
*
* @returns the number of properties that were changed
*/
gint
wp_properties_add (WpProperties * self, WpProperties * props)
{
g_return_val_if_fail (self != NULL, -EINVAL);
g_return_val_if_fail (!(self->flags & FLAG_IS_DICT), -EINVAL);
g_return_val_if_fail (!(self->flags & FLAG_NO_OWNERSHIP), -EINVAL);
return pw_properties_add (self->props, wp_properties_peek_dict (props));
}
/*!
* @memberof WpProperties
* @param self: a properties object
* @param dict: a `spa_dict` that contains properties to add
*
* @brief Adds new properties in @em self, using the given @em dict as a source.
* Properties (keys) from @em dict that are already contained in @em self
* are not modified, unlike what happens with wp_properties_update_from_dict().
* Properties in @em self that are not contained in @em dict are left untouched.
*
* @returns the number of properties that were changed
*/
gint
wp_properties_add_from_dict (WpProperties * self,
const struct spa_dict * dict)
{
g_return_val_if_fail (self != NULL, -EINVAL);
g_return_val_if_fail (!(self->flags & FLAG_IS_DICT), -EINVAL);
g_return_val_if_fail (!(self->flags & FLAG_NO_OWNERSHIP), -EINVAL);
return pw_properties_add (self->props, dict);
}
/*!
* @memberof WpProperties
* @param self: a properties set
* @param props: a properties set that contains properties to update
* @param key1: a property to update
* @...: a list of additional properties to update, followed by %NULL
*
* @brief Updates (adds new or modifies existing) properties in @em self, using the
* given @em props as a source.
* Unlike wp_properties_update(), this function only updates properties that
* have one of the specified keys; the rest is left untouched.
*
* @returns the number of properties that were changed
*/
gint
wp_properties_update_keys (WpProperties * self, WpProperties * props,
const gchar * key1, ...)
{
gint changed = 0;
const gchar *value;
g_return_val_if_fail (self != NULL, -EINVAL);
g_return_val_if_fail (!(self->flags & FLAG_IS_DICT), -EINVAL);
g_return_val_if_fail (!(self->flags & FLAG_NO_OWNERSHIP), -EINVAL);
va_list args;
va_start (args, key1);
for (; key1; key1 = va_arg (args, const gchar *)) {
if ((value = wp_properties_get (props, key1)) != NULL)
changed += wp_properties_set (self, key1, value);
}
return changed;
}
/*!
* @memberof WpProperties
* @param self: a properties set
* @param dict: a `spa_dict` that contains properties to update
* @param key1: a property to update
* @...: a list of additional properties to update, followed by %NULL
*
* @brief Updates (adds new or modifies existing) properties in @em self, using the
* given @em dict as a source.
* Unlike wp_properties_update_from_dict(), this function only updates
* properties that have one of the specified keys; the rest is left untouched.
*
* @returns the number of properties that were changed
*/
gint
wp_properties_update_keys_from_dict (WpProperties * self,
const struct spa_dict * dict, const gchar * key1, ...)
{
gint changed = 0;
const gchar *value;
g_return_val_if_fail (self != NULL, -EINVAL);
g_return_val_if_fail (!(self->flags & FLAG_IS_DICT), -EINVAL);
g_return_val_if_fail (!(self->flags & FLAG_NO_OWNERSHIP), -EINVAL);
va_list args;
va_start (args, key1);
for (; key1; key1 = va_arg (args, const gchar *)) {
if ((value = spa_dict_lookup (dict, key1)) != NULL)
changed += wp_properties_set (self, key1, value);
}
return changed;
}
/*!
* @memberof WpProperties
* @param self: a properties set
* @param props: a properties set that contains properties to update
* @param keys: (array zero-terminated=1): the properties to update
2020-02-17 15:39:19 +02:00
*
* @brief The same as wp_properties_update_keys(), using a NULL-terminated array
* for specifying the keys to update
2020-02-17 15:39:19 +02:00
*
* @returns the number of properties that were changed
2020-02-17 15:39:19 +02:00
*/
gint
wp_properties_update_keys_array (WpProperties * self, WpProperties * props,
const gchar * keys[])
{
g_return_val_if_fail (self != NULL, -EINVAL);
g_return_val_if_fail (!(self->flags & FLAG_IS_DICT), -EINVAL);
g_return_val_if_fail (!(self->flags & FLAG_NO_OWNERSHIP), -EINVAL);
return pw_properties_update_keys (self->props,
wp_properties_peek_dict (props), keys);
}
/*!
* @memberof WpProperties
* @param self: a properties set
* @param props: a properties set that contains properties to add
* @param key1: a property to add
* @...: a list of additional properties to add, followed by %NULL
*
* @brief Adds new properties in @em self, using the given @em props as a source.
* Unlike wp_properties_add(), this function only adds properties that
* have one of the specified keys; the rest is left untouched.
*
* @returns the number of properties that were changed
*/
gint
wp_properties_add_keys (WpProperties * self, WpProperties * props,
const gchar * key1, ...)
{
gint changed = 0;
const gchar *value;
g_return_val_if_fail (self != NULL, -EINVAL);
g_return_val_if_fail (!(self->flags & FLAG_IS_DICT), -EINVAL);
g_return_val_if_fail (!(self->flags & FLAG_NO_OWNERSHIP), -EINVAL);
va_list args;
va_start (args, key1);
for (; key1; key1 = va_arg (args, const gchar *)) {
if ((value = wp_properties_get (props, key1)) == NULL)
continue;
if (wp_properties_get (self, key1) == NULL)
changed += wp_properties_set (self, key1, value);
}
return changed;
}
/*!
* @memberof WpProperties
* @param self: a properties set
* @param dict: a `spa_dict` that contains properties to add
* @param key1: a property to add
* @...: a list of additional properties to add, followed by %NULL
2020-02-17 15:39:19 +02:00
*
* @brief Adds new properties in @em self, using the given @em dict as a source.
* Unlike wp_properties_add_from_dict(), this function only adds
* properties that have one of the specified keys; the rest is left untouched.
2020-02-17 15:39:19 +02:00
*
* @returns the number of properties that were changed
2020-02-17 15:39:19 +02:00
*/
gint
wp_properties_add_keys_from_dict (WpProperties * self,
const struct spa_dict * dict, const gchar * key1, ...)
{
gint changed = 0;
const gchar *value;
g_return_val_if_fail (self != NULL, -EINVAL);
g_return_val_if_fail (!(self->flags & FLAG_IS_DICT), -EINVAL);
g_return_val_if_fail (!(self->flags & FLAG_NO_OWNERSHIP), -EINVAL);
va_list args;
va_start (args, key1);
for (; key1; key1 = va_arg (args, const gchar *)) {
if ((value = spa_dict_lookup (dict, key1)) == NULL)
continue;
if (wp_properties_get (self, key1) == NULL)
changed += wp_properties_set (self, key1, value);
}
return changed;
}
/*!
* @memberof WpProperties
* @param self: a properties set
* @param props: a properties set that contains properties to add
* @param keys: (array zero-terminated=1): the properties to add
*
* @brief The same as wp_properties_add_keys(), using a NULL-terminated array
* for specifying the keys to add
*
* @returns the number of properties that were changed
*/
gint
wp_properties_add_keys_array (WpProperties * self, WpProperties * props,
const gchar * keys[])
{
g_return_val_if_fail (self != NULL, -EINVAL);
g_return_val_if_fail (!(self->flags & FLAG_IS_DICT), -EINVAL);
g_return_val_if_fail (!(self->flags & FLAG_NO_OWNERSHIP), -EINVAL);
return pw_properties_add_keys (self->props,
wp_properties_peek_dict (props), keys);
}
/*!
* @memberof WpProperties
* @param self: a properties object
* @param key: a property key
2020-02-17 15:39:19 +02:00
*
* @returns (transfer none) (nullable): the value of the property identified
* with @em key, or %NULL if this property is not contained in @em self
2020-02-17 15:39:19 +02:00
*/
const gchar *
wp_properties_get (WpProperties * self, const gchar * key)
{
g_return_val_if_fail (self != NULL, NULL);
g_return_val_if_fail (key != NULL, NULL);
return spa_dict_lookup (wp_properties_peek_dict (self), key);
}
/*!
* @memberof WpProperties
* @param self: a properties object
* @param key: a property key
* @param value: (nullable): a property value
2020-02-17 15:39:19 +02:00
*
* @brief Sets the given property @em key - @em value pair on @em self. If the property
2020-02-17 15:39:19 +02:00
* already existed, the value is overwritten with the new one.
*
* If the @em value is %NULL, then the specified property is removed from @em self
2020-02-17 15:39:19 +02:00
*
* @returns %1 if the property was changed. %0 if nothing was changed because
2020-02-17 15:39:19 +02:00
* the property already existed with the same value or because the key to
* remove did not exist.
*/
gint
wp_properties_set (WpProperties * self, const gchar * key,
const gchar * value)
{
g_return_val_if_fail (self != NULL, -EINVAL);
g_return_val_if_fail (!(self->flags & FLAG_IS_DICT), -EINVAL);
g_return_val_if_fail (!(self->flags & FLAG_NO_OWNERSHIP), -EINVAL);
return pw_properties_set (self->props, key, value);
}
/*!
* @memberof WpProperties
* @param self: a properties object
* @param key: a property key
* @param format: a printf-style format to be formatted and set as a value for
* this property @em key
* @...: arguments for @em format
2020-02-17 15:39:19 +02:00
*
* @brief Formats the given @em format string with the specified arguments and sets the
* result as a value of the property specified with @em key
2020-02-17 15:39:19 +02:00
*
* @returns %1 if the property was changed. %0 if nothing was changed because
2020-02-17 15:39:19 +02:00
* the property already existed with the same value
*/
gint
wp_properties_setf (WpProperties * self, const gchar * key,
const gchar * format, ...)
{
gint res;
va_list varargs;
va_start (varargs, format);
res = wp_properties_setf_valist (self, key, format, varargs);
va_end (varargs);
return res;
}
/*!
* @memberof WpProperties
* @param self: a properties object
* @param key: a property key
* @param format: a printf-style format to be formatted and set as a value for
* this property @em key
* @param args: the variable arguments passed to wp_properties_setf()
2020-02-17 15:39:19 +02:00
*
* @brief This is the `va_list` version of wp_properties_setf()
2020-02-17 15:39:19 +02:00
*
* @returns %1 if the property was changed. %0 if nothing was changed because
2020-02-17 15:39:19 +02:00
* the property already existed with the same value
*/
gint
wp_properties_setf_valist (WpProperties * self, const gchar * key,
const gchar * format, va_list args)
{
g_return_val_if_fail (self != NULL, -EINVAL);
g_return_val_if_fail (!(self->flags & FLAG_IS_DICT), -EINVAL);
g_return_val_if_fail (!(self->flags & FLAG_NO_OWNERSHIP), -EINVAL);
return pw_properties_setva (self->props, key, format, args);
}
struct dict_iterator_data
{
WpProperties *properties;
const struct spa_dict_item *item;
};
static void
dict_iterator_reset (WpIterator *it)
{
struct dict_iterator_data *it_data = wp_iterator_get_user_data (it);
it_data->item = wp_properties_peek_dict (it_data->properties)->items;
}
static gboolean
dict_iterator_next (WpIterator *it, GValue *item)
{
struct dict_iterator_data *it_data = wp_iterator_get_user_data (it);
const struct spa_dict *dict = wp_properties_peek_dict (it_data->properties);
if ((it_data->item - dict->items) < dict->n_items) {
g_value_init (item, G_TYPE_POINTER);
2020-06-02 10:45:08 +03:00
g_value_set_pointer (item, (gpointer) it_data->item);
it_data->item++;
return TRUE;
}
return FALSE;
}
static gboolean
dict_iterator_fold (WpIterator *it, WpIteratorFoldFunc func, GValue *ret,
gpointer data)
{
struct dict_iterator_data *it_data = wp_iterator_get_user_data (it);
const struct spa_dict *dict = wp_properties_peek_dict (it_data->properties);
const struct spa_dict_item *i;
spa_dict_for_each (i, dict) {
g_auto (GValue) item = G_VALUE_INIT;
g_value_init (&item, G_TYPE_POINTER);
2020-06-02 10:45:08 +03:00
g_value_set_pointer (&item, (gpointer) i);
if (!func (&item, ret, data))
return FALSE;
}
return TRUE;
}
static void
dict_iterator_finalize (WpIterator *it)
{
struct dict_iterator_data *it_data = wp_iterator_get_user_data (it);
wp_properties_unref (it_data->properties);
}
static const WpIteratorMethods dict_iterator_methods = {
.version = WP_ITERATOR_METHODS_VERSION,
.reset = dict_iterator_reset,
.next = dict_iterator_next,
.fold = dict_iterator_fold,
.finalize = dict_iterator_finalize,
};
/*!
* @memberof WpProperties
* @param self: a properties object
*
* @returns (transfer full): an iterator that iterates over the properties.
* Use wp_properties_iterator_item_get_key() and
* wp_properties_iterator_item_get_value() to parse the items returned by
* this iterator.
*/
WpIterator *
wp_properties_new_iterator (WpProperties * self)
{
g_autoptr (WpIterator) it = NULL;
struct dict_iterator_data *it_data;
g_return_val_if_fail (self != NULL, NULL);
it = wp_iterator_new (&dict_iterator_methods,
sizeof (struct dict_iterator_data));
it_data = wp_iterator_get_user_data (it);
it_data->properties = wp_properties_ref (self);
it_data->item = wp_properties_peek_dict (it_data->properties)->items;
return g_steal_pointer (&it);
}
/*!
* @memberof WpProperties
* @param item: a
* <a href="https://developer.gnome.org/gobject/stable/gobject-Generic-values.html#GValue">
* GValue</a> that was returned from the [WpProperties](@ref properties_section) of
* wp_properties_new_iterator()
*
* @returns (transfer none): the property key of the @em item
*/
const gchar *
wp_properties_iterator_item_get_key (const GValue * item)
{
const struct spa_dict_item *dict_item = g_value_get_pointer (item);
g_return_val_if_fail (dict_item != NULL, NULL);
return dict_item->key;
}
/*!
* @memberof WpProperties
*
* @param item: a
* <a href="https://developer.gnome.org/gobject/stable/gobject-Generic-values.html#GValue">
* GValue</a> that was returned from the [WpProperties](@ref properties_section) of
* wp_properties_new_iterator()
*
* @returns (transfer none): the property value of the @em item
*/
const gchar *
wp_properties_iterator_item_get_value (const GValue * item)
{
const struct spa_dict_item *dict_item = g_value_get_pointer (item);
g_return_val_if_fail (dict_item != NULL, NULL);
return dict_item->value;
}
/*!
* @memberof WpProperties
* @param self: a properties object
*
*/
void
wp_properties_sort (WpProperties * self)
{
g_return_if_fail (self != NULL);
g_return_if_fail (!(self->flags & FLAG_IS_DICT));
g_return_if_fail (!(self->flags & FLAG_NO_OWNERSHIP));
return spa_dict_qsort (&self->props->dict);
}
/*!
* @memberof WpProperties
* @param self: a properties object
2020-02-17 15:39:19 +02:00
*
* @returns (transfer none): the internal properties set as a `struct spa_dict *`
2020-02-17 15:39:19 +02:00
*/
const struct spa_dict *
wp_properties_peek_dict (WpProperties * self)
{
g_return_val_if_fail (self != NULL, NULL);
return (self->flags & FLAG_IS_DICT) ? self->dict : &self->props->dict;
}
/*!
* @memberof WpProperties
* @param self: a properties object
2020-02-17 15:39:19 +02:00
*
* @returns (transfer full): a copy of the properties in @em self
2020-02-17 15:39:19 +02:00
* as a `struct pw_properties`
*/
struct pw_properties *
wp_properties_to_pw_properties (WpProperties * self)
{
g_return_val_if_fail (self != NULL, NULL);
return pw_properties_new_dict (wp_properties_peek_dict (self));
}
/*!
* @memberof WpProperties
* @param self: (transfer full): a properties object
*
* @brief Similar to wp_properties_to_pw_properties(), but this method avoids making
* a copy of the properties by returning the `struct pw_properties` that is
* stored internally and then freeing the [WpProperties](@ref properties_section) wrapper.
*
* If @em self is not uniquely owned (see wp_properties_ensure_unique_owner()),
* then this method does make a copy and is the same as
* wp_properties_to_pw_properties(), performance-wise.
*
* @returns (transfer full): the properties in @em self as a `struct pw_properties`
*/
struct pw_properties *
wp_properties_unref_and_take_pw_properties (WpProperties * self)
{
g_return_val_if_fail (self != NULL, NULL);
g_autoptr (WpProperties) unique = wp_properties_ensure_unique_owner (self);
/* set the flag so that unref-ing @em unique will not destroy unique->props */
unique->flags = FLAG_NO_OWNERSHIP;
return unique->props;
}
/*!
* @memberof WpProperties
* @param self: a properties object
* @param other: a set of properties to match
2020-02-17 15:39:19 +02:00
*
* @brief Checks if all property values contained in @em other are matching with the
* values in @em self.
2020-02-17 15:39:19 +02:00
*
* If a property is contained in @em other and not in @em self, the result is not
* matched. If a property is contained in both sets, then the value of the
* property in @em other is interpreted as a glob-style pattern
* (using g_pattern_match_simple()) and the value in @em self is checked to
2020-02-17 15:39:19 +02:00
* see if it matches with this pattern.
*
* @returns %TRUE if all matches were successfull, %FALSE if at least one
2020-02-17 15:39:19 +02:00
* property value did not match
*/
gboolean
wp_properties_matches (WpProperties * self, WpProperties *other)
{
const struct spa_dict * dict;
const struct spa_dict_item *item;
const gchar *value;
g_return_val_if_fail (self != NULL, FALSE);
/* Check if the property values match the ones from 'self' */
dict = wp_properties_peek_dict (other);
spa_dict_for_each(item, dict) {
value = wp_properties_get (self, item->key);
if (!value || !g_pattern_match_simple (value, item->value))
return FALSE;
}
return TRUE;
}