diff --git a/gst/gstvalue.c b/gst/gstvalue.c index e4edab96dd..b406f50123 100644 --- a/gst/gstvalue.c +++ b/gst/gstvalue.c @@ -2243,6 +2243,8 @@ gst_value_deserialize_caps (GValue * dest, const gchar * s) GstCaps *caps; if (*s != '"') { + /* this can happen if caps are ANY, EMPTY, or only contains a single + * empty structure */ caps = gst_caps_from_string (s); } else { gchar *str = gst_string_unwrap (s); @@ -2802,7 +2804,7 @@ _priv_gst_value_parse_value (gchar * str, }; int i; - if (G_UNLIKELY (!_priv_gst_value_parse_string (s, &value_end, &s, TRUE))) + if (G_UNLIKELY (!_priv_gst_value_parse_string (s, &value_end, &s, FALSE))) return FALSE; /* Set NULL terminator for deserialization */ value_s = g_strndup (value_s, value_end - value_s); @@ -2817,8 +2819,7 @@ _priv_gst_value_parse_value (gchar * str, } else { g_value_init (value, type); - if (G_UNLIKELY (!_priv_gst_value_parse_string (s, &value_end, &s, - (type != G_TYPE_STRING)))) + if (G_UNLIKELY (!_priv_gst_value_parse_string (s, &value_end, &s, FALSE))) return FALSE; /* Set NULL terminator for deserialization */ value_s = g_strndup (value_s, value_end - value_s); @@ -2878,14 +2879,32 @@ gst_value_serialize_segment (const GValue * value) } static gboolean -gst_value_deserialize_segment (GValue * dest, const gchar * s) +gst_value_deserialize_segment_internal (GValue * dest, const gchar * s, + gboolean unescape) { GstStructure *str; GstSegment seg; gboolean res; + gsize len; + gchar *t; - str = gst_structure_from_string (s, NULL); - if (str == NULL) + if (unescape) { + len = strlen (s); + if (G_UNLIKELY (*s != '"' || len < 2 || s[len - 1] != '"')) { + /* "\"" is not an accepted string, so len must be at least 2 */ + GST_ERROR ("Failed deserializing segement: expected string to start and " + "end with '\"'"); + return FALSE; + } + t = g_strdup (s + 1); + t[len - 2] = '\0'; + /* removed trailing '"' */ + str = gst_structure_from_string (t, NULL); + g_free (t); + } else { + str = gst_structure_from_string (s, NULL); + } + if (G_UNLIKELY (str == NULL)) return FALSE; res = gst_structure_id_get (str, @@ -2908,6 +2927,12 @@ gst_value_deserialize_segment (GValue * dest, const gchar * s) return res; } +static gboolean +gst_value_deserialize_segment (GValue * dest, const gchar * s) +{ + return gst_value_deserialize_segment_internal (dest, s, TRUE); +} + /**************** * GstStructure * ****************/ @@ -2952,6 +2977,8 @@ gst_value_serialize_structure (const GValue * value) GstStructure *structure = g_value_get_boxed (value); return priv_gst_string_take_and_wrap (gst_structure_to_string (structure)); + /* string should always end up being wrapped, since a structure string + * ends in a ';' character */ } static gboolean @@ -2960,6 +2987,14 @@ gst_value_deserialize_structure (GValue * dest, const gchar * s) GstStructure *structure; if (*s != '"') { + /* the output of gst_value_serialize_structure would never produce + * such a string, but a user may pass to gst_structure_from_string + * the string: + * name, sub=(GstStructure)sub-name, val=(int)5; + * and expect sub to be read as an *empty* structure with the name + * sub-name. Similar to + * name, caps=(GstCaps)video/x-raw, val=(int)5; + * which gst_structure_to_string can produce. */ structure = gst_structure_from_string (s, NULL); } else { gchar *str = gst_string_unwrap (s); @@ -3048,6 +3083,9 @@ gst_value_deserialize_caps_features (GValue * dest, const gchar * s) GstCapsFeatures *features; if (*s != '"') { + /* This can happen if gst_caps_features_to_string only returns + * ALL, NONE, or a single features name, which means it is not + * actually wrapped by priv_gst_string_take_and_wrap */ features = gst_caps_features_from_string (s); } else { gchar *str = gst_string_unwrap (s); @@ -3086,6 +3124,13 @@ gst_value_deserialize_tag_list (GValue * dest, const gchar * s) GstTagList *taglist; if (*s != '"') { + /* the output of gst_value_serialize_tag_list would never produce + * such a string, but a user may pass to gst_structure_from_string + * the string: + * name, list=(GstTagList)taglist, val=(int)5; + * and expect list to be read as an *empty* tag list. Similar to + * name, caps=(GstCaps)video/x-raw, val=(int)5; + * which gst_structure_to_string can produce. */ taglist = gst_tag_list_new_from_string (s); } else { gchar *str = gst_string_unwrap (s); @@ -3110,6 +3155,8 @@ gst_value_serialize_tag_list (const GValue * value) GstTagList *taglist = g_value_get_boxed (value); return priv_gst_string_take_and_wrap (gst_tag_list_to_string (taglist)); + /* string should always end up being wrapped, since a taglist (structure) + * string ends in a ';' character */ } @@ -3367,7 +3414,7 @@ gst_value_deserialize_sample (GValue * dest, const gchar * s) g_strdelimit (fields[2], "_", '='); g_base64_decode_inplace (fields[2], &outlen); GST_TRACE ("segment : %s", fields[2]); - if (!gst_value_deserialize_segment (&sval, fields[2])) + if (!gst_value_deserialize_segment_internal (&sval, fields[2], FALSE)) goto fail; } diff --git a/tests/check/gst/gstvalue.c b/tests/check/gst/gstvalue.c index e7d6e53406..25ec621a2a 100644 --- a/tests/check/gst/gstvalue.c +++ b/tests/check/gst/gstvalue.c @@ -3294,31 +3294,30 @@ GST_START_TEST (test_structure_ops) const gchar *op; gint ret; GType str_type; - const gchar *str_result; } comparisons[] = { /* *INDENT-OFF* */ - {"foo,bar=(int)1", "foo,bar=(int)1", "compare", GST_VALUE_EQUAL, 0, NULL}, - {"foo,bar=(int)1", "foo,bar=(int)1", "is_subset", TRUE, 0, NULL}, - {"foo,bar=(int)1", "foo,bar=(int)1", "intersect", TRUE, GST_TYPE_STRUCTURE, "foo,bar=(int)1"}, - {"foo,bar=(int)1", "foo,bar=(int)1", "union", TRUE, GST_TYPE_STRUCTURE, "foo,bar=(int)1"}, - {"foo,bar=(int)[1,2]", "foo,bar=(int)1", "compare", GST_VALUE_UNORDERED, 0, NULL}, - {"foo,bar=(int)[1,2]", "foo,bar=(int)1", "is_subset", FALSE, 0, NULL}, - {"foo,bar=(int)[1,2]", "foo,bar=(int)1", "intersect", TRUE, GST_TYPE_STRUCTURE, "foo,bar=(int)1"}, - {"foo,bar=(int)[1,2]", "foo,bar=(int)1", "union", TRUE, GST_TYPE_STRUCTURE, "foo,bar=(int)[1,2]"}, - {"foo,bar=(int)1", "foo,bar=(int)[1,2]", "compare", GST_VALUE_UNORDERED, 0, NULL}, - {"foo,bar=(int)1", "foo,bar=(int)[1,2]", "is_subset", TRUE, 0, NULL}, - {"foo,bar=(int)1", "foo,bar=(int)[1,2]", "intersect", TRUE, GST_TYPE_STRUCTURE, "foo,bar=(int)1"}, - {"foo,bar=(int)1", "foo,bar=(int)[1,2]", "union", TRUE, GST_TYPE_STRUCTURE, "foo,bar=(int)[1,2]"}, - {"foo,bar=(int)1", "foo,bar=(int)2", "compare", GST_VALUE_UNORDERED, 0, NULL}, - {"foo,bar=(int)1", "foo,bar=(int)2", "is_subset", FALSE, 0, NULL}, - {"foo,bar=(int)1", "foo,bar=(int)2", "intersect", FALSE, 0, NULL}, - {"foo,bar=(int)1", "foo,bar=(int)2", "union", TRUE, GST_TYPE_STRUCTURE, "foo,bar=(int)[1,2]"}, - {"foo,bar=(int)1", "baz,bar=(int)1", "compare", GST_VALUE_UNORDERED, 0, NULL}, - {"foo,bar=(int)1", "baz,bar=(int)1", "is_subset", FALSE, 0, NULL}, - {"foo,bar=(int)1", "baz,bar=(int)1", "intersect", FALSE, 0, NULL}, + {"foo,bar=(int)1", "foo,bar=(int)1", "compare", GST_VALUE_EQUAL, 0}, + {"foo,bar=(int)1", "foo,bar=(int)1", "is_subset", TRUE, 0}, + {"foo,bar=(int)1", "foo,bar=(int)1", "intersect", TRUE, GST_TYPE_STRUCTURE}, + {"foo,bar=(int)1", "foo,bar=(int)1", "union", TRUE, GST_TYPE_STRUCTURE}, + {"foo,bar=(int)[1,2]", "foo,bar=(int)1", "compare", GST_VALUE_UNORDERED, 0}, + {"foo,bar=(int)[1,2]", "foo,bar=(int)1", "is_subset", FALSE, 0}, + {"foo,bar=(int)[1,2]", "foo,bar=(int)1", "intersect", TRUE, GST_TYPE_STRUCTURE}, + {"foo,bar=(int)[1,2]", "foo,bar=(int)1", "union", TRUE, GST_TYPE_STRUCTURE}, + {"foo,bar=(int)1", "foo,bar=(int)[1,2]", "compare", GST_VALUE_UNORDERED, 0}, + {"foo,bar=(int)1", "foo,bar=(int)[1,2]", "is_subset", TRUE, 0}, + {"foo,bar=(int)1", "foo,bar=(int)[1,2]", "intersect", TRUE, GST_TYPE_STRUCTURE}, + {"foo,bar=(int)1", "foo,bar=(int)[1,2]", "union", TRUE, GST_TYPE_STRUCTURE}, + {"foo,bar=(int)1", "foo,bar=(int)2", "compare", GST_VALUE_UNORDERED, 0}, + {"foo,bar=(int)1", "foo,bar=(int)2", "is_subset", FALSE, 0}, + {"foo,bar=(int)1", "foo,bar=(int)2", "intersect", FALSE, 0}, + {"foo,bar=(int)1", "foo,bar=(int)2", "union", TRUE, GST_TYPE_STRUCTURE}, + {"foo,bar=(int)1", "baz,bar=(int)1", "compare", GST_VALUE_UNORDERED, 0}, + {"foo,bar=(int)1", "baz,bar=(int)1", "is_subset", FALSE, 0}, + {"foo,bar=(int)1", "baz,bar=(int)1", "intersect", FALSE, 0}, #if 0 /* deserializing lists is not implemented (but this should still work!) */ - {"foo,bar=(int)1", "baz,bar=(int)1", "union", TRUE, G_TYPE_LIST, "{foo,bar=(int)1;, baz,bar=(int)1;}"}, + {"foo,bar=(int)1", "baz,bar=(int)1", "union", TRUE, G_TYPE_LIST}, #endif /* *INDENT-ON* */ }; @@ -3333,8 +3332,7 @@ GST_START_TEST (test_structure_ops) fail_unless (s2 != NULL); GST_DEBUG ("checking %s with structure1 %" GST_PTR_FORMAT " structure2 %" - GST_PTR_FORMAT " is %d, %s", comparisons[i].op, s1, s2, - comparisons[i].ret, comparisons[i].str_result); + GST_PTR_FORMAT " is %d", comparisons[i].op, s1, s2, comparisons[i].ret); g_value_init (&v1, GST_TYPE_STRUCTURE); gst_value_set_structure (&v1, s1); @@ -3357,11 +3355,10 @@ GST_START_TEST (test_structure_ops) str = gst_value_serialize (&v3); GST_LOG ("result %s", str); - g_free (str); g_value_init (&result, comparisons[i].str_type); - fail_unless (gst_value_deserialize (&result, - comparisons[i].str_result)); + fail_unless (gst_value_deserialize (&result, str)); + g_free (str); fail_unless (gst_value_compare (&result, &v3) == GST_VALUE_EQUAL); g_value_unset (&v3); g_value_unset (&result);