mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-25 15:06:14 +01:00
gobject: Add g_{param_spec,signal}_is_valid_name() functions
Making this validation code public allows projects to validate a GParamSpec name before creating it. While hard-coded GParamSpec don't need this, we can't afford crashing the main program for dynamically generated GParamSpec from user-created data. In such case, we will need to validate the param names and return errors instead of trying to create a GParamSpec with invalid names. Includes modifications from Philip Withnall and Emmanuele Bassi to rearrange the new function addition and split it into one function for GParamSpecs and one for GSignals.
This commit is contained in:
parent
fb1e416a32
commit
13d1697b67
@ -521,6 +521,7 @@ g_param_value_defaults
|
||||
g_param_value_validate
|
||||
g_param_value_convert
|
||||
g_param_values_cmp
|
||||
g_param_spec_is_valid_name
|
||||
g_param_spec_get_name
|
||||
g_param_spec_get_name_quark
|
||||
g_param_spec_get_nick
|
||||
@ -859,6 +860,7 @@ g_signal_override_class_handler
|
||||
g_signal_chain_from_overridden_handler
|
||||
g_signal_add_emission_hook
|
||||
g_signal_remove_emission_hook
|
||||
g_signal_is_valid_name
|
||||
g_signal_parse_name
|
||||
g_signal_get_invocation_hint
|
||||
g_signal_type_cclosure_new
|
||||
|
@ -381,20 +381,34 @@ is_canonical (const gchar *key)
|
||||
return (strchr (key, '_') == NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_valid_property_name (const gchar *key)
|
||||
/**
|
||||
* g_param_spec_is_valid_name:
|
||||
* @name: the canonical name of the property
|
||||
*
|
||||
* Validate a property name for a #GParamSpec. This can be useful for
|
||||
* dynamically-generated properties which need to be validated at run-time
|
||||
* before actually trying to create them.
|
||||
*
|
||||
* See [canonical parameter names][canonical-parameter-names] for details of
|
||||
* the rules for valid names.
|
||||
*
|
||||
* Returns: %TRUE if @name is a valid property name, %FALSE otherwise.
|
||||
* Since: 2.66
|
||||
*/
|
||||
gboolean
|
||||
g_param_spec_is_valid_name (const gchar *name)
|
||||
{
|
||||
const gchar *p;
|
||||
|
||||
/* First character must be a letter. */
|
||||
if ((key[0] < 'A' || key[0] > 'Z') &&
|
||||
(key[0] < 'a' || key[0] > 'z'))
|
||||
if ((name[0] < 'A' || name[0] > 'Z') &&
|
||||
(name[0] < 'a' || name[0] > 'z'))
|
||||
return FALSE;
|
||||
|
||||
for (p = key; *p != 0; p++)
|
||||
for (p = name; *p != 0; p++)
|
||||
{
|
||||
const gchar c = *p;
|
||||
|
||||
|
||||
if (c != '-' && c != '_' &&
|
||||
(c < '0' || c > '9') &&
|
||||
(c < 'A' || c > 'Z') &&
|
||||
@ -439,7 +453,7 @@ g_param_spec_internal (GType param_type,
|
||||
|
||||
g_return_val_if_fail (G_TYPE_IS_PARAM (param_type) && param_type != G_TYPE_PARAM, NULL);
|
||||
g_return_val_if_fail (name != NULL, NULL);
|
||||
g_return_val_if_fail (is_valid_property_name (name), NULL);
|
||||
g_return_val_if_fail (g_param_spec_is_valid_name (name), NULL);
|
||||
g_return_val_if_fail (!(flags & G_PARAM_STATIC_NAME) || is_canonical (name), NULL);
|
||||
|
||||
pspec = (gpointer) g_type_create_instance (param_type);
|
||||
|
@ -395,6 +395,9 @@ GLIB_AVAILABLE_IN_ALL
|
||||
GType g_param_type_register_static (const gchar *name,
|
||||
const GParamSpecTypeInfo *pspec_info);
|
||||
|
||||
GLIB_AVAILABLE_IN_2_66
|
||||
gboolean g_param_spec_is_valid_name (const gchar *name);
|
||||
|
||||
/* For registering builting types */
|
||||
GType _g_param_type_register_static_constant (const gchar *name,
|
||||
const GParamSpecTypeInfo *pspec_info,
|
||||
|
@ -367,33 +367,29 @@ is_canonical (const gchar *key)
|
||||
return (strchr (key, '_') == NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_valid_signal_name (const gchar *key)
|
||||
/**
|
||||
* g_signal_is_valid_name:
|
||||
* @name: the canonical name of the signal
|
||||
*
|
||||
* Validate a signal name. This can be useful for dynamically-generated signals
|
||||
* which need to be validated at run-time before actually trying to create them.
|
||||
*
|
||||
* See [canonical parameter names][canonical-parameter-names] for details of
|
||||
* the rules for valid names. The rules for signal names are the same as those
|
||||
* for property names.
|
||||
*
|
||||
* Returns: %TRUE if @name is a valid signal name, %FALSE otherwise.
|
||||
* Since: 2.66
|
||||
*/
|
||||
gboolean
|
||||
g_signal_is_valid_name (const gchar *name)
|
||||
{
|
||||
const gchar *p;
|
||||
|
||||
/* FIXME: We allow this, against our own documentation (the leading `-` is
|
||||
* invalid), because GTK has historically used this. */
|
||||
if (g_str_equal (key, "-gtk-private-changed"))
|
||||
if (g_str_equal (name, "-gtk-private-changed"))
|
||||
return TRUE;
|
||||
|
||||
/* First character must be a letter. */
|
||||
if ((key[0] < 'A' || key[0] > 'Z') &&
|
||||
(key[0] < 'a' || key[0] > 'z'))
|
||||
return FALSE;
|
||||
|
||||
for (p = key; *p != 0; p++)
|
||||
{
|
||||
const gchar c = *p;
|
||||
|
||||
if (c != '-' && c != '_' &&
|
||||
(c < '0' || c > '9') &&
|
||||
(c < 'A' || c > 'Z') &&
|
||||
(c < 'a' || c > 'z'))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
return g_param_spec_is_valid_name (name);
|
||||
}
|
||||
|
||||
static inline guint
|
||||
@ -1325,7 +1321,7 @@ g_signal_lookup (const gchar *name,
|
||||
if (!g_type_name (itype))
|
||||
g_warning (G_STRLOC ": unable to look up signal \"%s\" for invalid type id '%"G_GSIZE_FORMAT"'",
|
||||
name, itype);
|
||||
else if (!is_valid_signal_name (name))
|
||||
else if (!g_signal_is_valid_name (name))
|
||||
g_warning (G_STRLOC ": unable to look up invalid signal name \"%s\" on type '%s'",
|
||||
name, g_type_name (itype));
|
||||
}
|
||||
@ -1712,7 +1708,7 @@ g_signal_newv (const gchar *signal_name,
|
||||
GSignalCVaMarshaller va_marshaller;
|
||||
|
||||
g_return_val_if_fail (signal_name != NULL, 0);
|
||||
g_return_val_if_fail (is_valid_signal_name (signal_name), 0);
|
||||
g_return_val_if_fail (g_signal_is_valid_name (signal_name), 0);
|
||||
g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (itype) || G_TYPE_IS_INTERFACE (itype), 0);
|
||||
if (n_params)
|
||||
g_return_val_if_fail (param_types != NULL, 0);
|
||||
|
@ -338,6 +338,8 @@ void g_signal_query (guint signal_id,
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
guint* g_signal_list_ids (GType itype,
|
||||
guint *n_ids);
|
||||
GLIB_AVAILABLE_IN_2_66
|
||||
gboolean g_signal_is_valid_name (const gchar *name);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
gboolean g_signal_parse_name (const gchar *detailed_signal,
|
||||
GType itype,
|
||||
|
@ -126,7 +126,7 @@ test_param_invalid_name (gconstpointer test_data)
|
||||
|
||||
g_test_trap_subprocess (NULL, 0, 0);
|
||||
g_test_trap_assert_failed ();
|
||||
g_test_trap_assert_stderr ("*CRITICAL*is_valid_property_name (name)*");
|
||||
g_test_trap_assert_stderr ("*CRITICAL*g_param_spec_is_valid_name (name)*");
|
||||
}
|
||||
|
||||
static void
|
||||
@ -846,6 +846,32 @@ test_param_default (void)
|
||||
g_param_spec_unref (param);
|
||||
}
|
||||
|
||||
static void
|
||||
test_param_is_valid_name (void)
|
||||
{
|
||||
const gchar *valid_names[] =
|
||||
{
|
||||
"property",
|
||||
"i",
|
||||
"multiple-segments",
|
||||
"segment0-SEGMENT1",
|
||||
"using_underscores",
|
||||
};
|
||||
const gchar *invalid_names[] =
|
||||
{
|
||||
"",
|
||||
"7zip",
|
||||
"my_int:hello",
|
||||
};
|
||||
gsize i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (valid_names); i++)
|
||||
g_assert_true (g_param_spec_is_valid_name (valid_names[i]));
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (invalid_names); i++)
|
||||
g_assert_false (g_param_spec_is_valid_name (invalid_names[i]));
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
@ -881,6 +907,7 @@ main (int argc, char *argv[])
|
||||
|
||||
g_test_add_func ("/value/transform", test_value_transform);
|
||||
g_test_add_func ("/param/default", test_param_default);
|
||||
g_test_add_func ("/param/is-valid-name", test_param_is_valid_name);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
@ -1449,7 +1449,33 @@ test_signals_invalid_name (gconstpointer test_data)
|
||||
|
||||
g_test_trap_subprocess (NULL, 0, 0);
|
||||
g_test_trap_assert_failed ();
|
||||
g_test_trap_assert_stderr ("*CRITICAL*is_valid_signal_name (signal_name)*");
|
||||
g_test_trap_assert_stderr ("*CRITICAL*g_signal_is_valid_name (signal_name)*");
|
||||
}
|
||||
|
||||
static void
|
||||
test_signal_is_valid_name (void)
|
||||
{
|
||||
const gchar *valid_names[] =
|
||||
{
|
||||
"signal",
|
||||
"i",
|
||||
"multiple-segments",
|
||||
"segment0-SEGMENT1",
|
||||
"using_underscores",
|
||||
};
|
||||
const gchar *invalid_names[] =
|
||||
{
|
||||
"",
|
||||
"7zip",
|
||||
"my_int:hello",
|
||||
};
|
||||
gsize i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (valid_names); i++)
|
||||
g_assert_true (g_signal_is_valid_name (valid_names[i]));
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (invalid_names); i++)
|
||||
g_assert_false (g_signal_is_valid_name (invalid_names[i]));
|
||||
}
|
||||
|
||||
/* --- */
|
||||
@ -1485,6 +1511,7 @@ main (int argc,
|
||||
g_test_add_data_func ("/gobject/signals/invalid-name/colon", "my_int:hello", test_signals_invalid_name);
|
||||
g_test_add_data_func ("/gobject/signals/invalid-name/first-char", "7zip", test_signals_invalid_name);
|
||||
g_test_add_data_func ("/gobject/signals/invalid-name/empty", "", test_signals_invalid_name);
|
||||
g_test_add_func ("/gobject/signals/is-valid-name", test_signal_is_valid_name);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user