Don't forbid the empty string "" in generic structures, only in taglists.
Properly allow the NULL string by adding special cases for serialising
and deserialising it. prop1=(string)NULL is the NULL string,
prop1=(string)"NULL" is the actual string with the value "NULL"
s = g_value_get_string (&field->value);
/* only check for NULL strings in taglists, as they are allowed in message
* structs, e.g. error message debug strings */
- if (G_UNLIKELY (s == NULL && IS_TAGLIST (structure))) {
- g_warning ("Trying to set NULL string on field '%s' on taglist. "
- "Please file a bug.", g_quark_to_string (field->name));
- g_value_unset (&field->value);
- return;
- } else if (G_UNLIKELY (s != NULL && *s == '\0')) {
- /* empty strings never make sense */
- g_warning ("Trying to set empty string on %s field '%s'. Please file a "
- "bug.", IS_TAGLIST (structure) ? "taglist" : "structure",
- g_quark_to_string (field->name));
- g_value_unset (&field->value);
- return;
+ if (G_UNLIKELY (IS_TAGLIST (structure) && (s == NULL || *s == '\0'))) {
+ if (s == NULL) {
+ g_warning ("Trying to set NULL string on field '%s' on taglist. "
+ "Please file a bug.", g_quark_to_string (field->name));
+ g_value_unset (&field->value);
+ return;
+ } else {
+ /* empty strings never make sense */
+ g_warning ("Trying to set empty string on taglist field '%s'. "
+ "Please file a bug.", g_quark_to_string (field->name));
+ g_value_unset (&field->value);
+ return;
+ }
} else if (G_UNLIKELY (s != NULL && !g_utf8_validate (s, -1, NULL))) {
g_warning ("Trying to set string on %s field '%s', but string is not "
"valid UTF-8. Please file a bug.",
g_string_append_len (s, "=(", 2);
g_string_append (s, gst_structure_to_abbr (type));
g_string_append_c (s, ')');
- g_string_append (s, GST_STR_NULL (t));
+ g_string_append (s, t == NULL ? "NULL" : t);
g_free (t);
}
* THIS FUNCTION MODIFIES THE STRING AND DETECTS INSIDE A NONTERMINATED STRING
*/
static gboolean
-gst_structure_parse_string (gchar * s, gchar ** end, gchar ** next)
+gst_structure_parse_string (gchar * s, gchar ** end, gchar ** next,
+ gboolean unescape)
{
gchar *w;
return ret;
}
- w = s;
- s++;
- while (*s != '"') {
- if (*s == 0)
- return FALSE;
-
- if (*s == '\\') {
+ if (unescape) {
+ w = s;
+ s++;
+ while (*s != '"') {
+ if (G_UNLIKELY (*s == 0))
+ return FALSE;
+ if (G_UNLIKELY (*s == '\\'))
+ s++;
+ *w = *s;
+ w++;
s++;
}
-
- *w = *s;
- w++;
s++;
+ } else {
+ /* Find the closing quotes */
+ s++;
+ while (*s != '"') {
+ if (G_UNLIKELY (*s == 0))
+ return FALSE;
+ if (G_UNLIKELY (*s == '\\'))
+ s++;
+ s++;
+ }
+ s++;
+ w = s;
}
- s++;
*end = w;
*next = s;
ret = gst_structure_parse_array (s, &s, value, type);
} else {
value_s = s;
- if (G_UNLIKELY (!gst_structure_parse_string (s, &value_end, &s)))
- return FALSE;
- c = *value_end;
- *value_end = '\0';
if (G_UNLIKELY (type == G_TYPE_INVALID)) {
GType try_types[] =
{ G_TYPE_INT, G_TYPE_DOUBLE, GST_TYPE_FRACTION, G_TYPE_BOOLEAN,
};
int i;
+ if (G_UNLIKELY (!gst_structure_parse_string (s, &value_end, &s, TRUE)))
+ return FALSE;
+ /* Set NULL terminator for deserialization */
+ c = *value_end;
+ *value_end = '\0';
+
for (i = 0; i < G_N_ELEMENTS (try_types); i++) {
g_value_init (value, try_types[i]);
ret = gst_value_deserialize (value, value_s);
} else {
g_value_init (value, type);
+ if (G_UNLIKELY (!gst_structure_parse_string (s, &value_end, &s,
+ (type != G_TYPE_STRING))))
+ return FALSE;
+ /* Set NULL terminator for deserialization */
+ c = *value_end;
+ *value_end = '\0';
+
ret = gst_value_deserialize (value, value_s);
if (G_UNLIKELY (!ret))
g_value_unset (value);
r++;
name = r;
- if (G_UNLIKELY (!gst_structure_parse_string (r, &w, &r))) {
+ if (G_UNLIKELY (!gst_structure_parse_string (r, &w, &r, TRUE))) {
GST_WARNING ("Failed to parse structure string");
goto error;
}
static gint
gst_value_compare_string (const GValue * value1, const GValue * value2)
{
- if (!value1->data[0].v_pointer || !value2->data[0].v_pointer) {
- return GST_VALUE_UNORDERED;
+ if (G_UNLIKELY (!value1->data[0].v_pointer || !value2->data[0].v_pointer)) {
+ /* if only one is NULL, no match - otherwise both NULL == EQUAL */
+ if (value1->data[0].v_pointer != value2->data[0].v_pointer)
+ return GST_VALUE_UNORDERED;
} else {
int x = strcmp (value1->data[0].v_pointer, value2->data[0].v_pointer);
return GST_VALUE_LESS_THAN;
if (x > 0)
return GST_VALUE_GREATER_THAN;
- return GST_VALUE_EQUAL;
}
+
+ return GST_VALUE_EQUAL;
}
static int
int len;
gboolean wrap = FALSE;
- if (s == NULL)
+ if (G_UNLIKELY (s == NULL))
return -1;
+ /* Special case: the actual string NULL needs wrapping */
+ if (G_UNLIKELY (strcmp (s, "NULL") == 0))
+ return 4;
+
len = 0;
while (*s) {
if (GST_ASCII_IS_STRING (*s)) {
s++;
}
- return wrap ? len : -1;
+ /* Wrap the string if we found something that needs
+ * wrapping, or the empty string (len == 0) */
+ return (wrap || len == 0) ? len : -1;
}
static gchar *
*e++ = '\"';
*e = 0;
+ g_assert (e - d <= len + 3);
return d;
}
{
int len = gst_string_measure_wrapping (s);
- if (len < 0)
+ if (G_LIKELY (len < 0))
return g_strdup (s);
return gst_string_wrap_inner (s, len);
gchar *out;
int len = gst_string_measure_wrapping (s);
- if (len < 0)
+ if (G_LIKELY (len < 0))
return s;
out = gst_string_wrap_inner (s, len);
static gboolean
gst_value_deserialize_string (GValue * dest, const gchar * s)
{
- if (*s != '"') {
+ if (G_UNLIKELY (strcmp (s, "NULL") == 0)) {
+ g_value_set_string (dest, NULL);
+ return TRUE;
+ } else if (G_LIKELY (*s != '"')) {
if (!g_utf8_validate (s, -1, NULL))
return FALSE;
g_value_set_string (dest, s);
return TRUE;
} else {
gchar *str = gst_string_unwrap (s);
-
if (G_UNLIKELY (!str))
return FALSE;
g_value_take_string (dest, str);
GST_END_TEST;
+GST_START_TEST (test_string_properties)
+{
+ GstCaps *caps1, *caps2;
+ GstStructure *st1, *st2;
+ gchar *str, *res1, *res2;
+
+ /* test escaping/unescaping */
+ st1 = gst_structure_new ("RandomStructure", "prop1", G_TYPE_STRING, "foo",
+ "prop2", G_TYPE_STRING, "", "prop3", G_TYPE_STRING, NULL,
+ "prop4", G_TYPE_STRING, "NULL", NULL);
+ str = gst_structure_to_string (st1);
+ st2 = gst_structure_from_string (str, NULL);
+ g_free (str);
+
+ fail_unless (st2 != NULL);
+
+ /* need to put stuctures into caps to compare */
+ caps1 = gst_caps_new_empty ();
+ gst_caps_append_structure (caps1, st1);
+ caps2 = gst_caps_new_empty ();
+ gst_caps_append_structure (caps2, st2);
+ res1 = gst_caps_to_string (caps1);
+ res2 = gst_caps_to_string (caps2);
+ fail_unless (gst_caps_is_equal (caps1, caps2),
+ "Structures did not match:\n\tStructure 1: %s\n\tStructure 2: %s\n",
+ res1, res2);
+ gst_caps_unref (caps1);
+ gst_caps_unref (caps2);
+ g_free (res1);
+ g_free (res2);
+}
+
+GST_END_TEST;
+
GST_START_TEST (test_structure_new)
{
GstStructure *s;
GST_END_TEST;
-GST_START_TEST (test_empty_string_fields)
-{
- GstStructure *s;
-
- s = gst_structure_empty_new ("con/struct");
- ASSERT_WARNING (gst_structure_set (s, "layout", G_TYPE_STRING, "", NULL));
- gst_structure_set (s, "debug-string", G_TYPE_STRING, NULL, NULL);
- gst_structure_free (s);
-}
-
-GST_END_TEST;
-
GST_START_TEST (test_vararg_getters)
{
GstStructure *s;
tcase_add_test (tc_chain, test_from_string);
tcase_add_test (tc_chain, test_to_string);
tcase_add_test (tc_chain, test_to_from_string);
+ tcase_add_test (tc_chain, test_string_properties);
tcase_add_test (tc_chain, test_complete_structure);
tcase_add_test (tc_chain, test_structure_new);
tcase_add_test (tc_chain, test_fixate);
tcase_add_test (tc_chain, test_fixate_frac_list);
tcase_add_test (tc_chain, test_structure_nested);
tcase_add_test (tc_chain, test_structure_nested_from_and_to_string);
- tcase_add_test (tc_chain, test_empty_string_fields);
tcase_add_test (tc_chain, test_vararg_getters);
return s;
}
gchar *try[] = {
"Dude",
"Hi, I'm a string",
- "tüüüt!"
+ "tüüüt!",
+ "\"\"" /* Empty string */
};
gchar *tmp;
GValue v = { 0, };
{
"", ""}, /* empty strings */
{
- "\"\"", ""}, /* FAILURES */
+ "\"\"", ""}, /* quoted empty string -> empty string */
+ /* Expected FAILURES: */
{
"\"", NULL}, /* missing second quote */
{
fail_unless (gst_value_compare (&value1, &value2) == GST_VALUE_LESS_THAN);
fail_unless (gst_value_compare (&value2, &value1) == GST_VALUE_GREATER_THAN);
fail_unless (gst_value_compare (&value1, &value1) == GST_VALUE_EQUAL);
+ /* Test some NULL string comparisons */
+ g_value_set_string (&value2, NULL);
+ fail_unless (gst_value_compare (&value1, &value2) == GST_VALUE_UNORDERED);
+ fail_unless (gst_value_compare (&value2, &value1) == GST_VALUE_UNORDERED);
+ fail_unless (gst_value_compare (&value2, &value2) == GST_VALUE_EQUAL);
+
g_value_unset (&value1);
g_value_unset (&value2);