gstreamer/gst/gstvalue.c
Ramon Garcia Fernandez 4c4ff33d1f Trying to fix the mess that I made with the two previous commits.
Original commit message from CVS:


Trying to fix the mess that I made with the two previous commits.

First commit, doing something wrong (fixing comparisons of signed and unsigned).
Second commit, trying to revert the previous, but changing other things and
reverting unrelated work of other people.
And this third, hopefully fixes it.
2004-02-07 15:51:39 +00:00

1497 lines
35 KiB
C

/* GStreamer
* Copyright (C) <2003> David A. Schleef <ds@schleef.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <gst/gst.h>
#include <gobject/gvaluecollector.h>
typedef struct _GstValueUnionInfo GstValueUnionInfo;
struct _GstValueUnionInfo {
GType type1;
GType type2;
GstValueUnionFunc func;
};
typedef struct _GstValueIntersectInfo GstValueIntersectInfo;
struct _GstValueIntersectInfo {
GType type1;
GType type2;
GstValueIntersectFunc func;
};
GType gst_type_fourcc;
GType gst_type_int_range;
GType gst_type_double_range;
GType gst_type_list;
static GArray *gst_value_table;
static GArray *gst_value_union_funcs;
static GArray *gst_value_intersect_funcs;
/*************************************/
/* list */
static void
gst_value_init_list (GValue *value)
{
value->data[0].v_pointer = g_array_new (FALSE, TRUE, sizeof(GValue));
}
static GArray *
gst_value_list_array_copy (const GArray *src)
{
GArray *dest;
gint i;
dest = g_array_sized_new (FALSE, TRUE, sizeof(GValue), src->len);
g_array_set_size (dest, src->len);
for (i = 0; i < src->len; i++) {
gst_value_init_and_copy (&g_array_index(dest, GValue, i),
&g_array_index(src, GValue, i));
}
return dest;
}
static void
gst_value_copy_list (const GValue *src_value, GValue *dest_value)
{
dest_value->data[0].v_pointer = gst_value_list_array_copy ((GArray *) src_value->data[0].v_pointer);
}
static void
gst_value_free_list (GValue *value)
{
gint i;
GArray *src = (GArray *) value->data[0].v_pointer;
if ((value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS) == 0) {
for (i = 0; i < src->len; i++) {
g_value_unset (&g_array_index(src, GValue, i));
}
g_array_free (src, TRUE);
}
}
static gpointer
gst_value_list_peek_pointer (const GValue *value)
{
return value->data[0].v_pointer;
}
static gchar *
gst_value_collect_list (GValue *value, guint n_collect_values,
GTypeCValue *collect_values, guint collect_flags)
{
if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
value->data[0].v_pointer = collect_values[0].v_pointer;
value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
} else {
value->data[0].v_pointer = gst_value_list_array_copy ((GArray *) collect_values[0].v_pointer);
}
return NULL;
}
static gchar *
gst_value_lcopy_list (const GValue *value, guint n_collect_values,
GTypeCValue *collect_values, guint collect_flags)
{
GArray **dest = collect_values[0].v_pointer;
if (!dest)
return g_strdup_printf ("value location for `%s' passed as NULL",
G_VALUE_TYPE_NAME (value));
if (!value->data[0].v_pointer)
return g_strdup_printf ("invalid value given for `%s'",
G_VALUE_TYPE_NAME (value));
if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
*dest = (GArray *) value->data[0].v_pointer;
} else {
*dest = gst_value_list_array_copy ((GArray *) value->data[0].v_pointer);
}
return NULL;
}
/**
* gst_value_list_prepend_value:
*
*/
void
gst_value_list_prepend_value (GValue *value, const GValue *prepend_value)
{
g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
g_array_prepend_vals ((GArray *) value->data[0].v_pointer, prepend_value, 1);
}
/**
* gst_value_list_append_value:
*
*/
void
gst_value_list_append_value (GValue *value, const GValue *append_value)
{
g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
g_array_append_vals ((GArray *) value->data[0].v_pointer, append_value, 1);
}
/**
* gst_value_list_get_size:
*
*/
guint
gst_value_list_get_size (const GValue *value)
{
g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), 0);
return ((GArray *) value->data[0].v_pointer)->len;
}
/**
* gst_value_list_get_value:
*
*/
const GValue *
gst_value_list_get_value (const GValue *value, guint index)
{
g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), NULL);
g_return_val_if_fail (index < gst_value_list_get_size (value), NULL);
return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer, GValue, index);
}
/**
* gst_value_list_concat:
* @dest: an uninitialized #GValue to take the result
* @value1: first value to put into the union
* @value2: second value to put into the union
*
* Concatenates copies of value1 and value2 into a list. dest will be
* initialized to the type GST_TYPE_LIST.
*/
void
gst_value_list_concat (GValue *dest, const GValue *value1, const GValue *value2)
{
guint i, value1_length, value2_length;
GArray *array;
g_return_if_fail (dest != NULL);
g_return_if_fail (G_VALUE_TYPE (dest) == 0);
g_return_if_fail (G_IS_VALUE (value1));
g_return_if_fail (G_IS_VALUE (value2));
value1_length = (GST_VALUE_HOLDS_LIST (value1) ? gst_value_list_get_size (value1) : 1);
value2_length = (GST_VALUE_HOLDS_LIST (value2) ? gst_value_list_get_size (value2) : 1);
g_value_init (dest, GST_TYPE_LIST);
array = (GArray *) dest->data[0].v_pointer;
g_array_set_size (array, value1_length + value2_length);
if (GST_VALUE_HOLDS_LIST (value1)) {
for (i = 0; i < value1_length; i++) {
gst_value_init_and_copy (&g_array_index(array, GValue, i),
gst_value_list_get_value (value1, i));
}
} else {
gst_value_init_and_copy (&g_array_index(array, GValue, 0), value1);
}
if (GST_VALUE_HOLDS_LIST (value2)) {
for (i = 0; i < value2_length; i++) {
gst_value_init_and_copy (&g_array_index(array, GValue, i + value1_length),
gst_value_list_get_value (value2, i));
}
} else {
gst_value_init_and_copy (&g_array_index(array, GValue, value1_length),
value2);
}
}
static void
gst_value_transform_list_string (const GValue *src_value,
GValue *dest_value)
{
GValue *list_value;
GArray *array;
GString *s;
int i;
char *list_s;
array = src_value->data[0].v_pointer;
s = g_string_new("{ ");
for(i=0;i<array->len;i++){
list_value = &g_array_index(array, GValue, i);
if (i != 0) {
g_string_append (s, ", ");
}
list_s = g_strdup_value_contents (list_value);
g_string_append (s, list_s);
g_free (list_s);
}
g_string_append (s, " }");
dest_value->data[0].v_pointer = g_string_free (s, FALSE);
}
static int
gst_value_compare_list (const GValue *value1, const GValue *value2)
{
int i,j;
GArray *array1 = value1->data[0].v_pointer;
GArray *array2 = value2->data[0].v_pointer;
GValue *v1;
GValue *v2;
if (array1->len != array2->len) return GST_VALUE_UNORDERED;
for(i=0;i<array1->len;i++){
v1 = &g_array_index (array1, GValue, i);
for(j=0;j<array1->len;j++){
v2 = &g_array_index (array2, GValue, j);
if (gst_value_compare(v1, v2) == GST_VALUE_EQUAL) break;
}
if (j==array1->len) {
return GST_VALUE_UNORDERED;
}
}
return GST_VALUE_EQUAL;
}
static char *
gst_value_serialize_list (const GValue *value)
{
int i;
GArray *array = value->data[0].v_pointer;
GString *s;
GValue *v;
gchar *s_val;
s = g_string_new("{ ");
for(i=0;i<array->len;i++){
v = &g_array_index (array, GValue, i);
s_val = gst_value_serialize (v);
g_string_append (s, s_val);
g_free (s_val);
if (i<array->len - 1) {
g_string_append (s, ", ");
}
}
g_string_append (s, " }");
return g_string_free (s, FALSE);
}
static gboolean
gst_value_deserialize_list (GValue *dest, const char *s)
{
g_warning("unimplemented");
return FALSE;
}
/*************************************/
/* fourcc */
static void
gst_value_init_fourcc (GValue *value)
{
value->data[0].v_int = 0;
}
static void
gst_value_copy_fourcc (const GValue *src_value, GValue *dest_value)
{
dest_value->data[0].v_int = src_value->data[0].v_int;
}
static gchar *
gst_value_collect_fourcc (GValue *value, guint n_collect_values,
GTypeCValue *collect_values, guint collect_flags)
{
value->data[0].v_int = collect_values[0].v_int;
return NULL;
}
static gchar *
gst_value_lcopy_fourcc (const GValue *value, guint n_collect_values,
GTypeCValue *collect_values, guint collect_flags)
{
guint32 *fourcc_p = collect_values[0].v_pointer;
if (!fourcc_p)
return g_strdup_printf ("value location for `%s' passed as NULL",
G_VALUE_TYPE_NAME (value));
*fourcc_p = value->data[0].v_int;
return NULL;
}
/**
* gst_value_set_fourcc:
*
*/
void
gst_value_set_fourcc (GValue *value, guint32 fourcc)
{
g_return_if_fail (GST_VALUE_HOLDS_FOURCC (value));
value->data[0].v_int = fourcc;
}
/**
* gst_value_get_fourcc:
*
*/
guint32
gst_value_get_fourcc (const GValue *value)
{
g_return_val_if_fail (GST_VALUE_HOLDS_FOURCC (value), 0);
return value->data[0].v_int;
}
static void
gst_value_transform_fourcc_string (const GValue *src_value,
GValue *dest_value)
{
guint32 fourcc = src_value->data[0].v_int;
if (g_ascii_isprint ((fourcc>>0) & 0xff) &&
g_ascii_isprint ((fourcc>>8) & 0xff) &&
g_ascii_isprint ((fourcc>>16) & 0xff) &&
g_ascii_isprint ((fourcc>>24) & 0xff)){
dest_value->data[0].v_pointer = g_strdup_printf(
GST_FOURCC_FORMAT, GST_FOURCC_ARGS(fourcc));
} else {
dest_value->data[0].v_pointer = g_strdup_printf("0x%08x", fourcc);
}
}
static int
gst_value_compare_fourcc (const GValue *value1, const GValue *value2)
{
if (value2->data[0].v_int == value1->data[0].v_int) return GST_VALUE_EQUAL;
return GST_VALUE_UNORDERED;
}
static char *
gst_value_serialize_fourcc (const GValue *value)
{
guint32 fourcc = value->data[0].v_int;
if (g_ascii_isalnum ((fourcc>>0) & 0xff) &&
g_ascii_isalnum ((fourcc>>8) & 0xff) &&
g_ascii_isalnum ((fourcc>>16) & 0xff) &&
g_ascii_isalnum ((fourcc>>24) & 0xff)){
return g_strdup_printf(GST_FOURCC_FORMAT, GST_FOURCC_ARGS(fourcc));
} else {
return g_strdup_printf("0x%08x", fourcc);
}
}
static gboolean
gst_value_deserialize_fourcc (GValue *dest, const char *s)
{
gboolean ret = FALSE;
guint32 fourcc = 0;
char *end;
if (strlen(s) == 4) {
fourcc = GST_MAKE_FOURCC(s[0], s[1], s[2], s[3]);
ret = TRUE;
} else if (g_ascii_isdigit (*s)) {
fourcc = strtoul (s, &end, 0);
if (*end == 0) {
ret = TRUE;
}
}
gst_value_set_fourcc (dest, fourcc);
return ret;
}
/*************************************/
/* int range */
static void
gst_value_init_int_range (GValue *value)
{
value->data[0].v_int = 0;
value->data[1].v_int = 0;
}
static void
gst_value_copy_int_range (const GValue *src_value, GValue *dest_value)
{
dest_value->data[0].v_int = src_value->data[0].v_int;
dest_value->data[1].v_int = src_value->data[1].v_int;
}
static gchar *
gst_value_collect_int_range (GValue *value, guint n_collect_values,
GTypeCValue *collect_values, guint collect_flags)
{
/* FIXME */
value->data[0].v_int = collect_values[0].v_int;
value->data[1].v_int = collect_values[1].v_int;
return NULL;
}
static gchar *
gst_value_lcopy_int_range (const GValue *value, guint n_collect_values,
GTypeCValue *collect_values, guint collect_flags)
{
guint32 *int_range_start = collect_values[0].v_pointer;
guint32 *int_range_end = collect_values[1].v_pointer;
if (!int_range_start)
return g_strdup_printf ("start value location for `%s' passed as NULL",
G_VALUE_TYPE_NAME (value));
if (!int_range_end)
return g_strdup_printf ("end value location for `%s' passed as NULL",
G_VALUE_TYPE_NAME (value));
*int_range_start = value->data[0].v_int;
*int_range_end = value->data[1].v_int;
return NULL;
}
/**
* gst_value_set_int_range:
*
*/
void
gst_value_set_int_range (GValue *value, int start, int end)
{
g_return_if_fail (GST_VALUE_HOLDS_INT_RANGE (value));
value->data[0].v_int = start;
value->data[1].v_int = end;
}
/**
* gst_value_get_int_range_min:
*
*/
int
gst_value_get_int_range_min (const GValue *value)
{
g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
return value->data[0].v_int;
}
/**
* gst_value_get_int_range_max:
*
*/
int
gst_value_get_int_range_max (const GValue *value)
{
g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
return value->data[1].v_int;
}
static void
gst_value_transform_int_range_string (const GValue *src_value,
GValue *dest_value)
{
dest_value->data[0].v_pointer = g_strdup_printf("[%d,%d]",
(int)src_value->data[0].v_int, (int)src_value->data[1].v_int);
}
static int
gst_value_compare_int_range (const GValue *value1, const GValue *value2)
{
if (value2->data[0].v_int == value1->data[0].v_int &&
value2->data[0].v_int == value1->data[0].v_int) return GST_VALUE_EQUAL;
return GST_VALUE_UNORDERED;
}
static char *
gst_value_serialize_int_range (const GValue *value)
{
return g_strdup_printf ("[ %d, %d ]", value->data[0].v_int,
value->data[1].v_int);
}
static gboolean
gst_value_deserialize_int_range (GValue *dest, const char *s)
{
g_warning("unimplemented");
return FALSE;
}
/*************************************/
/* double range */
static void
gst_value_init_double_range (GValue *value)
{
value->data[0].v_double = 0;
value->data[1].v_double = 0;
}
static void
gst_value_copy_double_range (const GValue *src_value, GValue *dest_value)
{
dest_value->data[0].v_double = src_value->data[0].v_double;
dest_value->data[1].v_double = src_value->data[1].v_double;
}
static gchar *
gst_value_collect_double_range (GValue *value, guint n_collect_values,
GTypeCValue *collect_values, guint collect_flags)
{
value->data[0].v_double = collect_values[0].v_double;
value->data[1].v_double = collect_values[1].v_double;
return NULL;
}
static gchar *
gst_value_lcopy_double_range (const GValue *value, guint n_collect_values,
GTypeCValue *collect_values, guint collect_flags)
{
gdouble *double_range_start = collect_values[0].v_pointer;
gdouble *double_range_end = collect_values[1].v_pointer;
if (!double_range_start)
return g_strdup_printf ("start value location for `%s' passed as NULL",
G_VALUE_TYPE_NAME (value));
if (!double_range_end)
return g_strdup_printf ("end value location for `%s' passed as NULL",
G_VALUE_TYPE_NAME (value));
*double_range_start = value->data[0].v_double;
*double_range_end = value->data[1].v_double;
return NULL;
}
/**
* gst_value_set_double_range:
*
*/
void
gst_value_set_double_range (GValue *value, double start, double end)
{
g_return_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value));
value->data[0].v_double = start;
value->data[1].v_double = end;
}
/**
* gst_value_get_double_range_min:
*
*/
double
gst_value_get_double_range_min (const GValue *value)
{
g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
return value->data[0].v_double;
}
/**
* gst_value_get_double_range_max:
*
*/
double
gst_value_get_double_range_max (const GValue *value)
{
g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
return value->data[1].v_double;
}
static void
gst_value_transform_double_range_string (const GValue *src_value,
GValue *dest_value)
{
char s1[G_ASCII_DTOSTR_BUF_SIZE],s2[G_ASCII_DTOSTR_BUF_SIZE];
dest_value->data[0].v_pointer = g_strdup_printf("[%s,%s]",
g_ascii_dtostr (s1, G_ASCII_DTOSTR_BUF_SIZE,
src_value->data[0].v_double),
g_ascii_dtostr (s2, G_ASCII_DTOSTR_BUF_SIZE,
src_value->data[1].v_double));
}
static int
gst_value_compare_double_range (const GValue *value1, const GValue *value2)
{
if (value2->data[0].v_double == value1->data[0].v_double &&
value2->data[0].v_double == value1->data[0].v_double)
return GST_VALUE_EQUAL;
return GST_VALUE_UNORDERED;
}
static char *
gst_value_serialize_double_range (const GValue *value)
{
char d1[G_ASCII_DTOSTR_BUF_SIZE];
char d2[G_ASCII_DTOSTR_BUF_SIZE];
g_ascii_dtostr(d1, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
g_ascii_dtostr(d2, G_ASCII_DTOSTR_BUF_SIZE, value->data[1].v_double);
return g_strdup_printf ("[ %s, %s ]", d1, d2);
}
static gboolean
gst_value_deserialize_double_range (GValue *dest, const char *s)
{
g_warning("unimplemented");
return FALSE;
}
/*************************************/
/* GstCaps */
/**
* gst_value_set_caps:
*
*/
void
gst_value_set_caps (GValue *value, const GstCaps *caps)
{
g_return_if_fail (GST_VALUE_HOLDS_CAPS (value));
value->data[0].v_pointer = gst_caps_copy (caps);
}
/**
* gst_value_get_caps:
*
*/
const GstCaps *
gst_value_get_caps (const GValue *value)
{
g_return_val_if_fail (GST_VALUE_HOLDS_CAPS (value), 0);
return value->data[0].v_pointer;
}
/*************************************/
/* boolean */
static int
gst_value_compare_boolean (const GValue *value1, const GValue *value2)
{
if ((value1->data[0].v_int!=0) == (value2->data[0].v_int!=0))
return GST_VALUE_EQUAL;
return GST_VALUE_UNORDERED;
}
static char *
gst_value_serialize_boolean (const GValue *value)
{
if (value->data[0].v_int) {
return g_strdup ("true");
}
return g_strdup ("false");
}
static gboolean
gst_value_deserialize_boolean (GValue *dest, const char *s)
{
gboolean ret = FALSE;
if (g_ascii_strcasecmp (s, "true") == 0 ||
g_ascii_strcasecmp (s, "yes") == 0 ||
g_ascii_strcasecmp (s, "t") == 0 ||
strcmp (s, "1") == 0) {
g_value_set_boolean (dest, TRUE);
ret = TRUE;
} else if (g_ascii_strcasecmp (s, "false") == 0 ||
g_ascii_strcasecmp (s, "no") == 0 ||
g_ascii_strcasecmp (s, "f") == 0 ||
strcmp (s, "0") == 0) {
g_value_set_boolean (dest, FALSE);
ret = TRUE;
}
return ret;
}
/*************************************/
/* int */
static int
gst_value_compare_int (const GValue *value1, const GValue *value2)
{
if (value1->data[0].v_int > value2->data[0].v_int)
return GST_VALUE_GREATER_THAN;
if (value1->data[0].v_int < value2->data[0].v_int)
return GST_VALUE_LESS_THAN;
return GST_VALUE_EQUAL;
}
static char *
gst_value_serialize_int (const GValue *value)
{
return g_strdup_printf ("%d", value->data[0].v_int);
}
static int
gst_strtoi (const char *s, char **end, int base)
{
int i;
if (s[0] == '-') {
i = - (int) strtoul (s + 1, end, base);
} else {
i = strtoul (s, end, base);
}
return i;
}
static gboolean
gst_value_deserialize_int (GValue *dest, const char *s)
{
int x;
char *end;
gboolean ret = FALSE;
x = gst_strtoi (s, &end, 0);
if (*end == 0) {
ret = TRUE;
} else {
if (g_ascii_strcasecmp (s, "little_endian") == 0) {
x = G_LITTLE_ENDIAN;
ret = TRUE;
} else if (g_ascii_strcasecmp (s, "big_endian") == 0) {
x = G_BIG_ENDIAN;
ret = TRUE;
} else if (g_ascii_strcasecmp (s, "byte_order") == 0) {
x = G_BYTE_ORDER;
ret = TRUE;
} else if (g_ascii_strcasecmp (s, "min") == 0) {
x = G_MININT;
ret = TRUE;
} else if (g_ascii_strcasecmp (s, "max") == 0) {
x = G_MAXINT;
ret = TRUE;
}
}
if (ret) {
g_value_set_int (dest, x);
}
return ret;
}
/*************************************/
/* double */
static int
gst_value_compare_double (const GValue *value1, const GValue *value2)
{
if (value1->data[0].v_double > value2->data[0].v_double)
return GST_VALUE_GREATER_THAN;
if (value1->data[0].v_double < value2->data[0].v_double)
return GST_VALUE_LESS_THAN;
if (value1->data[0].v_double == value2->data[0].v_double)
return GST_VALUE_EQUAL;
return GST_VALUE_UNORDERED;
}
static char *
gst_value_serialize_double (const GValue *value)
{
char d[G_ASCII_DTOSTR_BUF_SIZE];
g_ascii_dtostr(d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
return g_strdup (d);
}
static gboolean
gst_value_deserialize_double (GValue *dest, const char *s)
{
double x;
gboolean ret = FALSE;
char *end;
x = g_ascii_strtod (s, &end);
if (*end == 0) {
ret = TRUE;
} else {
if (g_ascii_strcasecmp (s, "min") == 0) {
x = -G_MAXDOUBLE;
ret = TRUE;
} else if (g_ascii_strcasecmp (s, "max") == 0) {
x = G_MAXDOUBLE;
ret = TRUE;
}
}
if (ret) {
g_value_set_double (dest, x);
}
return ret;
}
/*************************************/
/* string */
static int
gst_value_compare_string (const GValue *value1, const GValue *value2)
{
int x = strcmp(value1->data[0].v_pointer, value2->data[0].v_pointer);
if(x<0) return GST_VALUE_LESS_THAN;
if(x>0) return GST_VALUE_GREATER_THAN;
return GST_VALUE_EQUAL;
}
#define GST_ASCII_IS_STRING(c) (g_ascii_isalnum((c)) || ((c) == '_') || \
((c) == '-') || ((c) == '+') || ((c) == '/') || ((c) == ':') || \
((c) == '.'))
static gchar *
gst_string_wrap (const char *s)
{
const gchar *t;
int len;
gchar *d, *e;
gboolean wrap = FALSE;
len = 0;
t = s;
while (*t) {
if(GST_ASCII_IS_STRING(*t)) {
len++;
} else if(*t < 0x20 || *t >= 0x7f) {
wrap = TRUE;
len += 4;
} else {
wrap = TRUE;
len += 2;
}
t++;
}
if (!wrap) return strdup (s);
e = d = g_malloc(len + 3);
*e++ = '\"';
t = s;
while (*t) {
if(GST_ASCII_IS_STRING(*t)) {
*e++ = *t++;
} else if(*t < 0x20 || *t >= 0x7f) {
*e++ = '\\';
*e++ = '0' + ((*t)>>6);
*e++ = '0' + (((*t)>>3)&0x7);
*e++ = '0' + ((*t++)&0x7);
} else {
*e++ = '\\';
*e++ = *t++;
}
}
*e++ = '\"';
*e = 0;
return d;
}
static char *
gst_value_serialize_string (const GValue *value)
{
return gst_string_wrap (value->data[0].v_pointer);
}
static gboolean
gst_value_deserialize_string (GValue *dest, const char *s)
{
g_value_set_string (dest, s);
return TRUE;
}
/*************************************/
/* unions */
/*************************************/
/* intersection */
static gboolean
gst_value_intersect_int_int_range (GValue *dest, const GValue *src1,
const GValue *src2)
{
g_return_val_if_fail(G_VALUE_TYPE(src1) == G_TYPE_INT, FALSE);
g_return_val_if_fail(G_VALUE_TYPE(src2) == GST_TYPE_INT_RANGE, FALSE);
if (src2->data[0].v_int <= src1->data[0].v_int &&
src2->data[1].v_int >= src1->data[0].v_int){
gst_value_init_and_copy (dest, src1);
return TRUE;
}
return FALSE;
}
static gboolean
gst_value_intersect_int_range_int_range (GValue *dest, const GValue *src1,
const GValue *src2)
{
int min;
int max;
g_return_val_if_fail(G_VALUE_TYPE(src1) == GST_TYPE_INT_RANGE, FALSE);
g_return_val_if_fail(G_VALUE_TYPE(src2) == GST_TYPE_INT_RANGE, FALSE);
min = MAX(src1->data[0].v_int, src2->data[0].v_int);
max = MIN(src1->data[1].v_int, src2->data[1].v_int);
if(min < max){
g_value_init(dest, GST_TYPE_INT_RANGE);
gst_value_set_int_range(dest, min, max);
return TRUE;
}
if(min == max){
g_value_init(dest, G_TYPE_INT);
g_value_set_int(dest, min);
return TRUE;
}
return FALSE;
}
static gboolean
gst_value_intersect_double_double_range (GValue *dest, const GValue *src1,
const GValue *src2)
{
g_return_val_if_fail(G_VALUE_TYPE(src1) == G_TYPE_DOUBLE, FALSE);
g_return_val_if_fail(G_VALUE_TYPE(src2) == GST_TYPE_DOUBLE_RANGE, FALSE);
if (src2->data[0].v_double <= src1->data[0].v_double &&
src2->data[1].v_double >= src1->data[0].v_double){
gst_value_init_and_copy (dest, src1);
return TRUE;
}
return FALSE;
}
static gboolean
gst_value_intersect_double_range_double_range (GValue *dest, const GValue *src1,
const GValue *src2)
{
double min;
double max;
g_return_val_if_fail(G_VALUE_TYPE(src1) == GST_TYPE_DOUBLE_RANGE, FALSE);
g_return_val_if_fail(G_VALUE_TYPE(src2) == GST_TYPE_DOUBLE_RANGE, FALSE);
min = MAX(src1->data[0].v_double, src2->data[0].v_double);
max = MIN(src1->data[1].v_double, src2->data[1].v_double);
if(min < max){
g_value_init(dest, GST_TYPE_DOUBLE_RANGE);
gst_value_set_double_range(dest, min, max);
return TRUE;
}
if(min == max){
g_value_init(dest, G_TYPE_DOUBLE);
g_value_set_int(dest, min);
return TRUE;
}
return FALSE;
}
static gboolean
gst_value_intersect_list (GValue *dest, const GValue *value1, const GValue *value2)
{
guint i, size;
GValue intersection = { 0, };
gboolean ret = FALSE;
g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value1), FALSE);
size = gst_value_list_get_size (value1);
for (i = 0; i < size; i++) {
const GValue *cur = gst_value_list_get_value (value1, i);
if (gst_value_intersect (&intersection, cur, value2)) {
/* append value */
if (!ret) {
gst_value_init_and_copy (dest, &intersection);
ret = TRUE;
} else if (GST_VALUE_HOLDS_LIST (dest)) {
gst_value_list_append_value (dest, &intersection);
} else {
GValue temp = {0, };
gst_value_init_and_copy (&temp, dest);
g_value_unset (dest);
gst_value_list_concat (dest, &temp, &intersection);
}
g_value_unset (&intersection);
}
}
return ret;
}
/*************************************/
/**
* gst_value_can_compare:
*
*/
gboolean
gst_value_can_compare (const GValue *value1, const GValue *value2)
{
GstValueTable *table;
int i;
if(G_VALUE_TYPE(value1) != G_VALUE_TYPE(value2))return FALSE;
for(i=0;i<gst_value_table->len;i++){
table = &g_array_index(gst_value_table, GstValueTable, i);
if(table->type == G_VALUE_TYPE(value1) &&
table->compare) return TRUE;
}
return FALSE;
}
/**
* gst_value_compare:
*
*/
int
gst_value_compare (const GValue *value1, const GValue *value2)
{
GstValueTable *table;
int i;
if (G_VALUE_TYPE(value1) != G_VALUE_TYPE(value2)) return GST_VALUE_UNORDERED;
for(i=0;i<gst_value_table->len;i++){
table = &g_array_index(gst_value_table, GstValueTable, i);
if(table->type != G_VALUE_TYPE(value1) ||
table->compare == NULL) continue;
return table->compare(value1, value2);
}
g_critical("unable to compare values of type %s\n",
g_type_name (G_VALUE_TYPE (value1)));
return GST_VALUE_UNORDERED;
}
/* union */
/**
* gst_value_can_union:
*
*/
gboolean
gst_value_can_union (const GValue *value1, const GValue *value2)
{
GstValueUnionInfo *union_info;
int i;
for(i=0;i<gst_value_union_funcs->len;i++){
union_info = &g_array_index(gst_value_union_funcs, GstValueUnionInfo, i);
if(union_info->type1 == G_VALUE_TYPE(value1) &&
union_info->type2 == G_VALUE_TYPE(value2)) return TRUE;
}
return FALSE;
}
/**
* gst_value_union:
*
*/
gboolean
gst_value_union (GValue *dest, const GValue *value1, const GValue *value2)
{
GstValueUnionInfo *union_info;
int i;
for(i=0;i<gst_value_union_funcs->len;i++){
union_info = &g_array_index(gst_value_union_funcs, GstValueUnionInfo, i);
if(union_info->type1 == G_VALUE_TYPE(value1) &&
union_info->type2 == G_VALUE_TYPE(value2)) {
return union_info->func(dest, value1, value2);
}
}
gst_value_list_concat (dest, value1, value2);
return TRUE;
}
/**
* gst_value_register_union_func:
*
*/
void
gst_value_register_union_func (GType type1, GType type2, GstValueUnionFunc func)
{
GstValueUnionInfo union_info;
union_info.type1 = type1;
union_info.type2 = type2;
union_info.func = func;
g_array_append_val(gst_value_union_funcs, union_info);
}
/* intersection */
/**
* gst_value_can_intersect:
*
*/
gboolean
gst_value_can_intersect (const GValue *value1, const GValue *value2)
{
GstValueIntersectInfo *intersect_info;
int i;
/* special cases */
if (GST_VALUE_HOLDS_LIST (value1) ||
GST_VALUE_HOLDS_LIST (value2))
return TRUE;
for(i=0;i<gst_value_intersect_funcs->len;i++){
intersect_info = &g_array_index(gst_value_intersect_funcs,
GstValueIntersectInfo, i);
if(intersect_info->type1 == G_VALUE_TYPE(value1) &&
intersect_info->type2 == G_VALUE_TYPE(value2)) return TRUE;
}
return gst_value_can_compare (value1, value2);
}
/**
* gst_value_intersect:
*
*/
gboolean
gst_value_intersect (GValue *dest, const GValue *value1, const GValue *value2)
{
GstValueIntersectInfo *intersect_info;
int i;
int ret = FALSE;
/* special cases first */
if (GST_VALUE_HOLDS_LIST (value1))
return gst_value_intersect_list (dest, value1, value2);
if (GST_VALUE_HOLDS_LIST (value2))
return gst_value_intersect_list (dest, value2, value1);
for(i=0;i<gst_value_intersect_funcs->len;i++){
intersect_info = &g_array_index(gst_value_intersect_funcs,
GstValueIntersectInfo, i);
if(intersect_info->type1 == G_VALUE_TYPE(value1) &&
intersect_info->type2 == G_VALUE_TYPE(value2)) {
ret = intersect_info->func(dest, value1, value2);
return ret;
}
if(intersect_info->type1 == G_VALUE_TYPE(value2) &&
intersect_info->type2 == G_VALUE_TYPE(value1)) {
ret = intersect_info->func(dest, value2, value1);
return ret;
}
}
if(gst_value_compare(value1, value2) == GST_VALUE_EQUAL){
gst_value_init_and_copy (dest, value1);
ret = TRUE;
}
return ret;
}
/**
* gst_value_register_intersection_func:
*
*/
void
gst_value_register_intersect_func (GType type1, GType type2,
GstValueIntersectFunc func)
{
GstValueIntersectInfo intersect_info;
intersect_info.type1 = type1;
intersect_info.type2 = type2;
intersect_info.func = func;
g_array_append_val(gst_value_intersect_funcs, intersect_info);
}
/**
* gst_value_register:
*
*/
void
gst_value_register (const GstValueTable *table)
{
g_array_append_val(gst_value_table, *table);
}
/**
* gst_value_init_and_copy:
*
*/
void
gst_value_init_and_copy (GValue *dest, const GValue *src)
{
g_value_init (dest, G_VALUE_TYPE(src));
g_value_copy (src, dest);
}
/**
* gst_value_serialize:
*
*/
gchar *
gst_value_serialize (const GValue *value)
{
int i;
GValue s_val = { 0 };
GstValueTable *table;
char *s;
for(i=0;i<gst_value_table->len;i++){
table = &g_array_index(gst_value_table, GstValueTable, i);
if(table->type != G_VALUE_TYPE(value) ||
table->serialize == NULL) continue;
return table->serialize(value);
}
g_value_init (&s_val, G_TYPE_STRING);
g_value_transform (value, &s_val);
s = gst_string_wrap (g_value_get_string (&s_val));
g_value_unset (&s_val);
return s;
}
/**
* gst_value_deserialize:
*
*/
gboolean
gst_value_deserialize (GValue *dest, const gchar *src)
{
GstValueTable *table;
int i;
for(i=0;i<gst_value_table->len;i++){
table = &g_array_index(gst_value_table, GstValueTable, i);
if(table->type != G_VALUE_TYPE(dest) ||
table->deserialize == NULL) continue;
return table->deserialize(dest, src);
}
return FALSE;
}
void
_gst_value_initialize (void)
{
GTypeInfo info = {
0,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
0,
NULL,
NULL,
};
//const GTypeFundamentalInfo finfo = { G_TYPE_FLAG_DERIVABLE, };
gst_value_table = g_array_new(FALSE, FALSE, sizeof(GstValueTable));
gst_value_union_funcs = g_array_new(FALSE, FALSE,
sizeof(GstValueUnionInfo));
gst_value_intersect_funcs = g_array_new(FALSE, FALSE,
sizeof(GstValueIntersectInfo));
{
static const GTypeValueTable value_table = {
gst_value_init_fourcc,
NULL,
gst_value_copy_fourcc,
NULL,
"i",
gst_value_collect_fourcc,
"p",
gst_value_lcopy_fourcc
};
static GstValueTable gst_value = {
0,
gst_value_compare_fourcc,
gst_value_serialize_fourcc,
gst_value_deserialize_fourcc,
};
info.value_table = &value_table;
gst_type_fourcc = g_type_register_static (G_TYPE_BOXED, "GstFourcc", &info, 0);
gst_value.type = gst_type_fourcc;
gst_value_register (&gst_value);
}
{
static const GTypeValueTable value_table = {
gst_value_init_int_range,
NULL,
gst_value_copy_int_range,
NULL,
"ii",
gst_value_collect_int_range,
"pp",
gst_value_lcopy_int_range
};
static GstValueTable gst_value = {
0,
gst_value_compare_int_range,
gst_value_serialize_int_range,
gst_value_deserialize_int_range,
};
info.value_table = &value_table;
gst_type_int_range = g_type_register_static (G_TYPE_BOXED, "GstIntRange", &info, 0);
gst_value.type = gst_type_int_range;
gst_value_register (&gst_value);
}
{
static const GTypeValueTable value_table = {
gst_value_init_double_range,
NULL,
gst_value_copy_double_range,
NULL,
"dd",
gst_value_collect_double_range,
"pp",
gst_value_lcopy_double_range
};
static GstValueTable gst_value = {
0,
gst_value_compare_double_range,
gst_value_serialize_double_range,
gst_value_deserialize_double_range,
};
info.value_table = &value_table;
gst_type_double_range = g_type_register_static (G_TYPE_BOXED, "GstDoubleRange", &info, 0);
gst_value.type = gst_type_double_range;
gst_value_register (&gst_value);
}
{
static const GTypeValueTable value_table = {
gst_value_init_list,
gst_value_free_list,
gst_value_copy_list,
gst_value_list_peek_pointer,
"p",
gst_value_collect_list,
"p",
gst_value_lcopy_list
};
static GstValueTable gst_value = {
0,
gst_value_compare_list,
gst_value_serialize_list,
gst_value_deserialize_list,
};
info.value_table = &value_table;
gst_type_list = g_type_register_static (G_TYPE_BOXED, "GstValueList", &info, 0);
gst_value.type = gst_type_list;
gst_value_register (&gst_value);
}
{
static const GstValueTable gst_value = {
G_TYPE_INT,
gst_value_compare_int,
gst_value_serialize_int,
gst_value_deserialize_int,
};
gst_value_register (&gst_value);
}
{
static const GstValueTable gst_value = {
G_TYPE_DOUBLE,
gst_value_compare_double,
gst_value_serialize_double,
gst_value_deserialize_double,
};
gst_value_register (&gst_value);
}
{
static const GstValueTable gst_value = {
G_TYPE_STRING,
gst_value_compare_string,
gst_value_serialize_string,
gst_value_deserialize_string,
};
gst_value_register (&gst_value);
}
{
static const GstValueTable gst_value = {
G_TYPE_BOOLEAN,
gst_value_compare_boolean,
gst_value_serialize_boolean,
gst_value_deserialize_boolean,
};
gst_value_register (&gst_value);
}
g_value_register_transform_func (GST_TYPE_FOURCC, G_TYPE_STRING,
gst_value_transform_fourcc_string);
g_value_register_transform_func (GST_TYPE_INT_RANGE, G_TYPE_STRING,
gst_value_transform_int_range_string);
g_value_register_transform_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_STRING,
gst_value_transform_double_range_string);
g_value_register_transform_func (GST_TYPE_LIST, G_TYPE_STRING,
gst_value_transform_list_string);
gst_value_register_intersect_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
gst_value_intersect_int_int_range);
gst_value_register_intersect_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
gst_value_intersect_int_range_int_range);
gst_value_register_intersect_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
gst_value_intersect_double_double_range);
gst_value_register_intersect_func (GST_TYPE_DOUBLE_RANGE, GST_TYPE_DOUBLE_RANGE,
gst_value_intersect_double_range_double_range);
}