gstvalue: Add (de)serialize of G_TYPE_STRV
This allows setting strv properties from gst-launch-1.0, such as uris in uriplaylistbin. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8438>
This commit is contained in:
parent
a54568a93c
commit
e06e977304
@ -8133,6 +8133,115 @@ gst_value_transform_object_string (const GValue * src_value,
|
||||
dest_value->data[0].v_pointer = str;
|
||||
}
|
||||
|
||||
/*********
|
||||
* GStrv *
|
||||
*********/
|
||||
|
||||
static gchar *
|
||||
gst_value_serialize_strv (const GValue * value)
|
||||
{
|
||||
const gchar **strv = g_value_get_boxed (value);
|
||||
GString *str = g_string_new ("<");
|
||||
|
||||
while (*strv != NULL) {
|
||||
const gchar *s = *strv;
|
||||
|
||||
/* Add separator if it's not the first string */
|
||||
if (str->len > 1)
|
||||
g_string_append_c (str, ',');
|
||||
|
||||
g_string_append_c (str, '\"');
|
||||
|
||||
/* Escape \ to \\ and " to \" */
|
||||
while (*s != '\0') {
|
||||
if (*s == '\"' || *s == '\\')
|
||||
g_string_append_c (str, '\\');
|
||||
g_string_append_c (str, *s);
|
||||
s++;
|
||||
}
|
||||
|
||||
g_string_append_c (str, '\"');
|
||||
|
||||
strv++;
|
||||
}
|
||||
|
||||
g_string_append_c (str, '>');
|
||||
|
||||
return g_string_free (str, FALSE);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_value_deserialize_strv (GValue * dest, const gchar * s)
|
||||
{
|
||||
/* If it's not starting with '<' assume it's a simple comma separated list
|
||||
* with no escaping. Otherwise assume the format <"foo","bar"> with spaces
|
||||
* allowed between delimiters and \ for escaping. */
|
||||
if (*s != '<') {
|
||||
g_value_take_boxed (dest, g_strsplit (s, ",", -1));
|
||||
return TRUE;
|
||||
}
|
||||
s++;
|
||||
|
||||
while (g_ascii_isspace (*s))
|
||||
s++;
|
||||
|
||||
GPtrArray *strv = g_ptr_array_new_with_free_func (g_free);
|
||||
while (*s != '>') {
|
||||
if (*s != '\"')
|
||||
goto error;
|
||||
s++;
|
||||
|
||||
/* Find string end and check if we need to unescape it */
|
||||
gboolean escaped = FALSE;
|
||||
const gchar *start = s;
|
||||
while (*s != '\"') {
|
||||
if (*s == '\\') {
|
||||
escaped = TRUE;
|
||||
s++;
|
||||
}
|
||||
if (*s == '\0')
|
||||
goto error;
|
||||
s++;
|
||||
}
|
||||
s++;
|
||||
|
||||
/* Always copy the whole string and unescape inplace */
|
||||
gchar *substr = g_strndup (start, s - start - 1);
|
||||
if (escaped) {
|
||||
gchar *p1 = substr;
|
||||
const gchar *p2 = substr;
|
||||
while (*p2 != '\0') {
|
||||
if (*p2 == '\\')
|
||||
p2++;
|
||||
*p1 = *p2;
|
||||
p1++;
|
||||
p2++;
|
||||
}
|
||||
*p1 = '\0';
|
||||
}
|
||||
|
||||
g_ptr_array_add (strv, substr);
|
||||
|
||||
while (g_ascii_isspace (*s))
|
||||
s++;
|
||||
|
||||
if (*s == ',') {
|
||||
s++;
|
||||
while (g_ascii_isspace (*s))
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
g_ptr_array_add (strv, NULL);
|
||||
g_value_take_boxed (dest, g_ptr_array_free (strv, FALSE));
|
||||
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
g_ptr_array_free (strv, TRUE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GTypeInfo _info = {
|
||||
0, NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, NULL,
|
||||
};
|
||||
@ -8363,10 +8472,12 @@ _priv_gst_value_initialize (void)
|
||||
REGISTER_SERIALIZATION (gst_bitmask_get_type (), bitmask);
|
||||
REGISTER_SERIALIZATION (gst_structure_get_type (), structure);
|
||||
REGISTER_SERIALIZATION (gst_flagset_get_type (), flagset);
|
||||
REGISTER_SERIALIZATION (G_TYPE_GTYPE, gtype);
|
||||
|
||||
REGISTER_SERIALIZATION_NO_COMPARE (gst_segment_get_type (), segment);
|
||||
REGISTER_SERIALIZATION_NO_COMPARE (gst_caps_features_get_type (),
|
||||
caps_features);
|
||||
REGISTER_SERIALIZATION_NO_COMPARE (G_TYPE_STRV, strv);
|
||||
|
||||
REGISTER_SERIALIZATION_COMPARE_ONLY (gst_allocation_params_get_type (),
|
||||
allocation_params);
|
||||
@ -8374,26 +8485,18 @@ _priv_gst_value_initialize (void)
|
||||
|
||||
REGISTER_SERIALIZATION_CONST (G_TYPE_DOUBLE, double);
|
||||
REGISTER_SERIALIZATION_CONST (G_TYPE_FLOAT, float);
|
||||
|
||||
REGISTER_SERIALIZATION_CONST (G_TYPE_STRING, string);
|
||||
REGISTER_SERIALIZATION_CONST (G_TYPE_BOOLEAN, boolean);
|
||||
REGISTER_SERIALIZATION_CONST (G_TYPE_ENUM, enum);
|
||||
|
||||
REGISTER_SERIALIZATION_CONST (G_TYPE_FLAGS, gflags);
|
||||
|
||||
REGISTER_SERIALIZATION_CONST (G_TYPE_INT, int);
|
||||
|
||||
REGISTER_SERIALIZATION_CONST (G_TYPE_INT64, int64);
|
||||
REGISTER_SERIALIZATION_CONST (G_TYPE_LONG, long);
|
||||
|
||||
REGISTER_SERIALIZATION_CONST (G_TYPE_UINT, uint);
|
||||
REGISTER_SERIALIZATION_CONST (G_TYPE_UINT64, uint64);
|
||||
REGISTER_SERIALIZATION_CONST (G_TYPE_ULONG, ulong);
|
||||
|
||||
REGISTER_SERIALIZATION_CONST (G_TYPE_UCHAR, uchar);
|
||||
|
||||
REGISTER_SERIALIZATION (G_TYPE_GTYPE, gtype);
|
||||
|
||||
REGISTER_SERIALIZATION_WITH_PSPEC (gst_value_list_get_type (), value_list);
|
||||
REGISTER_SERIALIZATION_WITH_PSPEC (gst_value_array_get_type (), value_array);
|
||||
|
||||
|
@ -4001,6 +4001,68 @@ GST_START_TEST (test_serialize_deserialize_sample)
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_serialize_deserialize_strv)
|
||||
{
|
||||
GValue v = G_VALUE_INIT;
|
||||
g_value_init (&v, G_TYPE_STRV);
|
||||
|
||||
fail_if (gst_value_deserialize (&v, "<"));
|
||||
fail_if (gst_value_deserialize (&v, "< foo"));
|
||||
fail_if (gst_value_deserialize (&v, "< \"foo"));
|
||||
fail_if (gst_value_deserialize (&v, "< \"foo\\"));
|
||||
fail_if (gst_value_deserialize (&v, "< \"foo\""));
|
||||
fail_if (gst_value_deserialize (&v, "< \"foo\","));
|
||||
|
||||
struct
|
||||
{
|
||||
const gchar *str;
|
||||
const gchar *deserialized[3];
|
||||
const gchar *serialized;
|
||||
} tests[] = {
|
||||
{"", {NULL}, "<>"},
|
||||
{"foo", {"foo", NULL}, "<\"foo\">"},
|
||||
{"foo ", {"foo ", NULL}, "<\"foo \">"},
|
||||
{"foo ,", {"foo ", "", NULL}, "<\"foo \",\"\">"},
|
||||
{"foo , ", {"foo ", " ", NULL}, "<\"foo \",\" \">"},
|
||||
{"foo,bar", {"foo", "bar", NULL}, "<\"foo\",\"bar\">"},
|
||||
{"<>", {NULL}, "<>"},
|
||||
{"<\"\">", {"", NULL}, "<\"\">"},
|
||||
{"< \" \" > ", {" ", NULL}, "<\" \">"},
|
||||
{"<\"foo\",> ", {"foo", NULL}, "<\"foo\">"},
|
||||
{"<\"foo\" , > ", {"foo", NULL}, "<\"foo\">"},
|
||||
{"<\"foo\",\"bar\"> ", {"foo", "bar", NULL}, "<\"foo\",\"bar\">"},
|
||||
{"<\"foo\" , \"bar\"> ", {"foo", "bar", NULL}, "<\"foo\",\"bar\">"},
|
||||
{"<\"\\\"\\\\,<>\">", {"\"\\,<>", NULL}, "<\"\\\"\\\\,<>\">"},
|
||||
};
|
||||
|
||||
for (int i = 0; i < G_N_ELEMENTS (tests); i++) {
|
||||
const gchar *str = tests[i].str;
|
||||
const gchar *const *deserialized = tests[i].deserialized;
|
||||
|
||||
/* Deserialize */
|
||||
if (!gst_value_deserialize (&v, str))
|
||||
fail ("Failed to deserialize %dth '%s'", i, str);
|
||||
const gchar *const *strv = g_value_get_boxed (&v);
|
||||
if (!g_strv_equal (strv, deserialized)) {
|
||||
gchar *strv_str = g_strjoinv (", ", (gchar **) strv);
|
||||
gchar *expected_str = g_strjoinv (", ", (gchar **) deserialized);
|
||||
fail ("Deserialized %dth '%s' to '%s', expected '%s'", i, str, strv_str,
|
||||
expected_str);
|
||||
}
|
||||
|
||||
/* Re-serialize */
|
||||
gchar *serialized = gst_value_serialize (&v);
|
||||
if (!g_str_equal (serialized, tests[i].serialized))
|
||||
fail ("Serialized %dth '%s' to '%s', expected '%s'", i, str, serialized,
|
||||
tests[i].serialized);
|
||||
g_free (serialized);
|
||||
|
||||
g_value_reset (&v);
|
||||
}
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static Suite *
|
||||
gst_value_suite (void)
|
||||
{
|
||||
@ -4063,6 +4125,7 @@ gst_value_suite (void)
|
||||
tcase_add_test (tc_chain, test_serialize_deserialize_caps_features);
|
||||
tcase_add_test (tc_chain, test_serialize_deserialize_tag_list);
|
||||
tcase_add_test (tc_chain, test_serialize_deserialize_sample);
|
||||
tcase_add_test (tc_chain, test_serialize_deserialize_strv);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user