structure: Add GST_SERIALIZE_FLAG_STRICT

It makes serialization succeed only if all values have a type that can
be deserialized.

Sponsored-by: Netflix Inc.
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5355>
This commit is contained in:
Xavier Claessens 2023-09-20 15:34:40 -04:00 committed by GStreamer Marge Bot
parent 899d08722a
commit 9501d64ccd
3 changed files with 46 additions and 2 deletions

View file

@ -2033,6 +2033,7 @@ priv_gst_structure_append_to_gstring (const GstStructure * structure,
guint i, len; guint i, len;
gboolean nested_structs_brackets = gboolean nested_structs_brackets =
!(flags & GST_SERIALIZE_FLAG_BACKWARD_COMPAT); !(flags & GST_SERIALIZE_FLAG_BACKWARD_COMPAT);
gboolean strict = (flags & GST_SERIALIZE_FLAG_STRICT) != 0;
g_return_val_if_fail (s != NULL, FALSE); g_return_val_if_fail (s != NULL, FALSE);
@ -2069,7 +2070,8 @@ priv_gst_structure_append_to_gstring (const GstStructure * structure,
g_string_append_c (s, '['); g_string_append_c (s, '[');
g_string_append (s, g_quark_to_string (substruct->name)); g_string_append (s, g_quark_to_string (substruct->name));
priv_gst_structure_append_to_gstring (substruct, s, flags); if (!priv_gst_structure_append_to_gstring (substruct, s, flags))
return FALSE;
g_string_append_c (s, ']'); g_string_append_c (s, ']');
} else if (nested_structs_brackets } else if (nested_structs_brackets
&& G_VALUE_TYPE (&field->value) == GST_TYPE_CAPS) { && G_VALUE_TYPE (&field->value) == GST_TYPE_CAPS) {
@ -2081,9 +2083,13 @@ priv_gst_structure_append_to_gstring (const GstStructure * structure,
} else if (t) { } else if (t) {
g_string_append (s, t); g_string_append (s, t);
g_free (t); g_free (t);
if (strict && G_VALUE_HOLDS_OBJECT (&field->value))
return FALSE;
} else if (G_TYPE_CHECK_VALUE_TYPE (&field->value, G_TYPE_POINTER)) { } else if (G_TYPE_CHECK_VALUE_TYPE (&field->value, G_TYPE_POINTER)) {
gpointer ptr = g_value_get_pointer (&field->value); gpointer ptr = g_value_get_pointer (&field->value);
if (strict)
return FALSE;
if (!ptr) if (!ptr)
g_string_append (s, "NULL"); g_string_append (s, "NULL");
else else
@ -2093,6 +2099,8 @@ priv_gst_structure_append_to_gstring (const GstStructure * structure,
GST_WARNING ("No value transform to serialize field '%s' of type '%s'", GST_WARNING ("No value transform to serialize field '%s' of type '%s'",
g_quark_to_string (field->name), g_quark_to_string (field->name),
_priv_gst_value_gtype_to_abbr (type)); _priv_gst_value_gtype_to_abbr (type));
if (strict)
return FALSE;
/* TODO(ensonic): don't print NULL if field->value is not empty */ /* TODO(ensonic): don't print NULL if field->value is not empty */
g_string_append (s, "NULL"); g_string_append (s, "NULL");
} }
@ -2168,7 +2176,10 @@ structure_serialize (const GstStructure * structure, GstSerializeFlags flags)
* avoid unnecessary reallocs within GString */ * avoid unnecessary reallocs within GString */
s = g_string_sized_new (STRUCTURE_ESTIMATED_STRING_LEN (structure)); s = g_string_sized_new (STRUCTURE_ESTIMATED_STRING_LEN (structure));
g_string_append (s, g_quark_to_string (structure->name)); g_string_append (s, g_quark_to_string (structure->name));
priv_gst_structure_append_to_gstring (structure, s, flags); if (!priv_gst_structure_append_to_gstring (structure, s, flags)) {
g_string_free (s, TRUE);
return NULL;
}
return g_string_free (s, FALSE); return g_string_free (s, FALSE);
} }

View file

@ -32,11 +32,23 @@ GST_API GType _gst_structure_type;
typedef struct _GstStructure GstStructure; typedef struct _GstStructure GstStructure;
/**
* GST_SERIALIZE_FLAG_STRICT:
*
* Serialization fails if a value cannot be serialized instead of using
* placeholder "NULL" value (e.g. pointers, objects).
*
* Since: 1.24
*/
/** /**
* GstSerializeFlags: * GstSerializeFlags:
* @GST_SERIALIZE_FLAG_NONE: No special flags specified. * @GST_SERIALIZE_FLAG_NONE: No special flags specified.
* @GST_SERIALIZE_FLAG_BACKWARD_COMPAT: Serialize using the old format for * @GST_SERIALIZE_FLAG_BACKWARD_COMPAT: Serialize using the old format for
* nested structures. * nested structures.
* @GST_SERIALIZE_FLAG_STRICT: Serialization fails if a value cannot be
* serialized instead of using placeholder "NULL" value (e.g. pointers,
* objects). (Since 1.24)
* *
* Since: 1.20 * Since: 1.20
*/ */
@ -44,6 +56,7 @@ typedef enum
{ {
GST_SERIALIZE_FLAG_NONE = 0, GST_SERIALIZE_FLAG_NONE = 0,
GST_SERIALIZE_FLAG_BACKWARD_COMPAT = (1 << 0), GST_SERIALIZE_FLAG_BACKWARD_COMPAT = (1 << 0),
GST_SERIALIZE_FLAG_STRICT = (1 << 1),
} GstSerializeFlags; } GstSerializeFlags;
#define GST_TYPE_STRUCTURE (_gst_structure_type) #define GST_TYPE_STRUCTURE (_gst_structure_type)

View file

@ -1034,6 +1034,25 @@ GST_START_TEST (test_flags)
GST_END_TEST; GST_END_TEST;
GST_START_TEST (test_strict)
{
GstStructure *s;
GstElement *bin = gst_bin_new ("mybin");
s = gst_structure_new ("test-struct", "obj", GST_TYPE_BIN, bin, NULL);
fail_unless (s);
fail_if (gst_structure_serialize (s, GST_SERIALIZE_FLAG_STRICT));
gst_structure_free (s);
gst_object_unref (bin);
s = gst_structure_new ("test-struct", "ptr", G_TYPE_POINTER, NULL, NULL);
fail_unless (s);
fail_if (gst_structure_serialize (s, GST_SERIALIZE_FLAG_STRICT));
gst_structure_free (s);
}
GST_END_TEST;
static Suite * static Suite *
gst_structure_suite (void) gst_structure_suite (void)
{ {
@ -1067,6 +1086,7 @@ gst_structure_suite (void)
tcase_add_test (tc_chain, test_filter_and_map_in_place); tcase_add_test (tc_chain, test_filter_and_map_in_place);
tcase_add_test (tc_chain, test_flagset); tcase_add_test (tc_chain, test_flagset);
tcase_add_test (tc_chain, test_flags); tcase_add_test (tc_chain, test_flags);
tcase_add_test (tc_chain, test_strict);
return s; return s;
} }