diff options
author | Victor Toso <victortoso@gnome.org> | 2021-03-19 23:39:49 +0100 |
---|---|---|
committer | Victor Toso <victortoso@gnome.org> | 2021-03-20 13:03:58 +0100 |
commit | b50dc15f76e89838abde8403fe5f72b55d66496d (patch) | |
tree | 408b9775c615bf3eed1d3118d0937ea6a3d6076d | |
parent | 5878cad4ba11bd52b09a3bea5cf081c9ccae1c42 (diff) | |
download | grilo-b50dc15f76e89838abde8403fe5f72b55d66496d.tar.gz |
operation-options: Fix storing numeric limits
GrlOperationOptions needs to validate user input against the maximum
and minimum values of a metadata-key of numeric type. For numeric
types, the follow should always be true:
@min_value_registered <= @min_value_user
@min_value_user <= @max_value_user
@max_value_user <= @max_value_registered.
So, we do implement some sort generic CLAMP for numeric types. Sadly,
glib does not provide as of yet a g_value_cmp() [0] so we need to
write a bit more code to make this checks in Grilo today.
The followup commit adds a unit test.
Related: https://gitlab.gnome.org/GNOME/grilo/-/issues/140
[0] https://gitlab.gnome.org/GNOME/glib/-/issues/129
-rw-r--r-- | src/grl-metadata-key.c | 1 | ||||
-rw-r--r-- | src/grl-operation-options.c | 48 | ||||
-rw-r--r-- | src/grl-registry-priv.h | 11 | ||||
-rw-r--r-- | src/grl-registry.c | 75 |
4 files changed, 124 insertions, 11 deletions
diff --git a/src/grl-metadata-key.c b/src/grl-metadata-key.c index ce60105..342b4f4 100644 --- a/src/grl-metadata-key.c +++ b/src/grl-metadata-key.c @@ -785,3 +785,4 @@ grl_metadata_key_list_new(GrlKeyID first_key, ...) return g_list_reverse (key_list); } + diff --git a/src/grl-operation-options.c b/src/grl-operation-options.c index ec50d65..7296f47 100644 --- a/src/grl-operation-options.c +++ b/src/grl-operation-options.c @@ -32,7 +32,7 @@ #include <grl-value-helper.h> #include <grl-range-value.h> #include <grl-log.h> -#include <grl-registry.h> +#include <grl-registry-priv.h> #include "grl-operation-options-priv.h" #include "grl-type-builtins.h" @@ -705,6 +705,10 @@ grl_operation_options_get_key_filter_list (GrlOperationOptions *options) * * If @max_value is %NULL, then filter is "@key >= @min_value". * + * Note that @key will always respect the limits defined at creation time. + * e.g: Core's GRL_METADATA_KEY_ORIENTATION has "max = 359" and "min = 0", + * user can set "@max_value = 180" but "@max_value = 720" would be ignored. + * * Returns: %TRUE on success * * Since: 0.2.0 @@ -716,22 +720,44 @@ grl_operation_options_set_key_range_filter_value (GrlOperationOptions *options, GValue *max_value) { gboolean ret; + GrlRegistry *registry; + GValue min_registered = G_VALUE_INIT; + GValue max_registered = G_VALUE_INIT; \ + gboolean min_changed = FALSE; + gboolean max_changed = FALSE; ret = (options->priv->caps == NULL) || grl_caps_is_key_range_filter (options->priv->caps, key); - if (ret) { - if (min_value || max_value) { - grl_range_value_hashtable_insert (options->priv->key_range_filter, - GRLKEYID_TO_POINTER (key), - min_value, max_value); - } else { - g_hash_table_remove (options->priv->key_range_filter, - GRLKEYID_TO_POINTER (key)); - } + if (!ret) { + return FALSE; } - return ret; + if (!min_value && !max_value) { + g_hash_table_remove (options->priv->key_range_filter, + GRLKEYID_TO_POINTER (key)); + return TRUE; + } + + /* Does a CLAMP for GValue of numeric types so new min and max values are + * within min-max values as registered per metadata-key */ + registry = grl_registry_get_default (); + if (grl_registry_metadata_key_get_limits(registry, key, &min_registered, &max_registered)) { + max_changed = grl_registry_metadata_key_clamp(registry, key, &min_registered, max_value, &max_registered); + min_changed = grl_registry_metadata_key_clamp(registry, key, &min_registered, min_value, &max_registered); + } else { + GRL_DEBUG("Can't get limits of this key"); + } + + if (min_changed || max_changed) { + GRL_DEBUG("@min_value=%c @max_value=%c changes due metadata-key limits", + min_changed ? 'y':'n', max_changed ? 'y':'n'); + } + + grl_range_value_hashtable_insert (options->priv->key_range_filter, + GRLKEYID_TO_POINTER (key), + min_value, max_value); + return TRUE; } /** diff --git a/src/grl-registry-priv.h b/src/grl-registry-priv.h index a692f51..2d6c277 100644 --- a/src/grl-registry-priv.h +++ b/src/grl-registry-priv.h @@ -47,4 +47,15 @@ GrlKeyID grl_registry_register_or_lookup_metadata_key (GrlRegistry *registry, const GValue *value, GrlKeyID bind_key); +gboolean grl_registry_metadata_key_get_limits(GrlRegistry *registry, + GrlKeyID key, + GValue *min, + GValue *max); + +gboolean grl_registry_metadata_key_clamp(GrlRegistry *registry, + GrlKeyID key, + GValue *min, + GValue *value, + GValue *max); + #endif /* _GRL_REGISTRY_PRIV_H_ */ diff --git a/src/grl-registry.c b/src/grl-registry.c index 12e0031..51223e9 100644 --- a/src/grl-registry.c +++ b/src/grl-registry.c @@ -2238,3 +2238,78 @@ bail: return ret; } + + +G_GNUC_INTERNAL gboolean +grl_registry_metadata_key_get_limits(GrlRegistry *registry, + GrlKeyID key, + GValue *min, + GValue *max) +{ + GParamSpec *key_pspec; + const gchar *key_name; + GType key_type; + + key_name = key_id_handler_get_name (®istry->priv->key_id_handler, key); + if (!key_name) { + return FALSE; + } + + key_pspec = g_hash_table_lookup (registry->priv->system_keys, key_name); + if (!key_pspec) { + return FALSE; + } + + key_type = G_PARAM_SPEC_VALUE_TYPE (key_pspec); + +#define CHECK_NUMERIC_AND_SET_VALUE_LIMITS(value_type, numeric_type, getter, cast_type) { \ + if (value_type == numeric_type) { \ + g_value_init (min, numeric_type); \ + g_value_init (max, numeric_type); \ + g_value_set_##getter (min, (cast_type (key_pspec))->minimum); \ + g_value_set_##getter (max, (cast_type (key_pspec))->maximum); \ + return TRUE; \ + } \ +} + + CHECK_NUMERIC_AND_SET_VALUE_LIMITS (key_type, G_TYPE_INT, int, G_PARAM_SPEC_INT); + CHECK_NUMERIC_AND_SET_VALUE_LIMITS (key_type, G_TYPE_LONG, long, G_PARAM_SPEC_LONG); + CHECK_NUMERIC_AND_SET_VALUE_LIMITS (key_type, G_TYPE_INT64, int64, G_PARAM_SPEC_INT64); + CHECK_NUMERIC_AND_SET_VALUE_LIMITS (key_type, G_TYPE_CHAR, schar, G_PARAM_SPEC_CHAR); + CHECK_NUMERIC_AND_SET_VALUE_LIMITS (key_type, G_TYPE_UINT, uint, G_PARAM_SPEC_UINT); + CHECK_NUMERIC_AND_SET_VALUE_LIMITS (key_type, G_TYPE_ULONG, ulong, G_PARAM_SPEC_ULONG); + CHECK_NUMERIC_AND_SET_VALUE_LIMITS (key_type, G_TYPE_UINT64, uint64, G_PARAM_SPEC_UINT64); + CHECK_NUMERIC_AND_SET_VALUE_LIMITS (key_type, G_TYPE_UCHAR, uchar, G_PARAM_SPEC_UCHAR); + CHECK_NUMERIC_AND_SET_VALUE_LIMITS (key_type, G_TYPE_FLOAT, float, G_PARAM_SPEC_FLOAT); + CHECK_NUMERIC_AND_SET_VALUE_LIMITS (key_type, G_TYPE_DOUBLE, double, G_PARAM_SPEC_DOUBLE); + return FALSE; +} + +G_GNUC_INTERNAL gboolean +grl_registry_metadata_key_clamp(GrlRegistry *registry, + GrlKeyID key, + GValue *min, + GValue *value, + GValue *max) +{ + const gchar *key_name; + + key_name = key_id_handler_get_name (®istry->priv->key_id_handler, key); + if (key_name) { + GParamSpec *key_pspec; + + key_pspec = g_hash_table_lookup (registry->priv->system_keys, key_name); + if (key_pspec) { + if (g_param_values_cmp(key_pspec, value, min) < 0) { + GRL_DEBUG("reset value to min"); + g_value_transform(min, value); + return TRUE; + } else if (g_param_values_cmp(key_pspec, value, max) > 0) { + GRL_DEBUG("reset value to max"); + g_value_transform(max, value); + return TRUE; + } + } + } + return FALSE; +} |