67f609084b859e7ea3d6ea84fe2d3a567d33471c
[platform/upstream/gstreamer.git] / gst / gstvalue.c
1 /* GStreamer
2  * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /**
21  * SECTION:gstvalue
22  * @short_description: GValue implementations specific
23  * to GStreamer
24  *
25  * GValue implementations specific to GStreamer.
26  *
27  * Note that operations on the same #GValue from multiple threads may lead to
28  * undefined behaviour.
29  *
30  * Last reviewed on 2008-03-11 (0.10.18)
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36 #include <math.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <ctype.h>
41
42 #include "gst_private.h"
43 #include "glib-compat-private.h"
44 #include <gst/gst.h>
45 #include <gobject/gvaluecollector.h>
46 #include "gstutils.h"
47
48 typedef struct _GstValueUnionInfo GstValueUnionInfo;
49 struct _GstValueUnionInfo
50 {
51   GType type1;
52   GType type2;
53   GstValueUnionFunc func;
54 };
55
56 typedef struct _GstValueIntersectInfo GstValueIntersectInfo;
57 struct _GstValueIntersectInfo
58 {
59   GType type1;
60   GType type2;
61   GstValueIntersectFunc func;
62 };
63
64 typedef struct _GstValueSubtractInfo GstValueSubtractInfo;
65 struct _GstValueSubtractInfo
66 {
67   GType minuend;
68   GType subtrahend;
69   GstValueSubtractFunc func;
70 };
71
72 #define FUNDAMENTAL_TYPE_ID_MAX \
73     (G_TYPE_FUNDAMENTAL_MAX >> G_TYPE_FUNDAMENTAL_SHIFT)
74 #define FUNDAMENTAL_TYPE_ID(type) \
75     ((type) >> G_TYPE_FUNDAMENTAL_SHIFT)
76
77 #define VALUE_LIST_SIZE(v) (((GArray *) (v)->data[0].v_pointer)->len)
78 #define VALUE_LIST_GET_VALUE(v, index) ((const GValue *) &g_array_index ((GArray *) (v)->data[0].v_pointer, GValue, (index)))
79
80 static GArray *gst_value_table;
81 static GHashTable *gst_value_hash;
82 static GstValueTable *gst_value_tables_fundamental[FUNDAMENTAL_TYPE_ID_MAX + 1];
83 static GArray *gst_value_union_funcs;
84 static GArray *gst_value_intersect_funcs;
85 static GArray *gst_value_subtract_funcs;
86
87 /* Forward declarations */
88 static gchar *gst_value_serialize_fraction (const GValue * value);
89
90 static GstValueCompareFunc gst_value_get_compare_func (const GValue * value1);
91 static gint gst_value_compare_with_func (const GValue * value1,
92     const GValue * value2, GstValueCompareFunc compare);
93
94 static gchar *gst_string_wrap (const gchar * s);
95 static gchar *gst_string_take_and_wrap (gchar * s);
96 static gchar *gst_string_unwrap (const gchar * s);
97
98 static inline GstValueTable *
99 gst_value_hash_lookup_type (GType type)
100 {
101   if (G_LIKELY (G_TYPE_IS_FUNDAMENTAL (type)))
102     return gst_value_tables_fundamental[FUNDAMENTAL_TYPE_ID (type)];
103   else
104     return g_hash_table_lookup (gst_value_hash, (gpointer) type);
105 }
106
107 static void
108 gst_value_hash_add_type (GType type, const GstValueTable * table)
109 {
110   if (G_TYPE_IS_FUNDAMENTAL (type))
111     gst_value_tables_fundamental[FUNDAMENTAL_TYPE_ID (type)] = (gpointer) table;
112
113   g_hash_table_insert (gst_value_hash, (gpointer) type, (gpointer) table);
114 }
115
116 /********
117  * list *
118  ********/
119
120 /* two helper functions to serialize/stringify any type of list
121  * regular lists are done with { }, arrays with < >
122  */
123 static gchar *
124 gst_value_serialize_any_list (const GValue * value, const gchar * begin,
125     const gchar * end)
126 {
127   guint i;
128   GArray *array = value->data[0].v_pointer;
129   GString *s;
130   GValue *v;
131   gchar *s_val;
132   guint alen = array->len;
133
134   /* estimate minimum string length to minimise re-allocs in GString */
135   s = g_string_sized_new (2 + (6 * alen) + 2);
136   g_string_append (s, begin);
137   for (i = 0; i < alen; i++) {
138     v = &g_array_index (array, GValue, i);
139     s_val = gst_value_serialize (v);
140     g_string_append (s, s_val);
141     g_free (s_val);
142     if (i < alen - 1) {
143       g_string_append_len (s, ", ", 2);
144     }
145   }
146   g_string_append (s, end);
147   return g_string_free (s, FALSE);
148 }
149
150 static void
151 gst_value_transform_any_list_string (const GValue * src_value,
152     GValue * dest_value, const gchar * begin, const gchar * end)
153 {
154   GValue *list_value;
155   GArray *array;
156   GString *s;
157   guint i;
158   gchar *list_s;
159   guint alen;
160
161   array = src_value->data[0].v_pointer;
162   alen = array->len;
163
164   /* estimate minimum string length to minimise re-allocs in GString */
165   s = g_string_sized_new (2 + (10 * alen) + 2);
166   g_string_append (s, begin);
167   for (i = 0; i < alen; i++) {
168     list_value = &g_array_index (array, GValue, i);
169
170     if (i != 0) {
171       g_string_append_len (s, ", ", 2);
172     }
173     list_s = g_strdup_value_contents (list_value);
174     g_string_append (s, list_s);
175     g_free (list_s);
176   }
177   g_string_append (s, end);
178
179   dest_value->data[0].v_pointer = g_string_free (s, FALSE);
180 }
181
182 /*
183  * helper function to see if a type is fixed. Is used internally here and
184  * there. Do not export, since it doesn't work for types where the content
185  * decides the fixedness (e.g. GST_TYPE_ARRAY).
186  */
187 static gboolean
188 gst_type_is_fixed (GType type)
189 {
190   /* the basic int, string, double types */
191   if (type <= G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
192     return TRUE;
193   }
194   /* our fundamental types that are certainly not fixed */
195   if (type == GST_TYPE_INT_RANGE || type == GST_TYPE_DOUBLE_RANGE ||
196       type == GST_TYPE_INT64_RANGE ||
197       type == GST_TYPE_LIST || type == GST_TYPE_FRACTION_RANGE) {
198     return FALSE;
199   }
200   /* other (boxed) types that are fixed */
201   if (type == GST_TYPE_BUFFER) {
202     return TRUE;
203   }
204   /* heavy checks */
205   if (G_TYPE_IS_FUNDAMENTAL (type) || G_TYPE_FUNDAMENTAL (type) <=
206       G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
207     return TRUE;
208   }
209
210   return FALSE;
211 }
212
213 /* GValue functions usable for both regular lists and arrays */
214 static void
215 gst_value_init_list_or_array (GValue * value)
216 {
217   value->data[0].v_pointer = g_array_new (FALSE, TRUE, sizeof (GValue));
218 }
219
220 static GArray *
221 copy_garray_of_gstvalue (const GArray * src)
222 {
223   GArray *dest;
224   guint i, len;
225
226   len = src->len;
227   dest = g_array_sized_new (FALSE, TRUE, sizeof (GValue), len);
228   g_array_set_size (dest, len);
229   for (i = 0; i < len; i++) {
230     gst_value_init_and_copy (&g_array_index (dest, GValue, i),
231         &g_array_index (src, GValue, i));
232   }
233
234   return dest;
235 }
236
237 static void
238 gst_value_copy_list_or_array (const GValue * src_value, GValue * dest_value)
239 {
240   dest_value->data[0].v_pointer =
241       copy_garray_of_gstvalue ((GArray *) src_value->data[0].v_pointer);
242 }
243
244 static void
245 gst_value_free_list_or_array (GValue * value)
246 {
247   guint i, len;
248   GArray *src = (GArray *) value->data[0].v_pointer;
249   len = src->len;
250
251   if ((value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS) == 0) {
252     for (i = 0; i < len; i++) {
253       g_value_unset (&g_array_index (src, GValue, i));
254     }
255     g_array_free (src, TRUE);
256   }
257 }
258
259 static gpointer
260 gst_value_list_or_array_peek_pointer (const GValue * value)
261 {
262   return value->data[0].v_pointer;
263 }
264
265 static gchar *
266 gst_value_collect_list_or_array (GValue * value, guint n_collect_values,
267     GTypeCValue * collect_values, guint collect_flags)
268 {
269   if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
270     value->data[0].v_pointer = collect_values[0].v_pointer;
271     value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
272   } else {
273     value->data[0].v_pointer =
274         copy_garray_of_gstvalue ((GArray *) collect_values[0].v_pointer);
275   }
276   return NULL;
277 }
278
279 static gchar *
280 gst_value_lcopy_list_or_array (const GValue * value, guint n_collect_values,
281     GTypeCValue * collect_values, guint collect_flags)
282 {
283   GArray **dest = collect_values[0].v_pointer;
284
285   if (!dest)
286     return g_strdup_printf ("value location for `%s' passed as NULL",
287         G_VALUE_TYPE_NAME (value));
288   if (!value->data[0].v_pointer)
289     return g_strdup_printf ("invalid value given for `%s'",
290         G_VALUE_TYPE_NAME (value));
291   if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
292     *dest = (GArray *) value->data[0].v_pointer;
293   } else {
294     *dest = copy_garray_of_gstvalue ((GArray *) value->data[0].v_pointer);
295   }
296   return NULL;
297 }
298
299 static gboolean
300 gst_value_list_or_array_get_basic_type (const GValue * value, GType * type)
301 {
302   if (G_UNLIKELY (value == NULL))
303     return FALSE;
304
305   if (GST_VALUE_HOLDS_LIST (value)) {
306     if (VALUE_LIST_SIZE (value) == 0)
307       return FALSE;
308     return gst_value_list_or_array_get_basic_type (VALUE_LIST_GET_VALUE (value,
309             0), type);
310   }
311   if (GST_VALUE_HOLDS_ARRAY (value)) {
312     const GArray *array = (const GArray *) value->data[0].v_pointer;
313     if (array->len == 0)
314       return FALSE;
315     return gst_value_list_or_array_get_basic_type (&g_array_index (array,
316             GValue, 0), type);
317   }
318
319   *type = G_VALUE_TYPE (value);
320
321   return TRUE;
322 }
323
324 #define IS_RANGE_COMPAT(type1,type2,t1,t2) \
325   (((t1) == (type1) && (t2) == (type2)) || ((t2) == (type1) && (t1) == (type2)))
326
327 static gboolean
328 gst_value_list_or_array_are_compatible (const GValue * value1,
329     const GValue * value2)
330 {
331   GType basic_type1, basic_type2;
332
333   /* empty or same type is OK */
334   if (!gst_value_list_or_array_get_basic_type (value1, &basic_type1) ||
335       !gst_value_list_or_array_get_basic_type (value2, &basic_type2) ||
336       basic_type1 == basic_type2)
337     return TRUE;
338
339   /* ranges are distinct types for each bound type... */
340   if (IS_RANGE_COMPAT (G_TYPE_INT, GST_TYPE_INT_RANGE, basic_type1,
341           basic_type2))
342     return TRUE;
343   if (IS_RANGE_COMPAT (G_TYPE_INT64, GST_TYPE_INT64_RANGE, basic_type1,
344           basic_type2))
345     return TRUE;
346   if (IS_RANGE_COMPAT (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE, basic_type1,
347           basic_type2))
348     return TRUE;
349   if (IS_RANGE_COMPAT (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE, basic_type1,
350           basic_type2))
351     return TRUE;
352
353   return FALSE;
354 }
355
356 /**
357  * gst_value_list_append_value:
358  * @value: a #GValue of type #GST_TYPE_LIST
359  * @append_value: the value to append
360  *
361  * Appends @append_value to the GstValueList in @value.
362  */
363 void
364 gst_value_list_append_value (GValue * value, const GValue * append_value)
365 {
366   GValue val = { 0, };
367
368   g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
369   g_return_if_fail (G_IS_VALUE (append_value));
370   g_return_if_fail (gst_value_list_or_array_are_compatible (value,
371           append_value));
372
373   gst_value_init_and_copy (&val, append_value);
374   g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1);
375 }
376
377 /**
378  * gst_value_list_prepend_value:
379  * @value: a #GValue of type #GST_TYPE_LIST
380  * @prepend_value: the value to prepend
381  *
382  * Prepends @prepend_value to the GstValueList in @value.
383  */
384 void
385 gst_value_list_prepend_value (GValue * value, const GValue * prepend_value)
386 {
387   GValue val = { 0, };
388
389   g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
390   g_return_if_fail (G_IS_VALUE (prepend_value));
391   g_return_if_fail (gst_value_list_or_array_are_compatible (value,
392           prepend_value));
393
394   gst_value_init_and_copy (&val, prepend_value);
395   g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1);
396 }
397
398 /**
399  * gst_value_list_concat:
400  * @dest: (out caller-allocates): an uninitialized #GValue to take the result
401  * @value1: a #GValue
402  * @value2: a #GValue
403  *
404  * Concatenates copies of @value1 and @value2 into a list.  Values that are not
405  * of type #GST_TYPE_LIST are treated as if they were lists of length 1.
406  * @dest will be initialized to the type #GST_TYPE_LIST.
407  */
408 void
409 gst_value_list_concat (GValue * dest, const GValue * value1,
410     const GValue * value2)
411 {
412   guint i, value1_length, value2_length;
413   GArray *array;
414
415   g_return_if_fail (dest != NULL);
416   g_return_if_fail (G_VALUE_TYPE (dest) == 0);
417   g_return_if_fail (G_IS_VALUE (value1));
418   g_return_if_fail (G_IS_VALUE (value2));
419   g_return_if_fail (gst_value_list_or_array_are_compatible (value1, value2));
420
421   value1_length =
422       (GST_VALUE_HOLDS_LIST (value1) ? VALUE_LIST_SIZE (value1) : 1);
423   value2_length =
424       (GST_VALUE_HOLDS_LIST (value2) ? VALUE_LIST_SIZE (value2) : 1);
425   g_value_init (dest, GST_TYPE_LIST);
426   array = (GArray *) dest->data[0].v_pointer;
427   g_array_set_size (array, value1_length + value2_length);
428
429   if (GST_VALUE_HOLDS_LIST (value1)) {
430     for (i = 0; i < value1_length; i++) {
431       gst_value_init_and_copy (&g_array_index (array, GValue, i),
432           VALUE_LIST_GET_VALUE (value1, i));
433     }
434   } else {
435     gst_value_init_and_copy (&g_array_index (array, GValue, 0), value1);
436   }
437
438   if (GST_VALUE_HOLDS_LIST (value2)) {
439     for (i = 0; i < value2_length; i++) {
440       gst_value_init_and_copy (&g_array_index (array, GValue,
441               i + value1_length), VALUE_LIST_GET_VALUE (value2, i));
442     }
443   } else {
444     gst_value_init_and_copy (&g_array_index (array, GValue, value1_length),
445         value2);
446   }
447 }
448
449 /**
450  * gst_value_list_merge:
451  * @dest: (out caller-allocates): an uninitialized #GValue to take the result
452  * @value1: a #GValue
453  * @value2: a #GValue
454  *
455  * Merges copies of @value1 and @value2.  Values that are not
456  * of type #GST_TYPE_LIST are treated as if they were lists of length 1.
457  *
458  * The result will be put into @dest and will either be a list that will not
459  * contain any duplicates, or a non-list type (if @value1 and @value2
460  * were equal).
461  *
462  * Since: 0.10.32
463  */
464 void
465 gst_value_list_merge (GValue * dest, const GValue * value1,
466     const GValue * value2)
467 {
468   guint i, j, k, value1_length, value2_length, skipped;
469   const GValue *src;
470   gboolean skip;
471   GArray *array;
472
473   g_return_if_fail (dest != NULL);
474   g_return_if_fail (G_VALUE_TYPE (dest) == 0);
475   g_return_if_fail (G_IS_VALUE (value1));
476   g_return_if_fail (G_IS_VALUE (value2));
477   g_return_if_fail (gst_value_list_or_array_are_compatible (value1, value2));
478
479   value1_length =
480       (GST_VALUE_HOLDS_LIST (value1) ? VALUE_LIST_SIZE (value1) : 1);
481   value2_length =
482       (GST_VALUE_HOLDS_LIST (value2) ? VALUE_LIST_SIZE (value2) : 1);
483   g_value_init (dest, GST_TYPE_LIST);
484   array = (GArray *) dest->data[0].v_pointer;
485   g_array_set_size (array, value1_length + value2_length);
486
487   if (GST_VALUE_HOLDS_LIST (value1)) {
488     for (i = 0; i < value1_length; i++) {
489       gst_value_init_and_copy (&g_array_index (array, GValue, i),
490           VALUE_LIST_GET_VALUE (value1, i));
491     }
492   } else {
493     gst_value_init_and_copy (&g_array_index (array, GValue, 0), value1);
494   }
495
496   j = value1_length;
497   skipped = 0;
498   if (GST_VALUE_HOLDS_LIST (value2)) {
499     for (i = 0; i < value2_length; i++) {
500       skip = FALSE;
501       src = VALUE_LIST_GET_VALUE (value2, i);
502       for (k = 0; k < value1_length; k++) {
503         if (gst_value_compare (&g_array_index (array, GValue, k),
504                 src) == GST_VALUE_EQUAL) {
505           skip = TRUE;
506           skipped++;
507           break;
508         }
509       }
510       if (!skip) {
511         gst_value_init_and_copy (&g_array_index (array, GValue, j), src);
512         j++;
513       }
514     }
515   } else {
516     skip = FALSE;
517     for (k = 0; k < value1_length; k++) {
518       if (gst_value_compare (&g_array_index (array, GValue, k),
519               value2) == GST_VALUE_EQUAL) {
520         skip = TRUE;
521         skipped++;
522         break;
523       }
524     }
525     if (!skip) {
526       gst_value_init_and_copy (&g_array_index (array, GValue, j), value2);
527     }
528   }
529   if (skipped) {
530     guint new_size = value1_length + (value2_length - skipped);
531
532     if (new_size > 1) {
533       /* shrink list */
534       g_array_set_size (array, new_size);
535     } else {
536       GValue single_dest;
537
538       /* size is 1, take single value in list and make it new dest */
539       single_dest = g_array_index (array, GValue, 0);
540
541       /* clean up old value allocations: must set array size to 0, because
542        * allocated values are not inited meaning g_value_unset() will not
543        * work on them */
544       g_array_set_size (array, 0);
545       g_value_unset (dest);
546
547       /* the single value is our new result */
548       *dest = single_dest;
549     }
550   }
551 }
552
553 /**
554  * gst_value_list_get_size:
555  * @value: a #GValue of type #GST_TYPE_LIST
556  *
557  * Gets the number of values contained in @value.
558  *
559  * Returns: the number of values
560  */
561 guint
562 gst_value_list_get_size (const GValue * value)
563 {
564   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), 0);
565
566   return ((GArray *) value->data[0].v_pointer)->len;
567 }
568
569 /**
570  * gst_value_list_get_value:
571  * @value: a #GValue of type #GST_TYPE_LIST
572  * @index: index of value to get from the list
573  *
574  * Gets the value that is a member of the list contained in @value and
575  * has the index @index.
576  *
577  * Returns: (transfer none): the value at the given index
578  */
579 const GValue *
580 gst_value_list_get_value (const GValue * value, guint index)
581 {
582   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), NULL);
583   g_return_val_if_fail (index < VALUE_LIST_SIZE (value), NULL);
584
585   return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer,
586       GValue, index);
587 }
588
589 /**
590  * gst_value_array_append_value:
591  * @value: a #GValue of type #GST_TYPE_ARRAY
592  * @append_value: the value to append
593  *
594  * Appends @append_value to the GstValueArray in @value.
595  */
596 void
597 gst_value_array_append_value (GValue * value, const GValue * append_value)
598 {
599   GValue val = { 0, };
600
601   g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value));
602   g_return_if_fail (G_IS_VALUE (append_value));
603   g_return_if_fail (gst_value_list_or_array_are_compatible (value,
604           append_value));
605
606   gst_value_init_and_copy (&val, append_value);
607   g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1);
608 }
609
610 /**
611  * gst_value_array_prepend_value:
612  * @value: a #GValue of type #GST_TYPE_ARRAY
613  * @prepend_value: the value to prepend
614  *
615  * Prepends @prepend_value to the GstValueArray in @value.
616  */
617 void
618 gst_value_array_prepend_value (GValue * value, const GValue * prepend_value)
619 {
620   GValue val = { 0, };
621
622   g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value));
623   g_return_if_fail (G_IS_VALUE (prepend_value));
624   g_return_if_fail (gst_value_list_or_array_are_compatible (value,
625           prepend_value));
626
627   gst_value_init_and_copy (&val, prepend_value);
628   g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1);
629 }
630
631 /**
632  * gst_value_array_get_size:
633  * @value: a #GValue of type #GST_TYPE_ARRAY
634  *
635  * Gets the number of values contained in @value.
636  *
637  * Returns: the number of values
638  */
639 guint
640 gst_value_array_get_size (const GValue * value)
641 {
642   g_return_val_if_fail (GST_VALUE_HOLDS_ARRAY (value), 0);
643
644   return ((GArray *) value->data[0].v_pointer)->len;
645 }
646
647 /**
648  * gst_value_array_get_value:
649  * @value: a #GValue of type #GST_TYPE_ARRAY
650  * @index: index of value to get from the array
651  *
652  * Gets the value that is a member of the array contained in @value and
653  * has the index @index.
654  *
655  * Returns: (transfer none): the value at the given index
656  */
657 const GValue *
658 gst_value_array_get_value (const GValue * value, guint index)
659 {
660   g_return_val_if_fail (GST_VALUE_HOLDS_ARRAY (value), NULL);
661   g_return_val_if_fail (index < gst_value_array_get_size (value), NULL);
662
663   return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer,
664       GValue, index);
665 }
666
667 static void
668 gst_value_transform_list_string (const GValue * src_value, GValue * dest_value)
669 {
670   gst_value_transform_any_list_string (src_value, dest_value, "{ ", " }");
671 }
672
673 static void
674 gst_value_transform_array_string (const GValue * src_value, GValue * dest_value)
675 {
676   gst_value_transform_any_list_string (src_value, dest_value, "< ", " >");
677 }
678
679 /* Do an unordered compare of the contents of a list */
680 static gint
681 gst_value_compare_list (const GValue * value1, const GValue * value2)
682 {
683   guint i, j;
684   GArray *array1 = value1->data[0].v_pointer;
685   GArray *array2 = value2->data[0].v_pointer;
686   GValue *v1;
687   GValue *v2;
688   gint len, to_remove;
689   guint8 *removed;
690   GstValueCompareFunc compare;
691
692   /* get length and do initial length check. */
693   len = array1->len;
694   if (len != array2->len)
695     return GST_VALUE_UNORDERED;
696
697   /* place to mark removed value indices of array2 */
698   removed = g_newa (guint8, len);
699   memset (removed, 0, len);
700   to_remove = len;
701
702   /* loop over array1, all items should be in array2. When we find an
703    * item in array2, remove it from array2 by marking it as removed */
704   for (i = 0; i < len; i++) {
705     v1 = &g_array_index (array1, GValue, i);
706     if ((compare = gst_value_get_compare_func (v1))) {
707       for (j = 0; j < len; j++) {
708         /* item is removed, we can skip it */
709         if (removed[j])
710           continue;
711         v2 = &g_array_index (array2, GValue, j);
712         if (gst_value_compare_with_func (v1, v2, compare) == GST_VALUE_EQUAL) {
713           /* mark item as removed now that we found it in array2 and 
714            * decrement the number of remaining items in array2. */
715           removed[j] = 1;
716           to_remove--;
717           break;
718         }
719       }
720       /* item in array1 and not in array2, UNORDERED */
721       if (j == len)
722         return GST_VALUE_UNORDERED;
723     } else
724       return GST_VALUE_UNORDERED;
725   }
726   /* if not all items were removed, array2 contained something not in array1 */
727   if (to_remove != 0)
728     return GST_VALUE_UNORDERED;
729
730   /* arrays are equal */
731   return GST_VALUE_EQUAL;
732 }
733
734 /* Perform an ordered comparison of the contents of an array */
735 static gint
736 gst_value_compare_array (const GValue * value1, const GValue * value2)
737 {
738   guint i;
739   GArray *array1 = value1->data[0].v_pointer;
740   GArray *array2 = value2->data[0].v_pointer;
741   guint len = array1->len;
742   GValue *v1;
743   GValue *v2;
744
745   if (len != array2->len)
746     return GST_VALUE_UNORDERED;
747
748   for (i = 0; i < len; i++) {
749     v1 = &g_array_index (array1, GValue, i);
750     v2 = &g_array_index (array2, GValue, i);
751     if (gst_value_compare (v1, v2) != GST_VALUE_EQUAL)
752       return GST_VALUE_UNORDERED;
753   }
754
755   return GST_VALUE_EQUAL;
756 }
757
758 static gchar *
759 gst_value_serialize_list (const GValue * value)
760 {
761   return gst_value_serialize_any_list (value, "{ ", " }");
762 }
763
764 static gboolean
765 gst_value_deserialize_list (GValue * dest, const gchar * s)
766 {
767   g_warning ("gst_value_deserialize_list: unimplemented");
768   return FALSE;
769 }
770
771 static gchar *
772 gst_value_serialize_array (const GValue * value)
773 {
774   return gst_value_serialize_any_list (value, "< ", " >");
775 }
776
777 static gboolean
778 gst_value_deserialize_array (GValue * dest, const gchar * s)
779 {
780   g_warning ("gst_value_deserialize_array: unimplemented");
781   return FALSE;
782 }
783
784 /*************
785  * int range *
786  *
787  * Values in the range are defined as any value greater or equal
788  * to min*step, AND lesser or equal to max*step.
789  * For step == 1, this falls back to the traditional range semantics.
790  *************/
791
792 #define INT_RANGE_MIN(v) (((gint *)((v)->data[0].v_pointer))[0])
793 #define INT_RANGE_MAX(v) (((gint *)((v)->data[0].v_pointer))[1])
794 #define INT_RANGE_STEP(v) (((gint *)((v)->data[0].v_pointer))[2])
795
796 static void
797 gst_value_init_int_range (GValue * value)
798 {
799   gint *vals = g_slice_alloc0 (3 * sizeof (gint));
800   value->data[0].v_pointer = vals;
801   INT_RANGE_MIN (value) = 0;
802   INT_RANGE_MAX (value) = 0;
803   INT_RANGE_STEP (value) = 1;
804 }
805
806 static void
807 gst_value_free_int_range (GValue * value)
808 {
809   g_return_if_fail (GST_VALUE_HOLDS_INT_RANGE (value));
810   g_slice_free1 (3 * sizeof (gint), value->data[0].v_pointer);
811   value->data[0].v_pointer = NULL;
812 }
813
814 static void
815 gst_value_copy_int_range (const GValue * src_value, GValue * dest_value)
816 {
817   gint *vals = (gint *) dest_value->data[0].v_pointer;
818   gint *src_vals = (gint *) src_value->data[0].v_pointer;
819
820   if (vals == NULL) {
821     gst_value_init_int_range (dest_value);
822   }
823   if (src_vals != NULL) {
824     INT_RANGE_MIN (dest_value) = INT_RANGE_MIN (src_value);
825     INT_RANGE_MAX (dest_value) = INT_RANGE_MAX (src_value);
826     INT_RANGE_STEP (dest_value) = INT_RANGE_STEP (src_value);
827   }
828 }
829
830 static gchar *
831 gst_value_collect_int_range (GValue * value, guint n_collect_values,
832     GTypeCValue * collect_values, guint collect_flags)
833 {
834   gint *vals = value->data[0].v_pointer;
835
836   if (n_collect_values != 2)
837     return g_strdup_printf ("not enough value locations for `%s' passed",
838         G_VALUE_TYPE_NAME (value));
839   if (collect_values[0].v_int >= collect_values[1].v_int)
840     return g_strdup_printf ("range start is not smaller than end for `%s'",
841         G_VALUE_TYPE_NAME (value));
842
843   if (vals == NULL) {
844     gst_value_init_int_range (value);
845   }
846
847   gst_value_set_int_range_step (value, collect_values[0].v_int,
848       collect_values[1].v_int, 1);
849
850   return NULL;
851 }
852
853 static gchar *
854 gst_value_lcopy_int_range (const GValue * value, guint n_collect_values,
855     GTypeCValue * collect_values, guint collect_flags)
856 {
857   guint32 *int_range_start = collect_values[0].v_pointer;
858   guint32 *int_range_end = collect_values[1].v_pointer;
859   guint32 *int_range_step = collect_values[2].v_pointer;
860   gint *vals = (gint *) value->data[0].v_pointer;
861
862   if (!int_range_start)
863     return g_strdup_printf ("start value location for `%s' passed as NULL",
864         G_VALUE_TYPE_NAME (value));
865   if (!int_range_end)
866     return g_strdup_printf ("end value location for `%s' passed as NULL",
867         G_VALUE_TYPE_NAME (value));
868   if (!int_range_step)
869     return g_strdup_printf ("step value location for `%s' passed as NULL",
870         G_VALUE_TYPE_NAME (value));
871
872   if (G_UNLIKELY (vals == NULL)) {
873     return g_strdup_printf ("Uninitialised `%s' passed",
874         G_VALUE_TYPE_NAME (value));
875   }
876
877   *int_range_start = INT_RANGE_MIN (value);
878   *int_range_end = INT_RANGE_MAX (value);
879   *int_range_step = INT_RANGE_STEP (value);
880
881   return NULL;
882 }
883
884 /**
885  * gst_value_set_int_range_step:
886  * @value: a GValue initialized to GST_TYPE_INT_RANGE
887  * @start: the start of the range
888  * @end: the end of the range
889  * @step: the step of the range
890  *
891  * Sets @value to the range specified by @start, @end and @step.
892  */
893 void
894 gst_value_set_int_range_step (GValue * value, gint start, gint end, gint step)
895 {
896   g_return_if_fail (GST_VALUE_HOLDS_INT_RANGE (value));
897   g_return_if_fail (start < end);
898   g_return_if_fail (step > 0);
899   g_return_if_fail (start % step == 0);
900   g_return_if_fail (end % step == 0);
901
902   INT_RANGE_MIN (value) = start / step;
903   INT_RANGE_MAX (value) = end / step;
904   INT_RANGE_STEP (value) = step;
905 }
906
907 /**
908  * gst_value_set_int_range:
909  * @value: a GValue initialized to GST_TYPE_INT_RANGE
910  * @start: the start of the range
911  * @end: the end of the range
912  *
913  * Sets @value to the range specified by @start and @end.
914  */
915 void
916 gst_value_set_int_range (GValue * value, gint start, gint end)
917 {
918   gst_value_set_int_range_step (value, start, end, 1);
919 }
920
921 /**
922  * gst_value_get_int_range_min:
923  * @value: a GValue initialized to GST_TYPE_INT_RANGE
924  *
925  * Gets the minimum of the range specified by @value.
926  *
927  * Returns: the minimum of the range
928  */
929 gint
930 gst_value_get_int_range_min (const GValue * value)
931 {
932   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
933
934   return INT_RANGE_MIN (value) * INT_RANGE_STEP (value);
935 }
936
937 /**
938  * gst_value_get_int_range_max:
939  * @value: a GValue initialized to GST_TYPE_INT_RANGE
940  *
941  * Gets the maximum of the range specified by @value.
942  *
943  * Returns: the maxumum of the range
944  */
945 gint
946 gst_value_get_int_range_max (const GValue * value)
947 {
948   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
949
950   return INT_RANGE_MAX (value) * INT_RANGE_STEP (value);
951 }
952
953 /**
954  * gst_value_get_int_range_step:
955  * @value: a GValue initialized to GST_TYPE_INT_RANGE
956  *
957  * Gets the step of the range specified by @value.
958  *
959  * Returns: the step of the range
960  */
961 gint
962 gst_value_get_int_range_step (const GValue * value)
963 {
964   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
965
966   return INT_RANGE_STEP (value);
967 }
968
969 static void
970 gst_value_transform_int_range_string (const GValue * src_value,
971     GValue * dest_value)
972 {
973   if (INT_RANGE_STEP (src_value) == 1)
974     dest_value->data[0].v_pointer = g_strdup_printf ("[%d,%d]",
975         INT_RANGE_MIN (src_value), INT_RANGE_MAX (src_value));
976   else
977     dest_value->data[0].v_pointer = g_strdup_printf ("[%d,%d,%d]",
978         INT_RANGE_MIN (src_value) * INT_RANGE_STEP (src_value),
979         INT_RANGE_MAX (src_value) * INT_RANGE_STEP (src_value),
980         INT_RANGE_STEP (src_value));
981 }
982
983 static gint
984 gst_value_compare_int_range (const GValue * value1, const GValue * value2)
985 {
986   /* calculate the number of values in each range */
987   gint n1 = INT_RANGE_MAX (value1) - INT_RANGE_MIN (value1) + 1;
988   gint n2 = INT_RANGE_MAX (value2) - INT_RANGE_MIN (value2) + 1;
989
990   /* they must be equal */
991   if (n1 != n2)
992     return GST_VALUE_UNORDERED;
993
994   /* if empty, equal */
995   if (n1 == 0)
996     return GST_VALUE_EQUAL;
997
998   /* if more than one value, then it is only equal if the step is equal
999      and bounds lie on the same value */
1000   if (n1 > 1) {
1001     if (INT_RANGE_STEP (value1) == INT_RANGE_STEP (value2) &&
1002         INT_RANGE_STEP (value1) == INT_RANGE_STEP (value2) &&
1003         INT_RANGE_STEP (value1) == INT_RANGE_STEP (value2)) {
1004       return GST_VALUE_EQUAL;
1005     }
1006     return GST_VALUE_UNORDERED;
1007   } else {
1008     /* if just one, only if the value is equal */
1009     if (INT_RANGE_MIN (value1) == INT_RANGE_MIN (value2))
1010       return GST_VALUE_EQUAL;
1011     return GST_VALUE_UNORDERED;
1012   }
1013 }
1014
1015 static gchar *
1016 gst_value_serialize_int_range (const GValue * value)
1017 {
1018   if (INT_RANGE_STEP (value) == 1)
1019     return g_strdup_printf ("[ %d, %d ]", INT_RANGE_MIN (value),
1020         INT_RANGE_MAX (value));
1021   else
1022     return g_strdup_printf ("[ %d, %d, %d ]",
1023         INT_RANGE_MIN (value) * INT_RANGE_STEP (value),
1024         INT_RANGE_MAX (value) * INT_RANGE_STEP (value), INT_RANGE_STEP (value));
1025 }
1026
1027 static gboolean
1028 gst_value_deserialize_int_range (GValue * dest, const gchar * s)
1029 {
1030   g_warning ("unimplemented");
1031   return FALSE;
1032 }
1033
1034 /***************
1035  * int64 range *
1036  *
1037  * Values in the range are defined as any value greater or equal
1038  * to min*step, AND lesser or equal to max*step.
1039  * For step == 1, this falls back to the traditional range semantics.
1040  ***************/
1041
1042 #define INT64_RANGE_MIN(v) (((gint64 *)((v)->data[0].v_pointer))[0])
1043 #define INT64_RANGE_MAX(v) (((gint64 *)((v)->data[0].v_pointer))[1])
1044 #define INT64_RANGE_STEP(v) (((gint64 *)((v)->data[0].v_pointer))[2])
1045
1046 static void
1047 gst_value_init_int64_range (GValue * value)
1048 {
1049   gint64 *vals = g_slice_alloc0 (3 * sizeof (gint64));
1050   value->data[0].v_pointer = vals;
1051   INT64_RANGE_MIN (value) = 0;
1052   INT64_RANGE_MAX (value) = 0;
1053   INT64_RANGE_STEP (value) = 1;
1054 }
1055
1056 static void
1057 gst_value_free_int64_range (GValue * value)
1058 {
1059   g_return_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value));
1060   g_slice_free1 (3 * sizeof (gint64), value->data[0].v_pointer);
1061   value->data[0].v_pointer = NULL;
1062 }
1063
1064 static void
1065 gst_value_copy_int64_range (const GValue * src_value, GValue * dest_value)
1066 {
1067   gint64 *vals = (gint64 *) dest_value->data[0].v_pointer;
1068   gint64 *src_vals = (gint64 *) src_value->data[0].v_pointer;
1069
1070   if (vals == NULL) {
1071     gst_value_init_int64_range (dest_value);
1072   }
1073
1074   if (src_vals != NULL) {
1075     INT64_RANGE_MIN (dest_value) = INT64_RANGE_MIN (src_value);
1076     INT64_RANGE_MAX (dest_value) = INT64_RANGE_MAX (src_value);
1077     INT64_RANGE_STEP (dest_value) = INT64_RANGE_STEP (src_value);
1078   }
1079 }
1080
1081 static gchar *
1082 gst_value_collect_int64_range (GValue * value, guint n_collect_values,
1083     GTypeCValue * collect_values, guint collect_flags)
1084 {
1085   gint64 *vals = value->data[0].v_pointer;
1086
1087   if (n_collect_values != 2)
1088     return g_strdup_printf ("not enough value locations for `%s' passed",
1089         G_VALUE_TYPE_NAME (value));
1090   if (collect_values[0].v_int64 >= collect_values[1].v_int64)
1091     return g_strdup_printf ("range start is not smaller than end for `%s'",
1092         G_VALUE_TYPE_NAME (value));
1093
1094   if (vals == NULL) {
1095     gst_value_init_int64_range (value);
1096   }
1097
1098   gst_value_set_int64_range_step (value, collect_values[0].v_int64,
1099       collect_values[1].v_int64, 1);
1100
1101   return NULL;
1102 }
1103
1104 static gchar *
1105 gst_value_lcopy_int64_range (const GValue * value, guint n_collect_values,
1106     GTypeCValue * collect_values, guint collect_flags)
1107 {
1108   guint64 *int_range_start = collect_values[0].v_pointer;
1109   guint64 *int_range_end = collect_values[1].v_pointer;
1110   guint64 *int_range_step = collect_values[2].v_pointer;
1111   gint64 *vals = (gint64 *) value->data[0].v_pointer;
1112
1113   if (!int_range_start)
1114     return g_strdup_printf ("start value location for `%s' passed as NULL",
1115         G_VALUE_TYPE_NAME (value));
1116   if (!int_range_end)
1117     return g_strdup_printf ("end value location for `%s' passed as NULL",
1118         G_VALUE_TYPE_NAME (value));
1119   if (!int_range_step)
1120     return g_strdup_printf ("step value location for `%s' passed as NULL",
1121         G_VALUE_TYPE_NAME (value));
1122
1123   if (G_UNLIKELY (vals == NULL)) {
1124     return g_strdup_printf ("Uninitialised `%s' passed",
1125         G_VALUE_TYPE_NAME (value));
1126   }
1127
1128   *int_range_start = INT64_RANGE_MIN (value);
1129   *int_range_end = INT64_RANGE_MAX (value);
1130   *int_range_step = INT64_RANGE_STEP (value);
1131
1132   return NULL;
1133 }
1134
1135 /**
1136  * gst_value_set_int64_range_step:
1137  * @value: a GValue initialized to GST_TYPE_INT64_RANGE
1138  * @start: the start of the range
1139  * @end: the end of the range
1140  * @step: the step of the range
1141  *
1142  * Sets @value to the range specified by @start, @end and @step.
1143  *
1144  * Since: 0.11.0
1145  */
1146 void
1147 gst_value_set_int64_range_step (GValue * value, gint64 start, gint64 end,
1148     gint64 step)
1149 {
1150   g_return_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value));
1151   g_return_if_fail (start < end);
1152   g_return_if_fail (step > 0);
1153   g_return_if_fail (start % step == 0);
1154   g_return_if_fail (end % step == 0);
1155
1156   INT64_RANGE_MIN (value) = start / step;
1157   INT64_RANGE_MAX (value) = end / step;
1158   INT64_RANGE_STEP (value) = step;
1159 }
1160
1161 /**
1162  * gst_value_set_int64_range:
1163  * @value: a GValue initialized to GST_TYPE_INT64_RANGE
1164  * @start: the start of the range
1165  * @end: the end of the range
1166  *
1167  * Sets @value to the range specified by @start and @end.
1168  *
1169  * Since: 0.10.31
1170  */
1171 void
1172 gst_value_set_int64_range (GValue * value, gint64 start, gint64 end)
1173 {
1174   gst_value_set_int64_range_step (value, start, end, 1);
1175 }
1176
1177 /**
1178  * gst_value_get_int64_range_min:
1179  * @value: a GValue initialized to GST_TYPE_INT64_RANGE
1180  *
1181  * Gets the minimum of the range specified by @value.
1182  *
1183  * Returns: the minimum of the range
1184  *
1185  * Since: 0.10.31
1186  */
1187 gint64
1188 gst_value_get_int64_range_min (const GValue * value)
1189 {
1190   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value), 0);
1191
1192   return INT64_RANGE_MIN (value) * INT64_RANGE_STEP (value);
1193 }
1194
1195 /**
1196  * gst_value_get_int64_range_max:
1197  * @value: a GValue initialized to GST_TYPE_INT64_RANGE
1198  *
1199  * Gets the maximum of the range specified by @value.
1200  *
1201  * Returns: the maxumum of the range
1202  *
1203  * Since: 0.10.31
1204  */
1205 gint64
1206 gst_value_get_int64_range_max (const GValue * value)
1207 {
1208   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value), 0);
1209
1210   return INT64_RANGE_MAX (value) * INT64_RANGE_STEP (value);
1211 }
1212
1213 /**
1214  * gst_value_get_int64_range_step:
1215  * @value: a GValue initialized to GST_TYPE_INT64_RANGE
1216  *
1217  * Gets the step of the range specified by @value.
1218  *
1219  * Returns: the step of the range
1220  *
1221  * Since: 0.11.0
1222  */
1223 gint64
1224 gst_value_get_int64_range_step (const GValue * value)
1225 {
1226   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value), 0);
1227
1228   return INT64_RANGE_STEP (value);
1229 }
1230
1231 static void
1232 gst_value_transform_int64_range_string (const GValue * src_value,
1233     GValue * dest_value)
1234 {
1235   if (INT64_RANGE_STEP (src_value) == 1)
1236     dest_value->data[0].v_pointer =
1237         g_strdup_printf ("(gint64)[%" G_GINT64_FORMAT ",%" G_GINT64_FORMAT "]",
1238         INT64_RANGE_MIN (src_value), INT64_RANGE_MAX (src_value));
1239   else
1240     dest_value->data[0].v_pointer =
1241         g_strdup_printf ("(gint64)[%" G_GINT64_FORMAT ",%" G_GINT64_FORMAT
1242         ",%" G_GINT64_FORMAT "]",
1243         INT64_RANGE_MIN (src_value) * INT64_RANGE_STEP (src_value),
1244         INT64_RANGE_MAX (src_value) * INT64_RANGE_STEP (src_value),
1245         INT64_RANGE_STEP (src_value));
1246 }
1247
1248 static gint
1249 gst_value_compare_int64_range (const GValue * value1, const GValue * value2)
1250 {
1251   /* calculate the number of values in each range */
1252   gint64 n1 = INT64_RANGE_MAX (value1) - INT64_RANGE_MIN (value1) + 1;
1253   gint64 n2 = INT64_RANGE_MAX (value2) - INT64_RANGE_MIN (value2) + 1;
1254
1255   /* they must be equal */
1256   if (n1 != n2)
1257     return GST_VALUE_UNORDERED;
1258
1259   /* if empty, equal */
1260   if (n1 == 0)
1261     return GST_VALUE_EQUAL;
1262
1263   /* if more than one value, then it is only equal if the step is equal
1264      and bounds lie on the same value */
1265   if (n1 > 1) {
1266     if (INT64_RANGE_STEP (value1) == INT64_RANGE_STEP (value2) &&
1267         INT64_RANGE_STEP (value1) == INT64_RANGE_STEP (value2) &&
1268         INT64_RANGE_STEP (value1) == INT64_RANGE_STEP (value2)) {
1269       return GST_VALUE_EQUAL;
1270     }
1271     return GST_VALUE_UNORDERED;
1272   } else {
1273     /* if just one, only if the value is equal */
1274     if (INT64_RANGE_MIN (value1) == INT64_RANGE_MIN (value2))
1275       return GST_VALUE_EQUAL;
1276     return GST_VALUE_UNORDERED;
1277   }
1278 }
1279
1280 static gchar *
1281 gst_value_serialize_int64_range (const GValue * value)
1282 {
1283   if (INT64_RANGE_STEP (value) == 1)
1284     return g_strdup_printf ("[ %" G_GINT64_FORMAT ", %" G_GINT64_FORMAT " ]",
1285         INT64_RANGE_MIN (value), INT64_RANGE_MAX (value));
1286   else
1287     return g_strdup_printf ("[ %" G_GINT64_FORMAT ", %" G_GINT64_FORMAT ", %"
1288         G_GINT64_FORMAT " ]",
1289         INT64_RANGE_MIN (value) * INT64_RANGE_STEP (value),
1290         INT64_RANGE_MAX (value) * INT64_RANGE_STEP (value),
1291         INT64_RANGE_STEP (value));
1292 }
1293
1294 static gboolean
1295 gst_value_deserialize_int64_range (GValue * dest, const gchar * s)
1296 {
1297   g_warning ("unimplemented");
1298   return FALSE;
1299 }
1300
1301 /****************
1302  * double range *
1303  ****************/
1304
1305 static void
1306 gst_value_init_double_range (GValue * value)
1307 {
1308   value->data[0].v_double = 0;
1309   value->data[1].v_double = 0;
1310 }
1311
1312 static void
1313 gst_value_copy_double_range (const GValue * src_value, GValue * dest_value)
1314 {
1315   dest_value->data[0].v_double = src_value->data[0].v_double;
1316   dest_value->data[1].v_double = src_value->data[1].v_double;
1317 }
1318
1319 static gchar *
1320 gst_value_collect_double_range (GValue * value, guint n_collect_values,
1321     GTypeCValue * collect_values, guint collect_flags)
1322 {
1323   if (n_collect_values != 2)
1324     return g_strdup_printf ("not enough value locations for `%s' passed",
1325         G_VALUE_TYPE_NAME (value));
1326   if (collect_values[0].v_double >= collect_values[1].v_double)
1327     return g_strdup_printf ("range start is not smaller than end for `%s'",
1328         G_VALUE_TYPE_NAME (value));
1329
1330   value->data[0].v_double = collect_values[0].v_double;
1331   value->data[1].v_double = collect_values[1].v_double;
1332
1333   return NULL;
1334 }
1335
1336 static gchar *
1337 gst_value_lcopy_double_range (const GValue * value, guint n_collect_values,
1338     GTypeCValue * collect_values, guint collect_flags)
1339 {
1340   gdouble *double_range_start = collect_values[0].v_pointer;
1341   gdouble *double_range_end = collect_values[1].v_pointer;
1342
1343   if (!double_range_start)
1344     return g_strdup_printf ("start value location for `%s' passed as NULL",
1345         G_VALUE_TYPE_NAME (value));
1346   if (!double_range_end)
1347     return g_strdup_printf ("end value location for `%s' passed as NULL",
1348         G_VALUE_TYPE_NAME (value));
1349
1350   *double_range_start = value->data[0].v_double;
1351   *double_range_end = value->data[1].v_double;
1352
1353   return NULL;
1354 }
1355
1356 /**
1357  * gst_value_set_double_range:
1358  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
1359  * @start: the start of the range
1360  * @end: the end of the range
1361  *
1362  * Sets @value to the range specified by @start and @end.
1363  */
1364 void
1365 gst_value_set_double_range (GValue * value, gdouble start, gdouble end)
1366 {
1367   g_return_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value));
1368   g_return_if_fail (start < end);
1369
1370   value->data[0].v_double = start;
1371   value->data[1].v_double = end;
1372 }
1373
1374 /**
1375  * gst_value_get_double_range_min:
1376  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
1377  *
1378  * Gets the minimum of the range specified by @value.
1379  *
1380  * Returns: the minimum of the range
1381  */
1382 gdouble
1383 gst_value_get_double_range_min (const GValue * value)
1384 {
1385   g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
1386
1387   return value->data[0].v_double;
1388 }
1389
1390 /**
1391  * gst_value_get_double_range_max:
1392  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
1393  *
1394  * Gets the maximum of the range specified by @value.
1395  *
1396  * Returns: the maxumum of the range
1397  */
1398 gdouble
1399 gst_value_get_double_range_max (const GValue * value)
1400 {
1401   g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
1402
1403   return value->data[1].v_double;
1404 }
1405
1406 static void
1407 gst_value_transform_double_range_string (const GValue * src_value,
1408     GValue * dest_value)
1409 {
1410   gchar s1[G_ASCII_DTOSTR_BUF_SIZE], s2[G_ASCII_DTOSTR_BUF_SIZE];
1411
1412   dest_value->data[0].v_pointer = g_strdup_printf ("[%s,%s]",
1413       g_ascii_dtostr (s1, G_ASCII_DTOSTR_BUF_SIZE,
1414           src_value->data[0].v_double),
1415       g_ascii_dtostr (s2, G_ASCII_DTOSTR_BUF_SIZE,
1416           src_value->data[1].v_double));
1417 }
1418
1419 static gint
1420 gst_value_compare_double_range (const GValue * value1, const GValue * value2)
1421 {
1422   if (value2->data[0].v_double == value1->data[0].v_double &&
1423       value2->data[0].v_double == value1->data[0].v_double)
1424     return GST_VALUE_EQUAL;
1425   return GST_VALUE_UNORDERED;
1426 }
1427
1428 static gchar *
1429 gst_value_serialize_double_range (const GValue * value)
1430 {
1431   gchar d1[G_ASCII_DTOSTR_BUF_SIZE];
1432   gchar d2[G_ASCII_DTOSTR_BUF_SIZE];
1433
1434   g_ascii_dtostr (d1, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
1435   g_ascii_dtostr (d2, G_ASCII_DTOSTR_BUF_SIZE, value->data[1].v_double);
1436   return g_strdup_printf ("[ %s, %s ]", d1, d2);
1437 }
1438
1439 static gboolean
1440 gst_value_deserialize_double_range (GValue * dest, const gchar * s)
1441 {
1442   g_warning ("unimplemented");
1443   return FALSE;
1444 }
1445
1446 /****************
1447  * fraction range *
1448  ****************/
1449
1450 static void
1451 gst_value_init_fraction_range (GValue * value)
1452 {
1453   GValue *vals;
1454   GType ftype;
1455
1456   ftype = GST_TYPE_FRACTION;
1457
1458   value->data[0].v_pointer = vals = g_slice_alloc0 (2 * sizeof (GValue));
1459   g_value_init (&vals[0], ftype);
1460   g_value_init (&vals[1], ftype);
1461 }
1462
1463 static void
1464 gst_value_free_fraction_range (GValue * value)
1465 {
1466   GValue *vals = (GValue *) value->data[0].v_pointer;
1467
1468   if (vals != NULL) {
1469     /* we know the two values contain fractions without internal allocs */
1470     /* g_value_unset (&vals[0]); */
1471     /* g_value_unset (&vals[1]); */
1472     g_slice_free1 (2 * sizeof (GValue), vals);
1473     value->data[0].v_pointer = NULL;
1474   }
1475 }
1476
1477 static void
1478 gst_value_copy_fraction_range (const GValue * src_value, GValue * dest_value)
1479 {
1480   GValue *vals = (GValue *) dest_value->data[0].v_pointer;
1481   GValue *src_vals = (GValue *) src_value->data[0].v_pointer;
1482
1483   if (vals == NULL) {
1484     gst_value_init_fraction_range (dest_value);
1485     vals = dest_value->data[0].v_pointer;
1486   }
1487   if (src_vals != NULL) {
1488     g_value_copy (&src_vals[0], &vals[0]);
1489     g_value_copy (&src_vals[1], &vals[1]);
1490   }
1491 }
1492
1493 static gchar *
1494 gst_value_collect_fraction_range (GValue * value, guint n_collect_values,
1495     GTypeCValue * collect_values, guint collect_flags)
1496 {
1497   GValue *vals = (GValue *) value->data[0].v_pointer;
1498
1499   if (n_collect_values != 4)
1500     return g_strdup_printf ("not enough value locations for `%s' passed",
1501         G_VALUE_TYPE_NAME (value));
1502   if (collect_values[1].v_int == 0)
1503     return g_strdup_printf ("passed '0' as first denominator for `%s'",
1504         G_VALUE_TYPE_NAME (value));
1505   if (collect_values[3].v_int == 0)
1506     return g_strdup_printf ("passed '0' as second denominator for `%s'",
1507         G_VALUE_TYPE_NAME (value));
1508   if (gst_util_fraction_compare (collect_values[0].v_int,
1509           collect_values[1].v_int, collect_values[2].v_int,
1510           collect_values[3].v_int) >= 0)
1511     return g_strdup_printf ("range start is not smaller than end for `%s'",
1512         G_VALUE_TYPE_NAME (value));
1513
1514   if (vals == NULL) {
1515     gst_value_init_fraction_range (value);
1516     vals = value->data[0].v_pointer;
1517   }
1518
1519   gst_value_set_fraction (&vals[0], collect_values[0].v_int,
1520       collect_values[1].v_int);
1521   gst_value_set_fraction (&vals[1], collect_values[2].v_int,
1522       collect_values[3].v_int);
1523
1524   return NULL;
1525 }
1526
1527 static gchar *
1528 gst_value_lcopy_fraction_range (const GValue * value, guint n_collect_values,
1529     GTypeCValue * collect_values, guint collect_flags)
1530 {
1531   gint i;
1532   gint *dest_values[4];
1533   GValue *vals = (GValue *) value->data[0].v_pointer;
1534
1535   if (G_UNLIKELY (n_collect_values != 4))
1536     return g_strdup_printf ("not enough value locations for `%s' passed",
1537         G_VALUE_TYPE_NAME (value));
1538
1539   for (i = 0; i < 4; i++) {
1540     if (G_UNLIKELY (collect_values[i].v_pointer == NULL)) {
1541       return g_strdup_printf ("value location for `%s' passed as NULL",
1542           G_VALUE_TYPE_NAME (value));
1543     }
1544     dest_values[i] = collect_values[i].v_pointer;
1545   }
1546
1547   if (G_UNLIKELY (vals == NULL)) {
1548     return g_strdup_printf ("Uninitialised `%s' passed",
1549         G_VALUE_TYPE_NAME (value));
1550   }
1551
1552   dest_values[0][0] = gst_value_get_fraction_numerator (&vals[0]);
1553   dest_values[1][0] = gst_value_get_fraction_denominator (&vals[0]);
1554   dest_values[2][0] = gst_value_get_fraction_numerator (&vals[1]);
1555   dest_values[3][0] = gst_value_get_fraction_denominator (&vals[1]);
1556   return NULL;
1557 }
1558
1559 /**
1560  * gst_value_set_fraction_range:
1561  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1562  * @start: the start of the range (a GST_TYPE_FRACTION GValue)
1563  * @end: the end of the range (a GST_TYPE_FRACTION GValue)
1564  *
1565  * Sets @value to the range specified by @start and @end.
1566  */
1567 void
1568 gst_value_set_fraction_range (GValue * value, const GValue * start,
1569     const GValue * end)
1570 {
1571   GValue *vals;
1572
1573   g_return_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value));
1574   g_return_if_fail (GST_VALUE_HOLDS_FRACTION (start));
1575   g_return_if_fail (GST_VALUE_HOLDS_FRACTION (end));
1576   g_return_if_fail (gst_util_fraction_compare (start->data[0].v_int,
1577           start->data[1].v_int, end->data[0].v_int, end->data[1].v_int) < 0);
1578
1579   vals = (GValue *) value->data[0].v_pointer;
1580   if (vals == NULL) {
1581     gst_value_init_fraction_range (value);
1582     vals = value->data[0].v_pointer;
1583   }
1584   g_value_copy (start, &vals[0]);
1585   g_value_copy (end, &vals[1]);
1586 }
1587
1588 /**
1589  * gst_value_set_fraction_range_full:
1590  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1591  * @numerator_start: the numerator start of the range
1592  * @denominator_start: the denominator start of the range
1593  * @numerator_end: the numerator end of the range
1594  * @denominator_end: the denominator end of the range
1595  *
1596  * Sets @value to the range specified by @numerator_start/@denominator_start
1597  * and @numerator_end/@denominator_end.
1598  */
1599 void
1600 gst_value_set_fraction_range_full (GValue * value,
1601     gint numerator_start, gint denominator_start,
1602     gint numerator_end, gint denominator_end)
1603 {
1604   GValue start = { 0 };
1605   GValue end = { 0 };
1606
1607   g_return_if_fail (value != NULL);
1608   g_return_if_fail (denominator_start != 0);
1609   g_return_if_fail (denominator_end != 0);
1610   g_return_if_fail (gst_util_fraction_compare (numerator_start,
1611           denominator_start, numerator_end, denominator_end) < 0);
1612
1613   g_value_init (&start, GST_TYPE_FRACTION);
1614   g_value_init (&end, GST_TYPE_FRACTION);
1615
1616   gst_value_set_fraction (&start, numerator_start, denominator_start);
1617   gst_value_set_fraction (&end, numerator_end, denominator_end);
1618   gst_value_set_fraction_range (value, &start, &end);
1619
1620   /* we know the two values contain fractions without internal allocs */
1621   /* g_value_unset (&start); */
1622   /* g_value_unset (&end);   */
1623 }
1624
1625 /**
1626  * gst_value_get_fraction_range_min:
1627  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1628  *
1629  * Gets the minimum of the range specified by @value.
1630  *
1631  * Returns: the minimum of the range
1632  */
1633 const GValue *
1634 gst_value_get_fraction_range_min (const GValue * value)
1635 {
1636   GValue *vals;
1637
1638   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value), NULL);
1639
1640   vals = (GValue *) value->data[0].v_pointer;
1641   if (vals != NULL) {
1642     return &vals[0];
1643   }
1644
1645   return NULL;
1646 }
1647
1648 /**
1649  * gst_value_get_fraction_range_max:
1650  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1651  *
1652  * Gets the maximum of the range specified by @value.
1653  *
1654  * Returns: the maximum of the range
1655  */
1656 const GValue *
1657 gst_value_get_fraction_range_max (const GValue * value)
1658 {
1659   GValue *vals;
1660
1661   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value), NULL);
1662
1663   vals = (GValue *) value->data[0].v_pointer;
1664   if (vals != NULL) {
1665     return &vals[1];
1666   }
1667
1668   return NULL;
1669 }
1670
1671 static gchar *
1672 gst_value_serialize_fraction_range (const GValue * value)
1673 {
1674   GValue *vals = (GValue *) value->data[0].v_pointer;
1675   gchar *retval;
1676
1677   if (vals == NULL) {
1678     retval = g_strdup ("[ 0/1, 0/1 ]");
1679   } else {
1680     gchar *start, *end;
1681
1682     start = gst_value_serialize_fraction (&vals[0]);
1683     end = gst_value_serialize_fraction (&vals[1]);
1684
1685     retval = g_strdup_printf ("[ %s, %s ]", start, end);
1686     g_free (start);
1687     g_free (end);
1688   }
1689
1690   return retval;
1691 }
1692
1693 static void
1694 gst_value_transform_fraction_range_string (const GValue * src_value,
1695     GValue * dest_value)
1696 {
1697   dest_value->data[0].v_pointer =
1698       gst_value_serialize_fraction_range (src_value);
1699 }
1700
1701 static gint
1702 gst_value_compare_fraction_range (const GValue * value1, const GValue * value2)
1703 {
1704   GValue *vals1, *vals2;
1705   GstValueCompareFunc compare;
1706
1707   if (value2->data[0].v_pointer == value1->data[0].v_pointer)
1708     return GST_VALUE_EQUAL;     /* Only possible if both are NULL */
1709
1710   if (value2->data[0].v_pointer == NULL || value1->data[0].v_pointer == NULL)
1711     return GST_VALUE_UNORDERED;
1712
1713   vals1 = (GValue *) value1->data[0].v_pointer;
1714   vals2 = (GValue *) value2->data[0].v_pointer;
1715   if ((compare = gst_value_get_compare_func (&vals1[0]))) {
1716     if (gst_value_compare_with_func (&vals1[0], &vals2[0], compare) ==
1717         GST_VALUE_EQUAL &&
1718         gst_value_compare_with_func (&vals1[1], &vals2[1], compare) ==
1719         GST_VALUE_EQUAL)
1720       return GST_VALUE_EQUAL;
1721   }
1722   return GST_VALUE_UNORDERED;
1723 }
1724
1725 static gboolean
1726 gst_value_deserialize_fraction_range (GValue * dest, const gchar * s)
1727 {
1728   g_warning ("unimplemented");
1729   return FALSE;
1730 }
1731
1732 /***********
1733  * GstCaps *
1734  ***********/
1735
1736 /**
1737  * gst_value_set_caps:
1738  * @value: a GValue initialized to GST_TYPE_CAPS
1739  * @caps: (transfer none): the caps to set the value to
1740  *
1741  * Sets the contents of @value to @caps. A reference to the
1742  * provided @caps will be taken by the @value.
1743  */
1744 void
1745 gst_value_set_caps (GValue * value, const GstCaps * caps)
1746 {
1747   g_return_if_fail (G_IS_VALUE (value));
1748   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS);
1749   g_return_if_fail (caps == NULL || GST_IS_CAPS (caps));
1750
1751   g_value_set_boxed (value, caps);
1752 }
1753
1754 /**
1755  * gst_value_get_caps:
1756  * @value: a GValue initialized to GST_TYPE_CAPS
1757  *
1758  * Gets the contents of @value. The reference count of the returned
1759  * #GstCaps will not be modified, therefore the caller must take one
1760  * before getting rid of the @value.
1761  *
1762  * Returns: (transfer none): the contents of @value
1763  */
1764 const GstCaps *
1765 gst_value_get_caps (const GValue * value)
1766 {
1767   g_return_val_if_fail (G_IS_VALUE (value), NULL);
1768   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS, NULL);
1769
1770   return (GstCaps *) g_value_get_boxed (value);
1771 }
1772
1773 static gchar *
1774 gst_value_serialize_caps (const GValue * value)
1775 {
1776   GstCaps *caps = g_value_get_boxed (value);
1777
1778   return gst_caps_to_string (caps);
1779 }
1780
1781 static gboolean
1782 gst_value_deserialize_caps (GValue * dest, const gchar * s)
1783 {
1784   GstCaps *caps;
1785
1786   caps = gst_caps_from_string (s);
1787
1788   if (caps) {
1789     g_value_take_boxed (dest, caps);
1790     return TRUE;
1791   }
1792   return FALSE;
1793 }
1794
1795 /****************
1796  * GstStructure *
1797  ****************/
1798
1799 /**
1800  * gst_value_set_structure:
1801  * @value: a GValue initialized to GST_TYPE_STRUCTURE
1802  * @structure: the structure to set the value to
1803  *
1804  * Sets the contents of @value to @structure.  The actual
1805  *
1806  * Since: 0.10.15
1807  */
1808 void
1809 gst_value_set_structure (GValue * value, const GstStructure * structure)
1810 {
1811   g_return_if_fail (G_IS_VALUE (value));
1812   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE);
1813   g_return_if_fail (structure == NULL || GST_IS_STRUCTURE (structure));
1814
1815   g_value_set_boxed (value, structure);
1816 }
1817
1818 /**
1819  * gst_value_get_structure:
1820  * @value: a GValue initialized to GST_TYPE_STRUCTURE
1821  *
1822  * Gets the contents of @value.
1823  *
1824  * Returns: (transfer none): the contents of @value
1825  *
1826  * Since: 0.10.15
1827  */
1828 const GstStructure *
1829 gst_value_get_structure (const GValue * value)
1830 {
1831   g_return_val_if_fail (G_IS_VALUE (value), NULL);
1832   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE, NULL);
1833
1834   return (GstStructure *) g_value_get_boxed (value);
1835 }
1836
1837 static gchar *
1838 gst_value_serialize_structure (const GValue * value)
1839 {
1840   GstStructure *structure = g_value_get_boxed (value);
1841
1842   return gst_string_take_and_wrap (gst_structure_to_string (structure));
1843 }
1844
1845 static gboolean
1846 gst_value_deserialize_structure (GValue * dest, const gchar * s)
1847 {
1848   GstStructure *structure;
1849
1850   if (*s != '"') {
1851     structure = gst_structure_from_string (s, NULL);
1852   } else {
1853     gchar *str = gst_string_unwrap (s);
1854
1855     if (G_UNLIKELY (!str))
1856       return FALSE;
1857
1858     structure = gst_structure_from_string (str, NULL);
1859     g_free (str);
1860   }
1861
1862   if (G_LIKELY (structure)) {
1863     g_value_take_boxed (dest, structure);
1864     return TRUE;
1865   }
1866   return FALSE;
1867 }
1868
1869 /*************
1870  * GstBuffer *
1871  *************/
1872
1873 static gint
1874 gst_value_compare_buffer (const GValue * value1, const GValue * value2)
1875 {
1876   GstBuffer *buf1 = gst_value_get_buffer (value1);
1877   GstBuffer *buf2 = gst_value_get_buffer (value2);
1878   gsize size1, size2;
1879   GstMapInfo info1, info2;
1880   gint result = GST_VALUE_UNORDERED;
1881
1882   size1 = gst_buffer_get_size (buf1);
1883   size2 = gst_buffer_get_size (buf2);
1884
1885   if (size1 != size2)
1886     return GST_VALUE_UNORDERED;
1887
1888   if (size1 == 0)
1889     return GST_VALUE_EQUAL;
1890
1891   if (!gst_buffer_map (buf1, &info1, GST_MAP_READ))
1892     return GST_VALUE_UNORDERED;
1893
1894   if (!gst_buffer_map (buf2, &info2, GST_MAP_READ)) {
1895     gst_buffer_unmap (buf1, &info2);
1896     return GST_VALUE_UNORDERED;
1897   }
1898
1899   if (memcmp (info1.data, info2.data, info1.size) == 0)
1900     result = GST_VALUE_EQUAL;
1901
1902   gst_buffer_unmap (buf2, &info1);
1903   gst_buffer_unmap (buf1, &info2);
1904
1905   return result;
1906 }
1907
1908 static gchar *
1909 gst_value_serialize_buffer (const GValue * value)
1910 {
1911   GstMapInfo info;
1912   guint8 *data;
1913   gint i;
1914   gchar *string;
1915   GstBuffer *buffer;
1916
1917   buffer = gst_value_get_buffer (value);
1918   if (buffer == NULL)
1919     return NULL;
1920
1921   if (!gst_buffer_map (buffer, &info, GST_MAP_READ))
1922     return NULL;
1923
1924   data = info.data;
1925
1926   string = g_malloc (info.size * 2 + 1);
1927   for (i = 0; i < info.size; i++) {
1928     sprintf (string + i * 2, "%02x", data[i]);
1929   }
1930   string[info.size * 2] = 0;
1931
1932   gst_buffer_unmap (buffer, &info);
1933
1934   return string;
1935 }
1936
1937 static gboolean
1938 gst_value_deserialize_buffer (GValue * dest, const gchar * s)
1939 {
1940   GstBuffer *buffer;
1941   gint len;
1942   gchar ts[3];
1943   GstMapInfo info;
1944   guint8 *data;
1945   gint i;
1946
1947   len = strlen (s);
1948   if (len & 1)
1949     goto wrong_length;
1950
1951   buffer = gst_buffer_new_allocate (NULL, len / 2, 0);
1952   if (!gst_buffer_map (buffer, &info, GST_MAP_WRITE))
1953     goto map_failed;
1954   data = info.data;
1955
1956   for (i = 0; i < len / 2; i++) {
1957     if (!isxdigit ((int) s[i * 2]) || !isxdigit ((int) s[i * 2 + 1]))
1958       goto wrong_char;
1959
1960     ts[0] = s[i * 2 + 0];
1961     ts[1] = s[i * 2 + 1];
1962     ts[2] = 0;
1963
1964     data[i] = (guint8) strtoul (ts, NULL, 16);
1965   }
1966   gst_buffer_unmap (buffer, &info);
1967
1968   gst_value_take_buffer (dest, buffer);
1969
1970   return TRUE;
1971
1972   /* ERRORS */
1973 wrong_length:
1974   {
1975     return FALSE;
1976   }
1977 map_failed:
1978   {
1979     return FALSE;
1980   }
1981 wrong_char:
1982   {
1983     gst_buffer_unref (buffer);
1984     gst_buffer_unmap (buffer, &info);
1985     return FALSE;
1986   }
1987 }
1988
1989
1990 /***********
1991  * boolean *
1992  ***********/
1993
1994 static gint
1995 gst_value_compare_boolean (const GValue * value1, const GValue * value2)
1996 {
1997   if ((value1->data[0].v_int != 0) == (value2->data[0].v_int != 0))
1998     return GST_VALUE_EQUAL;
1999   return GST_VALUE_UNORDERED;
2000 }
2001
2002 static gchar *
2003 gst_value_serialize_boolean (const GValue * value)
2004 {
2005   if (value->data[0].v_int) {
2006     return g_strdup ("true");
2007   }
2008   return g_strdup ("false");
2009 }
2010
2011 static gboolean
2012 gst_value_deserialize_boolean (GValue * dest, const gchar * s)
2013 {
2014   gboolean ret = FALSE;
2015
2016   if (g_ascii_strcasecmp (s, "true") == 0 ||
2017       g_ascii_strcasecmp (s, "yes") == 0 ||
2018       g_ascii_strcasecmp (s, "t") == 0 || strcmp (s, "1") == 0) {
2019     g_value_set_boolean (dest, TRUE);
2020     ret = TRUE;
2021   } else if (g_ascii_strcasecmp (s, "false") == 0 ||
2022       g_ascii_strcasecmp (s, "no") == 0 ||
2023       g_ascii_strcasecmp (s, "f") == 0 || strcmp (s, "0") == 0) {
2024     g_value_set_boolean (dest, FALSE);
2025     ret = TRUE;
2026   }
2027
2028   return ret;
2029 }
2030
2031 #define CREATE_SERIALIZATION_START(_type,_macro)                        \
2032 static gint                                                             \
2033 gst_value_compare_ ## _type                                             \
2034 (const GValue * value1, const GValue * value2)                          \
2035 {                                                                       \
2036   g ## _type val1 = g_value_get_ ## _type (value1);                     \
2037   g ## _type val2 = g_value_get_ ## _type (value2);                     \
2038   if (val1 > val2)                                                      \
2039     return GST_VALUE_GREATER_THAN;                                      \
2040   if (val1 < val2)                                                      \
2041     return GST_VALUE_LESS_THAN;                                         \
2042   return GST_VALUE_EQUAL;                                               \
2043 }                                                                       \
2044                                                                         \
2045 static gchar *                                                          \
2046 gst_value_serialize_ ## _type (const GValue * value)                    \
2047 {                                                                       \
2048   GValue val = { 0, };                                                  \
2049   g_value_init (&val, G_TYPE_STRING);                                   \
2050   if (!g_value_transform (value, &val))                                 \
2051     g_assert_not_reached ();                                            \
2052   /* NO_COPY_MADNESS!!! */                                              \
2053   return (char *) g_value_get_string (&val);                            \
2054 }
2055
2056 /* deserialize the given s into to as a gint64.
2057  * check if the result is actually storeable in the given size number of
2058  * bytes.
2059  */
2060 static gboolean
2061 gst_value_deserialize_int_helper (gint64 * to, const gchar * s,
2062     gint64 min, gint64 max, gint size)
2063 {
2064   gboolean ret = FALSE;
2065   gchar *end;
2066   gint64 mask = -1;
2067
2068   errno = 0;
2069   *to = g_ascii_strtoull (s, &end, 0);
2070   /* a range error is a definitive no-no */
2071   if (errno == ERANGE) {
2072     return FALSE;
2073   }
2074
2075   if (*end == 0) {
2076     ret = TRUE;
2077   } else {
2078     if (g_ascii_strcasecmp (s, "little_endian") == 0) {
2079       *to = G_LITTLE_ENDIAN;
2080       ret = TRUE;
2081     } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {
2082       *to = G_BIG_ENDIAN;
2083       ret = TRUE;
2084     } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {
2085       *to = G_BYTE_ORDER;
2086       ret = TRUE;
2087     } else if (g_ascii_strcasecmp (s, "min") == 0) {
2088       *to = min;
2089       ret = TRUE;
2090     } else if (g_ascii_strcasecmp (s, "max") == 0) {
2091       *to = max;
2092       ret = TRUE;
2093     }
2094   }
2095   if (ret) {
2096     /* by definition, a gint64 fits into a gint64; so ignore those */
2097     if (size != sizeof (mask)) {
2098       if (*to >= 0) {
2099         /* for positive numbers, we create a mask of 1's outside of the range
2100          * and 0's inside the range.  An and will thus keep only 1 bits
2101          * outside of the range */
2102         mask <<= (size * 8);
2103         if ((mask & *to) != 0) {
2104           ret = FALSE;
2105         }
2106       } else {
2107         /* for negative numbers, we do a 2's complement version */
2108         mask <<= ((size * 8) - 1);
2109         if ((mask & *to) != mask) {
2110           ret = FALSE;
2111         }
2112       }
2113     }
2114   }
2115   return ret;
2116 }
2117
2118 #define CREATE_SERIALIZATION(_type,_macro)                              \
2119 CREATE_SERIALIZATION_START(_type,_macro)                                \
2120                                                                         \
2121 static gboolean                                                         \
2122 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s)         \
2123 {                                                                       \
2124   gint64 x;                                                             \
2125                                                                         \
2126   if (gst_value_deserialize_int_helper (&x, s, G_MIN ## _macro,         \
2127       G_MAX ## _macro, sizeof (g ## _type))) {                          \
2128     g_value_set_ ## _type (dest, /*(g ## _type)*/ x);                   \
2129     return TRUE;                                                        \
2130   } else {                                                              \
2131     return FALSE;                                                       \
2132   }                                                                     \
2133 }
2134
2135 #define CREATE_USERIALIZATION(_type,_macro)                             \
2136 CREATE_SERIALIZATION_START(_type,_macro)                                \
2137                                                                         \
2138 static gboolean                                                         \
2139 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s)         \
2140 {                                                                       \
2141   gint64 x;                                                             \
2142   gchar *end;                                                           \
2143   gboolean ret = FALSE;                                                 \
2144                                                                         \
2145   errno = 0;                                                            \
2146   x = g_ascii_strtoull (s, &end, 0);                                    \
2147   /* a range error is a definitive no-no */                             \
2148   if (errno == ERANGE) {                                                \
2149     return FALSE;                                                       \
2150   }                                                                     \
2151   /* the cast ensures the range check later on makes sense */           \
2152   x = (g ## _type) x;                                                   \
2153   if (*end == 0) {                                                      \
2154     ret = TRUE;                                                         \
2155   } else {                                                              \
2156     if (g_ascii_strcasecmp (s, "little_endian") == 0) {                 \
2157       x = G_LITTLE_ENDIAN;                                              \
2158       ret = TRUE;                                                       \
2159     } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {             \
2160       x = G_BIG_ENDIAN;                                                 \
2161       ret = TRUE;                                                       \
2162     } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {             \
2163       x = G_BYTE_ORDER;                                                 \
2164       ret = TRUE;                                                       \
2165     } else if (g_ascii_strcasecmp (s, "min") == 0) {                    \
2166       x = 0;                                                            \
2167       ret = TRUE;                                                       \
2168     } else if (g_ascii_strcasecmp (s, "max") == 0) {                    \
2169       x = G_MAX ## _macro;                                              \
2170       ret = TRUE;                                                       \
2171     }                                                                   \
2172   }                                                                     \
2173   if (ret) {                                                            \
2174     if (x > G_MAX ## _macro) {                                          \
2175       ret = FALSE;                                                      \
2176     } else {                                                            \
2177       g_value_set_ ## _type (dest, x);                                  \
2178     }                                                                   \
2179   }                                                                     \
2180   return ret;                                                           \
2181 }
2182
2183 #define REGISTER_SERIALIZATION(_gtype, _type)                           \
2184 G_STMT_START {                                                          \
2185   static const GstValueTable gst_value = {                              \
2186     _gtype,                                                             \
2187     gst_value_compare_ ## _type,                                        \
2188     gst_value_serialize_ ## _type,                                      \
2189     gst_value_deserialize_ ## _type,                                    \
2190   };                                                                    \
2191                                                                         \
2192   gst_value_register (&gst_value);                                      \
2193 } G_STMT_END
2194
2195 CREATE_SERIALIZATION (int, INT);
2196 CREATE_SERIALIZATION (int64, INT64);
2197 CREATE_SERIALIZATION (long, LONG);
2198
2199 CREATE_USERIALIZATION (uint, UINT);
2200 CREATE_USERIALIZATION (uint64, UINT64);
2201 CREATE_USERIALIZATION (ulong, ULONG);
2202
2203 /* FIXME 0.11: remove this again, plugins shouldn't have uchar properties */
2204 #ifndef G_MAXUCHAR
2205 #define G_MAXUCHAR 255
2206 #endif
2207 CREATE_USERIALIZATION (uchar, UCHAR);
2208
2209 /**********
2210  * double *
2211  **********/
2212 static gint
2213 gst_value_compare_double (const GValue * value1, const GValue * value2)
2214 {
2215   if (value1->data[0].v_double > value2->data[0].v_double)
2216     return GST_VALUE_GREATER_THAN;
2217   if (value1->data[0].v_double < value2->data[0].v_double)
2218     return GST_VALUE_LESS_THAN;
2219   if (value1->data[0].v_double == value2->data[0].v_double)
2220     return GST_VALUE_EQUAL;
2221   return GST_VALUE_UNORDERED;
2222 }
2223
2224 static gchar *
2225 gst_value_serialize_double (const GValue * value)
2226 {
2227   gchar d[G_ASCII_DTOSTR_BUF_SIZE];
2228
2229   g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
2230   return g_strdup (d);
2231 }
2232
2233 static gboolean
2234 gst_value_deserialize_double (GValue * dest, const gchar * s)
2235 {
2236   gdouble x;
2237   gboolean ret = FALSE;
2238   gchar *end;
2239
2240   x = g_ascii_strtod (s, &end);
2241   if (*end == 0) {
2242     ret = TRUE;
2243   } else {
2244     if (g_ascii_strcasecmp (s, "min") == 0) {
2245       x = -G_MAXDOUBLE;
2246       ret = TRUE;
2247     } else if (g_ascii_strcasecmp (s, "max") == 0) {
2248       x = G_MAXDOUBLE;
2249       ret = TRUE;
2250     }
2251   }
2252   if (ret) {
2253     g_value_set_double (dest, x);
2254   }
2255   return ret;
2256 }
2257
2258 /*********
2259  * float *
2260  *********/
2261
2262 static gint
2263 gst_value_compare_float (const GValue * value1, const GValue * value2)
2264 {
2265   if (value1->data[0].v_float > value2->data[0].v_float)
2266     return GST_VALUE_GREATER_THAN;
2267   if (value1->data[0].v_float < value2->data[0].v_float)
2268     return GST_VALUE_LESS_THAN;
2269   if (value1->data[0].v_float == value2->data[0].v_float)
2270     return GST_VALUE_EQUAL;
2271   return GST_VALUE_UNORDERED;
2272 }
2273
2274 static gchar *
2275 gst_value_serialize_float (const GValue * value)
2276 {
2277   gchar d[G_ASCII_DTOSTR_BUF_SIZE];
2278
2279   g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_float);
2280   return g_strdup (d);
2281 }
2282
2283 static gboolean
2284 gst_value_deserialize_float (GValue * dest, const gchar * s)
2285 {
2286   gdouble x;
2287   gboolean ret = FALSE;
2288   gchar *end;
2289
2290   x = g_ascii_strtod (s, &end);
2291   if (*end == 0) {
2292     ret = TRUE;
2293   } else {
2294     if (g_ascii_strcasecmp (s, "min") == 0) {
2295       x = -G_MAXFLOAT;
2296       ret = TRUE;
2297     } else if (g_ascii_strcasecmp (s, "max") == 0) {
2298       x = G_MAXFLOAT;
2299       ret = TRUE;
2300     }
2301   }
2302   if (x > G_MAXFLOAT || x < -G_MAXFLOAT)
2303     ret = FALSE;
2304   if (ret) {
2305     g_value_set_float (dest, (float) x);
2306   }
2307   return ret;
2308 }
2309
2310 /**********
2311  * string *
2312  **********/
2313
2314 static gint
2315 gst_value_compare_string (const GValue * value1, const GValue * value2)
2316 {
2317   if (G_UNLIKELY (!value1->data[0].v_pointer || !value2->data[0].v_pointer)) {
2318     /* if only one is NULL, no match - otherwise both NULL == EQUAL */
2319     if (value1->data[0].v_pointer != value2->data[0].v_pointer)
2320       return GST_VALUE_UNORDERED;
2321   } else {
2322     gint x = strcmp (value1->data[0].v_pointer, value2->data[0].v_pointer);
2323
2324     if (x < 0)
2325       return GST_VALUE_LESS_THAN;
2326     if (x > 0)
2327       return GST_VALUE_GREATER_THAN;
2328   }
2329
2330   return GST_VALUE_EQUAL;
2331 }
2332
2333 static gint
2334 gst_string_measure_wrapping (const gchar * s)
2335 {
2336   gint len;
2337   gboolean wrap = FALSE;
2338
2339   if (G_UNLIKELY (s == NULL))
2340     return -1;
2341
2342   /* Special case: the actual string NULL needs wrapping */
2343   if (G_UNLIKELY (strcmp (s, "NULL") == 0))
2344     return 4;
2345
2346   len = 0;
2347   while (*s) {
2348     if (GST_ASCII_IS_STRING (*s)) {
2349       len++;
2350     } else if (*s < 0x20 || *s >= 0x7f) {
2351       wrap = TRUE;
2352       len += 4;
2353     } else {
2354       wrap = TRUE;
2355       len += 2;
2356     }
2357     s++;
2358   }
2359
2360   /* Wrap the string if we found something that needs
2361    * wrapping, or the empty string (len == 0) */
2362   return (wrap || len == 0) ? len : -1;
2363 }
2364
2365 static gchar *
2366 gst_string_wrap_inner (const gchar * s, gint len)
2367 {
2368   gchar *d, *e;
2369
2370   e = d = g_malloc (len + 3);
2371
2372   *e++ = '\"';
2373   while (*s) {
2374     if (GST_ASCII_IS_STRING (*s)) {
2375       *e++ = *s++;
2376     } else if (*s < 0x20 || *s >= 0x7f) {
2377       *e++ = '\\';
2378       *e++ = '0' + ((*(guchar *) s) >> 6);
2379       *e++ = '0' + (((*s) >> 3) & 0x7);
2380       *e++ = '0' + ((*s++) & 0x7);
2381     } else {
2382       *e++ = '\\';
2383       *e++ = *s++;
2384     }
2385   }
2386   *e++ = '\"';
2387   *e = 0;
2388
2389   g_assert (e - d <= len + 3);
2390   return d;
2391 }
2392
2393 /* Do string wrapping/escaping */
2394 static gchar *
2395 gst_string_wrap (const gchar * s)
2396 {
2397   gint len = gst_string_measure_wrapping (s);
2398
2399   if (G_LIKELY (len < 0))
2400     return g_strdup (s);
2401
2402   return gst_string_wrap_inner (s, len);
2403 }
2404
2405 /* Same as above, but take ownership of the string */
2406 static gchar *
2407 gst_string_take_and_wrap (gchar * s)
2408 {
2409   gchar *out;
2410   gint len = gst_string_measure_wrapping (s);
2411
2412   if (G_LIKELY (len < 0))
2413     return s;
2414
2415   out = gst_string_wrap_inner (s, len);
2416   g_free (s);
2417
2418   return out;
2419 }
2420
2421 /*
2422  * This function takes a string delimited with double quotes (")
2423  * and unescapes any \xxx octal numbers.
2424  *
2425  * If sequences of \y are found where y is not in the range of
2426  * 0->3, y is copied unescaped.
2427  *
2428  * If \xyy is found where x is an octal number but y is not, an
2429  * error is encountered and NULL is returned.
2430  *
2431  * the input string must be \0 terminated.
2432  */
2433 static gchar *
2434 gst_string_unwrap (const gchar * s)
2435 {
2436   gchar *ret;
2437   gchar *read, *write;
2438
2439   /* NULL string returns NULL */
2440   if (s == NULL)
2441     return NULL;
2442
2443   /* strings not starting with " are invalid */
2444   if (*s != '"')
2445     return NULL;
2446
2447   /* make copy of original string to hold the result. This
2448    * string will always be smaller than the original */
2449   ret = g_strdup (s);
2450   read = ret;
2451   write = ret;
2452
2453   /* need to move to the next position as we parsed the " */
2454   read++;
2455
2456   while (*read) {
2457     if (GST_ASCII_IS_STRING (*read)) {
2458       /* normal chars are just copied */
2459       *write++ = *read++;
2460     } else if (*read == '"') {
2461       /* quote marks end of string */
2462       break;
2463     } else if (*read == '\\') {
2464       /* got an escape char, move to next position to read a tripplet
2465        * of octal numbers */
2466       read++;
2467       /* is the next char a possible first octal number? */
2468       if (*read >= '0' && *read <= '3') {
2469         /* parse other 2 numbers, if one of them is not in the range of
2470          * an octal number, we error. We also catch the case where a zero
2471          * byte is found here. */
2472         if (read[1] < '0' || read[1] > '7' || read[2] < '0' || read[2] > '7')
2473           goto beach;
2474
2475         /* now convert the octal number to a byte again. */
2476         *write++ = ((read[0] - '0') << 6) +
2477             ((read[1] - '0') << 3) + (read[2] - '0');
2478
2479         read += 3;
2480       } else {
2481         /* if we run into a \0 here, we definitely won't get a quote later */
2482         if (*read == 0)
2483           goto beach;
2484
2485         /* else copy \X sequence */
2486         *write++ = *read++;
2487       }
2488     } else {
2489       /* weird character, error */
2490       goto beach;
2491     }
2492   }
2493   /* if the string is not ending in " and zero terminated, we error */
2494   if (*read != '"' || read[1] != '\0')
2495     goto beach;
2496
2497   /* null terminate result string and return */
2498   *write = '\0';
2499   return ret;
2500
2501 beach:
2502   g_free (ret);
2503   return NULL;
2504 }
2505
2506 static gchar *
2507 gst_value_serialize_string (const GValue * value)
2508 {
2509   return gst_string_wrap (value->data[0].v_pointer);
2510 }
2511
2512 static gboolean
2513 gst_value_deserialize_string (GValue * dest, const gchar * s)
2514 {
2515   if (G_UNLIKELY (strcmp (s, "NULL") == 0)) {
2516     g_value_set_string (dest, NULL);
2517     return TRUE;
2518   } else if (G_LIKELY (*s != '"')) {
2519     if (!g_utf8_validate (s, -1, NULL))
2520       return FALSE;
2521     g_value_set_string (dest, s);
2522     return TRUE;
2523   } else {
2524     gchar *str = gst_string_unwrap (s);
2525     if (G_UNLIKELY (!str))
2526       return FALSE;
2527     g_value_take_string (dest, str);
2528   }
2529
2530   return TRUE;
2531 }
2532
2533 /********
2534  * enum *
2535  ********/
2536
2537 static gint
2538 gst_value_compare_enum (const GValue * value1, const GValue * value2)
2539 {
2540   GEnumValue *en1, *en2;
2541   GEnumClass *klass1 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value1));
2542   GEnumClass *klass2 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value2));
2543
2544   g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
2545   g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
2546   en1 = g_enum_get_value (klass1, g_value_get_enum (value1));
2547   en2 = g_enum_get_value (klass2, g_value_get_enum (value2));
2548   g_type_class_unref (klass1);
2549   g_type_class_unref (klass2);
2550   g_return_val_if_fail (en1, GST_VALUE_UNORDERED);
2551   g_return_val_if_fail (en2, GST_VALUE_UNORDERED);
2552   if (en1->value < en2->value)
2553     return GST_VALUE_LESS_THAN;
2554   if (en1->value > en2->value)
2555     return GST_VALUE_GREATER_THAN;
2556
2557   return GST_VALUE_EQUAL;
2558 }
2559
2560 static gchar *
2561 gst_value_serialize_enum (const GValue * value)
2562 {
2563   GEnumValue *en;
2564   GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value));
2565
2566   g_return_val_if_fail (klass, NULL);
2567   en = g_enum_get_value (klass, g_value_get_enum (value));
2568   g_type_class_unref (klass);
2569
2570   /* might be one of the custom formats registered later */
2571   if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (value) == GST_TYPE_FORMAT)) {
2572     const GstFormatDefinition *format_def;
2573
2574     format_def = gst_format_get_details ((GstFormat) g_value_get_enum (value));
2575     g_return_val_if_fail (format_def != NULL, NULL);
2576     return g_strdup (format_def->description);
2577   }
2578
2579   g_return_val_if_fail (en, NULL);
2580   return g_strdup (en->value_name);
2581 }
2582
2583 static gint
2584 gst_value_deserialize_enum_iter_cmp (const GValue * format_def_value,
2585     const gchar * s)
2586 {
2587   const GstFormatDefinition *format_def =
2588       g_value_get_pointer (format_def_value);
2589
2590   if (g_ascii_strcasecmp (s, format_def->nick) == 0)
2591     return 0;
2592
2593   return g_ascii_strcasecmp (s, format_def->description);
2594 }
2595
2596 static gboolean
2597 gst_value_deserialize_enum (GValue * dest, const gchar * s)
2598 {
2599   GEnumValue *en;
2600   gchar *endptr = NULL;
2601   GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (dest));
2602
2603   g_return_val_if_fail (klass, FALSE);
2604   if (!(en = g_enum_get_value_by_name (klass, s))) {
2605     if (!(en = g_enum_get_value_by_nick (klass, s))) {
2606       gint i = strtol (s, &endptr, 0);
2607
2608       if (endptr && *endptr == '\0') {
2609         en = g_enum_get_value (klass, i);
2610       }
2611     }
2612   }
2613   g_type_class_unref (klass);
2614
2615   /* might be one of the custom formats registered later */
2616   if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (dest) == GST_TYPE_FORMAT)) {
2617     GValue res = { 0, };
2618     const GstFormatDefinition *format_def;
2619     GstIterator *iter;
2620     gboolean found;
2621
2622     iter = gst_format_iterate_definitions ();
2623
2624     found = gst_iterator_find_custom (iter,
2625         (GCompareFunc) gst_value_deserialize_enum_iter_cmp, &res, (gpointer) s);
2626
2627     g_return_val_if_fail (found, FALSE);
2628     format_def = g_value_get_pointer (&res);
2629     g_return_val_if_fail (format_def != NULL, FALSE);
2630     g_value_set_enum (dest, (gint) format_def->value);
2631     g_value_unset (&res);
2632     gst_iterator_free (iter);
2633     return TRUE;
2634   }
2635
2636   g_return_val_if_fail (en, FALSE);
2637   g_value_set_enum (dest, en->value);
2638   return TRUE;
2639 }
2640
2641 /********
2642  * flags *
2643  ********/
2644
2645 /* we just compare the value here */
2646 static gint
2647 gst_value_compare_flags (const GValue * value1, const GValue * value2)
2648 {
2649   guint fl1, fl2;
2650   GFlagsClass *klass1 =
2651       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value1));
2652   GFlagsClass *klass2 =
2653       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value2));
2654
2655   g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
2656   g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
2657   fl1 = g_value_get_flags (value1);
2658   fl2 = g_value_get_flags (value2);
2659   g_type_class_unref (klass1);
2660   g_type_class_unref (klass2);
2661   if (fl1 < fl2)
2662     return GST_VALUE_LESS_THAN;
2663   if (fl1 > fl2)
2664     return GST_VALUE_GREATER_THAN;
2665
2666   return GST_VALUE_EQUAL;
2667 }
2668
2669 /* the different flags are serialized separated with a + */
2670 static gchar *
2671 gst_value_serialize_flags (const GValue * value)
2672 {
2673   guint flags;
2674   GFlagsValue *fl;
2675   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value));
2676   gchar *result, *tmp;
2677   gboolean first = TRUE;
2678
2679   g_return_val_if_fail (klass, NULL);
2680
2681   flags = g_value_get_flags (value);
2682
2683   /* if no flags are set, try to serialize to the _NONE string */
2684   if (!flags) {
2685     fl = g_flags_get_first_value (klass, flags);
2686     return g_strdup (fl->value_name);
2687   }
2688
2689   /* some flags are set, so serialize one by one */
2690   result = g_strdup ("");
2691   while (flags) {
2692     fl = g_flags_get_first_value (klass, flags);
2693     if (fl != NULL) {
2694       tmp = g_strconcat (result, (first ? "" : "+"), fl->value_name, NULL);
2695       g_free (result);
2696       result = tmp;
2697       first = FALSE;
2698
2699       /* clear flag */
2700       flags &= ~fl->value;
2701     }
2702   }
2703   g_type_class_unref (klass);
2704
2705   return result;
2706 }
2707
2708 static gboolean
2709 gst_value_deserialize_flags (GValue * dest, const gchar * s)
2710 {
2711   GFlagsValue *fl;
2712   gchar *endptr = NULL;
2713   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (dest));
2714   gchar **split;
2715   guint flags;
2716   gint i;
2717
2718   g_return_val_if_fail (klass, FALSE);
2719
2720   /* split into parts delimited with + */
2721   split = g_strsplit (s, "+", 0);
2722
2723   flags = 0;
2724   i = 0;
2725   /* loop over each part */
2726   while (split[i]) {
2727     if (!(fl = g_flags_get_value_by_name (klass, split[i]))) {
2728       if (!(fl = g_flags_get_value_by_nick (klass, split[i]))) {
2729         gint val = strtol (split[i], &endptr, 0);
2730
2731         /* just or numeric value */
2732         if (endptr && *endptr == '\0') {
2733           flags |= val;
2734         }
2735       }
2736     }
2737     if (fl) {
2738       flags |= fl->value;
2739     }
2740     i++;
2741   }
2742   g_strfreev (split);
2743   g_type_class_unref (klass);
2744   g_value_set_flags (dest, flags);
2745
2746   return TRUE;
2747 }
2748
2749 /****************
2750  * subset *
2751  ****************/
2752
2753 static gboolean
2754 gst_value_is_subset_int_range_int_range (const GValue * value1,
2755     const GValue * value2)
2756 {
2757   gint gcd;
2758
2759   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value1), FALSE);
2760   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value2), FALSE);
2761
2762   if (INT_RANGE_MIN (value1) * INT_RANGE_STEP (value1) <
2763       INT_RANGE_MIN (value2) * INT_RANGE_STEP (value2))
2764     return FALSE;
2765   if (INT_RANGE_MAX (value1) * INT_RANGE_STEP (value1) >
2766       INT_RANGE_MAX (value2) * INT_RANGE_STEP (value2))
2767     return FALSE;
2768
2769   if (INT_RANGE_MIN (value2) == INT_RANGE_MAX (value2)) {
2770     if ((INT_RANGE_MIN (value2) * INT_RANGE_STEP (value2)) %
2771         INT_RANGE_STEP (value1))
2772       return FALSE;
2773     return TRUE;
2774   }
2775
2776   gcd =
2777       gst_util_greatest_common_divisor (INT_RANGE_STEP (value1),
2778       INT_RANGE_STEP (value2));
2779   if (gcd != MIN (INT_RANGE_STEP (value1), INT_RANGE_STEP (value2)))
2780     return FALSE;
2781
2782   return TRUE;
2783 }
2784
2785 static gboolean
2786 gst_value_is_subset_int64_range_int64_range (const GValue * value1,
2787     const GValue * value2)
2788 {
2789   gint64 gcd;
2790
2791   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value1), FALSE);
2792   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value2), FALSE);
2793
2794   if (INT64_RANGE_MIN (value1) < INT64_RANGE_MIN (value2))
2795     return FALSE;
2796   if (INT64_RANGE_MAX (value1) > INT64_RANGE_MAX (value2))
2797     return FALSE;
2798
2799   if (INT64_RANGE_MIN (value2) == INT64_RANGE_MAX (value2)) {
2800     if ((INT64_RANGE_MIN (value2) * INT64_RANGE_STEP (value2)) %
2801         INT64_RANGE_STEP (value1))
2802       return FALSE;
2803     return TRUE;
2804   }
2805
2806   gcd =
2807       gst_util_greatest_common_divisor_int64 (INT64_RANGE_STEP (value1),
2808       INT64_RANGE_STEP (value2));
2809   if (gcd != MIN (INT64_RANGE_STEP (value1), INT64_RANGE_STEP (value2)))
2810     return FALSE;
2811
2812   return TRUE;
2813 }
2814
2815 gboolean
2816 gst_value_is_subset (const GValue * value1, const GValue * value2)
2817 {
2818   /* special case for int/int64 ranges, since we cannot compute
2819      the difference for those when they have different steps,
2820      and it's actually a lot simpler to compute whether a range
2821      is a subset of another. */
2822   if (GST_VALUE_HOLDS_INT_RANGE (value1) && GST_VALUE_HOLDS_INT_RANGE (value2)) {
2823     return gst_value_is_subset_int_range_int_range (value1, value2);
2824   } else if (GST_VALUE_HOLDS_INT64_RANGE (value1)
2825       && GST_VALUE_HOLDS_INT64_RANGE (value2)) {
2826     return gst_value_is_subset_int64_range_int64_range (value1, value2);
2827   }
2828
2829   /*
2830    * 1 - [1,2] = empty
2831    * -> !subset
2832    *
2833    * [1,2] - 1 = 2
2834    *  -> 1 - [1,2] = empty
2835    *  -> subset
2836    *
2837    * [1,3] - [1,2] = 3
2838    * -> [1,2] - [1,3] = empty
2839    * -> subset
2840    *
2841    * {1,2} - {1,3} = 2
2842    * -> {1,3} - {1,2} = 3
2843    * -> !subset
2844    *
2845    *  First caps subtraction needs to return a non-empty set, second
2846    *  subtractions needs to give en empty set.
2847    *  Both substractions are switched below, as it's faster that way.
2848    */
2849   if (!gst_value_subtract (NULL, value1, value2)) {
2850     if (gst_value_subtract (NULL, value2, value1)) {
2851       return TRUE;
2852     }
2853   }
2854   return FALSE;
2855 }
2856
2857 /*********
2858  * union *
2859  *********/
2860
2861 static gboolean
2862 gst_value_union_int_int_range (GValue * dest, const GValue * src1,
2863     const GValue * src2)
2864 {
2865   gint v = src1->data[0].v_int;
2866
2867   /* check if it's already in the range */
2868   if (INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2) <= v &&
2869       INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2) >= v &&
2870       v % INT_RANGE_STEP (src2) == 0) {
2871     if (dest)
2872       gst_value_init_and_copy (dest, src2);
2873     return TRUE;
2874   }
2875
2876   /* check if it extends the range */
2877   if (v == (INT_RANGE_MIN (src2) - 1) * INT_RANGE_STEP (src2)) {
2878     if (dest) {
2879       gst_value_init_and_copy (dest, src2);
2880       --INT_RANGE_MIN (src2);
2881     }
2882     return TRUE;
2883   }
2884   if (v == (INT_RANGE_MAX (src2) + 1) * INT_RANGE_STEP (src2)) {
2885     if (dest) {
2886       gst_value_init_and_copy (dest, src2);
2887       ++INT_RANGE_MAX (src2);
2888     }
2889     return TRUE;
2890   }
2891
2892   return FALSE;
2893 }
2894
2895 static gboolean
2896 gst_value_union_int_range_int_range (GValue * dest, const GValue * src1,
2897     const GValue * src2)
2898 {
2899   /* We can union in several special cases:
2900      1 - one is a subset of another
2901      2 - same step and not disjoint
2902      3 - different step, at least one with one value which matches a 'next' or 'previous'
2903      - anything else ?
2904    */
2905
2906   /* 1 - subset */
2907   if (gst_value_is_subset_int_range_int_range (src1, src2)) {
2908     if (dest)
2909       gst_value_init_and_copy (dest, src2);
2910     return TRUE;
2911   }
2912   if (gst_value_is_subset_int_range_int_range (src2, src1)) {
2913     if (dest)
2914       gst_value_init_and_copy (dest, src1);
2915     return TRUE;
2916   }
2917
2918   /* 2 - same step and not disjoint */
2919   if (INT_RANGE_STEP (src1) == INT_RANGE_STEP (src2)) {
2920     if ((INT_RANGE_MIN (src1) <= INT_RANGE_MAX (src2) + 1 &&
2921             INT_RANGE_MAX (src1) >= INT_RANGE_MIN (src2) - 1) ||
2922         (INT_RANGE_MIN (src2) <= INT_RANGE_MAX (src1) + 1 &&
2923             INT_RANGE_MAX (src2) >= INT_RANGE_MIN (src1) - 1)) {
2924       if (dest) {
2925         gint step = INT_RANGE_STEP (src1);
2926         gint min = step * MIN (INT_RANGE_MIN (src1), INT_RANGE_MIN (src2));
2927         gint max = step * MAX (INT_RANGE_MAX (src1), INT_RANGE_MAX (src2));
2928         g_value_init (dest, GST_TYPE_INT_RANGE);
2929         gst_value_set_int_range_step (dest, min, max, step);
2930       }
2931       return TRUE;
2932     }
2933   }
2934
2935   /* 3 - single value matches next or previous */
2936   if (INT_RANGE_STEP (src1) != INT_RANGE_STEP (src2)) {
2937     gint n1 = INT_RANGE_MAX (src1) - INT_RANGE_MIN (src1) + 1;
2938     gint n2 = INT_RANGE_MAX (src2) - INT_RANGE_MIN (src2) + 1;
2939     if (n1 == 1 || n2 == 1) {
2940       const GValue *range_value = NULL;
2941       gint scalar = 0;
2942       if (n1 == 1) {
2943         range_value = src2;
2944         scalar = INT_RANGE_MIN (src1) * INT_RANGE_STEP (src1);
2945       } else if (n2 == 1) {
2946         range_value = src1;
2947         scalar = INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2);
2948       }
2949
2950       if (scalar ==
2951           (INT_RANGE_MIN (range_value) - 1) * INT_RANGE_STEP (range_value)) {
2952         if (dest) {
2953           gst_value_init_and_copy (dest, range_value);
2954           --INT_RANGE_MIN (range_value);
2955         }
2956         return TRUE;
2957       } else if (scalar ==
2958           (INT_RANGE_MAX (range_value) + 1) * INT_RANGE_STEP (range_value)) {
2959         if (dest) {
2960           gst_value_init_and_copy (dest, range_value);
2961           ++INT_RANGE_MIN (range_value);
2962         }
2963         return TRUE;
2964       }
2965     }
2966   }
2967
2968   /* If we get there, we did not find a way to make a union that can be
2969      represented with our simplistic model. */
2970   return FALSE;
2971 }
2972
2973 /****************
2974  * intersection *
2975  ****************/
2976
2977 static gboolean
2978 gst_value_intersect_int_int_range (GValue * dest, const GValue * src1,
2979     const GValue * src2)
2980 {
2981   if (INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2) <= src1->data[0].v_int &&
2982       INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2) >= src1->data[0].v_int &&
2983       src1->data[0].v_int % INT_RANGE_STEP (src2) == 0) {
2984     if (dest)
2985       gst_value_init_and_copy (dest, src1);
2986     return TRUE;
2987   }
2988
2989   return FALSE;
2990 }
2991
2992 static gboolean
2993 gst_value_intersect_int_range_int_range (GValue * dest, const GValue * src1,
2994     const GValue * src2)
2995 {
2996   gint min;
2997   gint max;
2998   gint step;
2999
3000   step =
3001       INT_RANGE_STEP (src1) /
3002       gst_util_greatest_common_divisor (INT_RANGE_STEP (src1),
3003       INT_RANGE_STEP (src2));
3004   if (G_MAXINT32 / INT_RANGE_STEP (src2) < step)
3005     return FALSE;
3006   step *= INT_RANGE_STEP (src2);
3007
3008   min =
3009       MAX (INT_RANGE_MIN (src1) * INT_RANGE_STEP (src1),
3010       INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2));
3011   min = (min + step - 1) / step * step;
3012   max =
3013       MIN (INT_RANGE_MAX (src1) * INT_RANGE_STEP (src1),
3014       INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2));
3015   max = max / step * step;
3016
3017   if (min < max) {
3018     if (dest) {
3019       g_value_init (dest, GST_TYPE_INT_RANGE);
3020       gst_value_set_int_range_step (dest, min, max, step);
3021     }
3022     return TRUE;
3023   }
3024   if (min == max) {
3025     if (dest) {
3026       g_value_init (dest, G_TYPE_INT);
3027       g_value_set_int (dest, min);
3028     }
3029     return TRUE;
3030   }
3031
3032   return FALSE;
3033 }
3034
3035 static gboolean
3036 gst_value_intersect_int64_int64_range (GValue * dest, const GValue * src1,
3037     const GValue * src2)
3038 {
3039   if (INT64_RANGE_MIN (src2) * INT64_RANGE_STEP (src2) <= src1->data[0].v_int &&
3040       INT64_RANGE_MAX (src2) * INT64_RANGE_STEP (src2) >= src1->data[0].v_int &&
3041       src1->data[0].v_int % INT64_RANGE_STEP (src2) == 0) {
3042     if (dest)
3043       gst_value_init_and_copy (dest, src1);
3044     return TRUE;
3045   }
3046
3047   return FALSE;
3048 }
3049
3050 static gboolean
3051 gst_value_intersect_int64_range_int64_range (GValue * dest, const GValue * src1,
3052     const GValue * src2)
3053 {
3054   gint64 min;
3055   gint64 max;
3056   gint64 step;
3057
3058   step =
3059       INT64_RANGE_STEP (src1) /
3060       gst_util_greatest_common_divisor_int64 (INT64_RANGE_STEP (src1),
3061       INT64_RANGE_STEP (src2));
3062   if (G_MAXINT64 / INT64_RANGE_STEP (src2) < step)
3063     return FALSE;
3064   step *= INT64_RANGE_STEP (src2);
3065
3066   min =
3067       MAX (INT64_RANGE_MIN (src1) * INT64_RANGE_STEP (src1),
3068       INT64_RANGE_MIN (src2) * INT64_RANGE_STEP (src2));
3069   min = (min + step - 1) / step * step;
3070   max =
3071       MIN (INT64_RANGE_MAX (src1) * INT64_RANGE_STEP (src1),
3072       INT64_RANGE_MAX (src2) * INT64_RANGE_STEP (src2));
3073   max = max / step * step;
3074
3075   if (min < max) {
3076     if (dest) {
3077       g_value_init (dest, GST_TYPE_INT64_RANGE);
3078       gst_value_set_int64_range_step (dest, min, max, step);
3079     }
3080     return TRUE;
3081   }
3082   if (min == max) {
3083     if (dest) {
3084       g_value_init (dest, G_TYPE_INT64);
3085       g_value_set_int64 (dest, min);
3086     }
3087     return TRUE;
3088   }
3089
3090   return FALSE;
3091 }
3092
3093 static gboolean
3094 gst_value_intersect_double_double_range (GValue * dest, const GValue * src1,
3095     const GValue * src2)
3096 {
3097   if (src2->data[0].v_double <= src1->data[0].v_double &&
3098       src2->data[1].v_double >= src1->data[0].v_double) {
3099     if (dest)
3100       gst_value_init_and_copy (dest, src1);
3101     return TRUE;
3102   }
3103
3104   return FALSE;
3105 }
3106
3107 static gboolean
3108 gst_value_intersect_double_range_double_range (GValue * dest,
3109     const GValue * src1, const GValue * src2)
3110 {
3111   gdouble min;
3112   gdouble max;
3113
3114   min = MAX (src1->data[0].v_double, src2->data[0].v_double);
3115   max = MIN (src1->data[1].v_double, src2->data[1].v_double);
3116
3117   if (min < max) {
3118     if (dest) {
3119       g_value_init (dest, GST_TYPE_DOUBLE_RANGE);
3120       gst_value_set_double_range (dest, min, max);
3121     }
3122     return TRUE;
3123   }
3124   if (min == max) {
3125     if (dest) {
3126       g_value_init (dest, G_TYPE_DOUBLE);
3127       g_value_set_int (dest, (int) min);
3128     }
3129     return TRUE;
3130   }
3131
3132   return FALSE;
3133 }
3134
3135 static gboolean
3136 gst_value_intersect_list (GValue * dest, const GValue * value1,
3137     const GValue * value2)
3138 {
3139   guint i, size;
3140   GValue intersection = { 0, };
3141   gboolean ret = FALSE;
3142
3143   size = VALUE_LIST_SIZE (value1);
3144   for (i = 0; i < size; i++) {
3145     const GValue *cur = VALUE_LIST_GET_VALUE (value1, i);
3146
3147     /* quicker version when we don't need the resulting set */
3148     if (!dest) {
3149       if (gst_value_intersect (NULL, cur, value2)) {
3150         ret = TRUE;
3151         break;
3152       }
3153       continue;
3154     }
3155
3156     if (gst_value_intersect (&intersection, cur, value2)) {
3157       /* append value */
3158       if (!ret) {
3159         gst_value_init_and_copy (dest, &intersection);
3160         ret = TRUE;
3161       } else if (GST_VALUE_HOLDS_LIST (dest)) {
3162         gst_value_list_append_value (dest, &intersection);
3163       } else {
3164         GValue temp = { 0, };
3165
3166         gst_value_init_and_copy (&temp, dest);
3167         g_value_unset (dest);
3168         gst_value_list_concat (dest, &temp, &intersection);
3169         g_value_unset (&temp);
3170       }
3171       g_value_unset (&intersection);
3172     }
3173   }
3174
3175   return ret;
3176 }
3177
3178 static gboolean
3179 gst_value_intersect_array (GValue * dest, const GValue * src1,
3180     const GValue * src2)
3181 {
3182   guint size;
3183   guint n;
3184   GValue val = { 0 };
3185
3186   /* only works on similar-sized arrays */
3187   size = gst_value_array_get_size (src1);
3188   if (size != gst_value_array_get_size (src2))
3189     return FALSE;
3190
3191   /* quicker value when we don't need the resulting set */
3192   if (!dest) {
3193     for (n = 0; n < size; n++) {
3194       if (!gst_value_intersect (NULL, gst_value_array_get_value (src1, n),
3195               gst_value_array_get_value (src2, n))) {
3196         return FALSE;
3197       }
3198     }
3199     return TRUE;
3200   }
3201
3202   g_value_init (dest, GST_TYPE_ARRAY);
3203
3204   for (n = 0; n < size; n++) {
3205     if (!gst_value_intersect (&val, gst_value_array_get_value (src1, n),
3206             gst_value_array_get_value (src2, n))) {
3207       g_value_unset (dest);
3208       return FALSE;
3209     }
3210     gst_value_array_append_value (dest, &val);
3211     g_value_unset (&val);
3212   }
3213
3214   return TRUE;
3215 }
3216
3217 static gboolean
3218 gst_value_intersect_fraction_fraction_range (GValue * dest, const GValue * src1,
3219     const GValue * src2)
3220 {
3221   gint res1, res2;
3222   GValue *vals;
3223   GstValueCompareFunc compare;
3224
3225   vals = src2->data[0].v_pointer;
3226
3227   if (vals == NULL)
3228     return FALSE;
3229
3230   if ((compare = gst_value_get_compare_func (src1))) {
3231     res1 = gst_value_compare_with_func (&vals[0], src1, compare);
3232     res2 = gst_value_compare_with_func (&vals[1], src1, compare);
3233
3234     if ((res1 == GST_VALUE_EQUAL || res1 == GST_VALUE_LESS_THAN) &&
3235         (res2 == GST_VALUE_EQUAL || res2 == GST_VALUE_GREATER_THAN)) {
3236       if (dest)
3237         gst_value_init_and_copy (dest, src1);
3238       return TRUE;
3239     }
3240   }
3241
3242   return FALSE;
3243 }
3244
3245 static gboolean
3246 gst_value_intersect_fraction_range_fraction_range (GValue * dest,
3247     const GValue * src1, const GValue * src2)
3248 {
3249   GValue *min;
3250   GValue *max;
3251   gint res;
3252   GValue *vals1, *vals2;
3253   GstValueCompareFunc compare;
3254
3255   vals1 = src1->data[0].v_pointer;
3256   vals2 = src2->data[0].v_pointer;
3257   g_return_val_if_fail (vals1 != NULL && vals2 != NULL, FALSE);
3258
3259   if ((compare = gst_value_get_compare_func (&vals1[0]))) {
3260     /* min = MAX (src1.start, src2.start) */
3261     res = gst_value_compare_with_func (&vals1[0], &vals2[0], compare);
3262     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
3263     if (res == GST_VALUE_LESS_THAN)
3264       min = &vals2[0];          /* Take the max of the 2 */
3265     else
3266       min = &vals1[0];
3267
3268     /* max = MIN (src1.end, src2.end) */
3269     res = gst_value_compare_with_func (&vals1[1], &vals2[1], compare);
3270     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
3271     if (res == GST_VALUE_GREATER_THAN)
3272       max = &vals2[1];          /* Take the min of the 2 */
3273     else
3274       max = &vals1[1];
3275
3276     res = gst_value_compare_with_func (min, max, compare);
3277     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
3278     if (res == GST_VALUE_LESS_THAN) {
3279       if (dest) {
3280         g_value_init (dest, GST_TYPE_FRACTION_RANGE);
3281         vals1 = dest->data[0].v_pointer;
3282         g_value_copy (min, &vals1[0]);
3283         g_value_copy (max, &vals1[1]);
3284       }
3285       return TRUE;
3286     }
3287     if (res == GST_VALUE_EQUAL) {
3288       if (dest)
3289         gst_value_init_and_copy (dest, min);
3290       return TRUE;
3291     }
3292   }
3293
3294   return FALSE;
3295 }
3296
3297 /***************
3298  * subtraction *
3299  ***************/
3300
3301 static gboolean
3302 gst_value_subtract_int_int_range (GValue * dest, const GValue * minuend,
3303     const GValue * subtrahend)
3304 {
3305   gint min = gst_value_get_int_range_min (subtrahend);
3306   gint max = gst_value_get_int_range_max (subtrahend);
3307   gint step = gst_value_get_int_range_step (subtrahend);
3308   gint val = g_value_get_int (minuend);
3309
3310   /* subtracting a range from an int only works if the int is not in the
3311    * range */
3312   if (val < min || val > max || val % step) {
3313     /* and the result is the int */
3314     if (dest)
3315       gst_value_init_and_copy (dest, minuend);
3316     return TRUE;
3317   }
3318   return FALSE;
3319 }
3320
3321 /* creates a new int range based on input values.
3322  */
3323 static gboolean
3324 gst_value_create_new_range (GValue * dest, gint min1, gint max1, gint min2,
3325     gint max2, gint step)
3326 {
3327   GValue v1 = { 0, };
3328   GValue v2 = { 0, };
3329   GValue *pv1, *pv2;            /* yeah, hungarian! */
3330
3331   g_return_val_if_fail (step > 0, FALSE);
3332   g_return_val_if_fail (min1 % step == 0, FALSE);
3333   g_return_val_if_fail (max1 % step == 0, FALSE);
3334   g_return_val_if_fail (min2 % step == 0, FALSE);
3335   g_return_val_if_fail (max2 % step == 0, FALSE);
3336
3337   if (min1 <= max1 && min2 <= max2) {
3338     pv1 = &v1;
3339     pv2 = &v2;
3340   } else if (min1 <= max1) {
3341     pv1 = dest;
3342     pv2 = NULL;
3343   } else if (min2 <= max2) {
3344     pv1 = NULL;
3345     pv2 = dest;
3346   } else {
3347     return FALSE;
3348   }
3349
3350   if (!dest)
3351     return TRUE;
3352
3353   if (min1 < max1) {
3354     g_value_init (pv1, GST_TYPE_INT_RANGE);
3355     gst_value_set_int_range_step (pv1, min1, max1, step);
3356   } else if (min1 == max1) {
3357     g_value_init (pv1, G_TYPE_INT);
3358     g_value_set_int (pv1, min1);
3359   }
3360   if (min2 < max2) {
3361     g_value_init (pv2, GST_TYPE_INT_RANGE);
3362     gst_value_set_int_range_step (pv2, min2, max2, step);
3363   } else if (min2 == max2) {
3364     g_value_init (pv2, G_TYPE_INT);
3365     g_value_set_int (pv2, min2);
3366   }
3367
3368   if (min1 <= max1 && min2 <= max2) {
3369     gst_value_list_concat (dest, pv1, pv2);
3370     g_value_unset (pv1);
3371     g_value_unset (pv2);
3372   }
3373   return TRUE;
3374 }
3375
3376 static gboolean
3377 gst_value_subtract_int_range_int (GValue * dest, const GValue * minuend,
3378     const GValue * subtrahend)
3379 {
3380   gint min = gst_value_get_int_range_min (minuend);
3381   gint max = gst_value_get_int_range_max (minuend);
3382   gint step = gst_value_get_int_range_step (minuend);
3383   gint val = g_value_get_int (subtrahend);
3384
3385   g_return_val_if_fail (min < max, FALSE);
3386
3387   /* value is outside of the range, return range unchanged */
3388   if (val < min || val > max || val % step) {
3389     if (dest)
3390       gst_value_init_and_copy (dest, minuend);
3391     return TRUE;
3392   } else {
3393     /* max must be MAXINT too as val <= max */
3394     if (val >= G_MAXINT - step + 1) {
3395       max -= step;
3396       val -= step;
3397     }
3398     /* min must be MININT too as val >= max */
3399     if (val <= G_MININT + step - 1) {
3400       min += step;
3401       val += step;
3402     }
3403     if (dest)
3404       gst_value_create_new_range (dest, min, val - step, val + step, max, step);
3405   }
3406   return TRUE;
3407 }
3408
3409 static gboolean
3410 gst_value_subtract_int_range_int_range (GValue * dest, const GValue * minuend,
3411     const GValue * subtrahend)
3412 {
3413   gint min1 = gst_value_get_int_range_min (minuend);
3414   gint max1 = gst_value_get_int_range_max (minuend);
3415   gint step1 = gst_value_get_int_range_step (minuend);
3416   gint min2 = gst_value_get_int_range_min (subtrahend);
3417   gint max2 = gst_value_get_int_range_max (subtrahend);
3418   gint step2 = gst_value_get_int_range_step (subtrahend);
3419   gint step;
3420
3421   if (step1 != step2) {
3422     /* ENOIMPL */
3423     g_assert (FALSE);
3424     return FALSE;
3425   }
3426   step = step1;
3427
3428   if (max2 >= max1 && min2 <= min1) {
3429     return FALSE;
3430   } else if (max2 >= max1) {
3431     return gst_value_create_new_range (dest, min1, MIN (min2 - step, max1),
3432         step, 0, step);
3433   } else if (min2 <= min1) {
3434     return gst_value_create_new_range (dest, MAX (max2 + step, min1), max1,
3435         step, 0, step);
3436   } else {
3437     return gst_value_create_new_range (dest, min1, MIN (min2 - step, max1),
3438         MAX (max2 + step, min1), max1, step);
3439   }
3440 }
3441
3442 static gboolean
3443 gst_value_subtract_int64_int64_range (GValue * dest, const GValue * minuend,
3444     const GValue * subtrahend)
3445 {
3446   gint64 min = gst_value_get_int64_range_min (subtrahend);
3447   gint64 max = gst_value_get_int64_range_max (subtrahend);
3448   gint64 step = gst_value_get_int64_range_step (subtrahend);
3449   gint64 val = g_value_get_int64 (minuend);
3450
3451   /* subtracting a range from an int64 only works if the int64 is not in the
3452    * range */
3453   if (val < min || val > max || val % step) {
3454     /* and the result is the int64 */
3455     if (dest)
3456       gst_value_init_and_copy (dest, minuend);
3457     return TRUE;
3458   }
3459   return FALSE;
3460 }
3461
3462 /* creates a new int64 range based on input values.
3463  */
3464 static gboolean
3465 gst_value_create_new_int64_range (GValue * dest, gint64 min1, gint64 max1,
3466     gint64 min2, gint64 max2, gint64 step)
3467 {
3468   GValue v1 = { 0, };
3469   GValue v2 = { 0, };
3470   GValue *pv1, *pv2;            /* yeah, hungarian! */
3471
3472   g_return_val_if_fail (step > 0, FALSE);
3473   g_return_val_if_fail (min1 % step == 0, FALSE);
3474   g_return_val_if_fail (max1 % step == 0, FALSE);
3475   g_return_val_if_fail (min2 % step == 0, FALSE);
3476   g_return_val_if_fail (max2 % step == 0, FALSE);
3477
3478   if (min1 <= max1 && min2 <= max2) {
3479     pv1 = &v1;
3480     pv2 = &v2;
3481   } else if (min1 <= max1) {
3482     pv1 = dest;
3483     pv2 = NULL;
3484   } else if (min2 <= max2) {
3485     pv1 = NULL;
3486     pv2 = dest;
3487   } else {
3488     return FALSE;
3489   }
3490
3491   if (!dest)
3492     return TRUE;
3493
3494   if (min1 < max1) {
3495     g_value_init (pv1, GST_TYPE_INT64_RANGE);
3496     gst_value_set_int64_range_step (pv1, min1, max1, step);
3497   } else if (min1 == max1) {
3498     g_value_init (pv1, G_TYPE_INT64);
3499     g_value_set_int64 (pv1, min1);
3500   }
3501   if (min2 < max2) {
3502     g_value_init (pv2, GST_TYPE_INT64_RANGE);
3503     gst_value_set_int64_range_step (pv2, min2, max2, step);
3504   } else if (min2 == max2) {
3505     g_value_init (pv2, G_TYPE_INT64);
3506     g_value_set_int64 (pv2, min2);
3507   }
3508
3509   if (min1 <= max1 && min2 <= max2) {
3510     gst_value_list_concat (dest, pv1, pv2);
3511     g_value_unset (pv1);
3512     g_value_unset (pv2);
3513   }
3514   return TRUE;
3515 }
3516
3517 static gboolean
3518 gst_value_subtract_int64_range_int64 (GValue * dest, const GValue * minuend,
3519     const GValue * subtrahend)
3520 {
3521   gint64 min = gst_value_get_int64_range_min (minuend);
3522   gint64 max = gst_value_get_int64_range_max (minuend);
3523   gint64 step = gst_value_get_int64_range_step (minuend);
3524   gint64 val = g_value_get_int64 (subtrahend);
3525
3526   g_return_val_if_fail (min < max, FALSE);
3527
3528   /* value is outside of the range, return range unchanged */
3529   if (val < min || val > max || val % step) {
3530     if (dest)
3531       gst_value_init_and_copy (dest, minuend);
3532     return TRUE;
3533   } else {
3534     /* max must be MAXINT64 too as val <= max */
3535     if (val >= G_MAXINT64 - step + 1) {
3536       max -= step;
3537       val -= step;
3538     }
3539     /* min must be MININT64 too as val >= max */
3540     if (val <= G_MININT64 + step - 1) {
3541       min += step;
3542       val += step;
3543     }
3544     if (dest)
3545       gst_value_create_new_int64_range (dest, min, val - step, val + step, max,
3546           step);
3547   }
3548   return TRUE;
3549 }
3550
3551 static gboolean
3552 gst_value_subtract_int64_range_int64_range (GValue * dest,
3553     const GValue * minuend, const GValue * subtrahend)
3554 {
3555   gint64 min1 = gst_value_get_int64_range_min (minuend);
3556   gint64 max1 = gst_value_get_int64_range_max (minuend);
3557   gint64 step1 = gst_value_get_int64_range_step (minuend);
3558   gint64 min2 = gst_value_get_int64_range_min (subtrahend);
3559   gint64 max2 = gst_value_get_int64_range_max (subtrahend);
3560   gint64 step2 = gst_value_get_int64_range_step (subtrahend);
3561   gint64 step;
3562
3563   if (step1 != step2) {
3564     /* ENOIMPL */
3565     g_assert (FALSE);
3566     return FALSE;
3567   }
3568   step = step1;
3569
3570   if (max2 >= max1 && min2 <= min1) {
3571     return FALSE;
3572   } else if (max2 >= max1) {
3573     return gst_value_create_new_int64_range (dest, min1, MIN (min2 - step,
3574             max1), step, 0, step);
3575   } else if (min2 <= min1) {
3576     return gst_value_create_new_int64_range (dest, MAX (max2 + step, min1),
3577         max1, step, 0, step);
3578   } else {
3579     return gst_value_create_new_int64_range (dest, min1, MIN (min2 - step,
3580             max1), MAX (max2 + step, min1), max1, step);
3581   }
3582 }
3583
3584 static gboolean
3585 gst_value_subtract_double_double_range (GValue * dest, const GValue * minuend,
3586     const GValue * subtrahend)
3587 {
3588   gdouble min = gst_value_get_double_range_min (subtrahend);
3589   gdouble max = gst_value_get_double_range_max (subtrahend);
3590   gdouble val = g_value_get_double (minuend);
3591
3592   if (val < min || val > max) {
3593     if (dest)
3594       gst_value_init_and_copy (dest, minuend);
3595     return TRUE;
3596   }
3597   return FALSE;
3598 }
3599
3600 static gboolean
3601 gst_value_subtract_double_range_double (GValue * dest, const GValue * minuend,
3602     const GValue * subtrahend)
3603 {
3604   /* since we don't have open ranges, we cannot create a hole in
3605    * a double range. We return the original range */
3606   if (dest)
3607     gst_value_init_and_copy (dest, minuend);
3608   return TRUE;
3609 }
3610
3611 static gboolean
3612 gst_value_subtract_double_range_double_range (GValue * dest,
3613     const GValue * minuend, const GValue * subtrahend)
3614 {
3615   /* since we don't have open ranges, we have to approximate */
3616   /* done like with ints */
3617   gdouble min1 = gst_value_get_double_range_min (minuend);
3618   gdouble max2 = gst_value_get_double_range_max (minuend);
3619   gdouble max1 = MIN (gst_value_get_double_range_min (subtrahend), max2);
3620   gdouble min2 = MAX (gst_value_get_double_range_max (subtrahend), min1);
3621   GValue v1 = { 0, };
3622   GValue v2 = { 0, };
3623   GValue *pv1, *pv2;            /* yeah, hungarian! */
3624
3625   if (min1 < max1 && min2 < max2) {
3626     pv1 = &v1;
3627     pv2 = &v2;
3628   } else if (min1 < max1) {
3629     pv1 = dest;
3630     pv2 = NULL;
3631   } else if (min2 < max2) {
3632     pv1 = NULL;
3633     pv2 = dest;
3634   } else {
3635     return FALSE;
3636   }
3637
3638   if (!dest)
3639     return TRUE;
3640
3641   if (min1 < max1) {
3642     g_value_init (pv1, GST_TYPE_DOUBLE_RANGE);
3643     gst_value_set_double_range (pv1, min1, max1);
3644   }
3645   if (min2 < max2) {
3646     g_value_init (pv2, GST_TYPE_DOUBLE_RANGE);
3647     gst_value_set_double_range (pv2, min2, max2);
3648   }
3649
3650   if (min1 < max1 && min2 < max2) {
3651     gst_value_list_concat (dest, pv1, pv2);
3652     g_value_unset (pv1);
3653     g_value_unset (pv2);
3654   }
3655   return TRUE;
3656 }
3657
3658 static gboolean
3659 gst_value_subtract_from_list (GValue * dest, const GValue * minuend,
3660     const GValue * subtrahend)
3661 {
3662   guint i, size;
3663   GValue subtraction = { 0, };
3664   gboolean ret = FALSE;
3665   GType ltype;
3666
3667   ltype = gst_value_list_get_type ();
3668
3669   size = VALUE_LIST_SIZE (minuend);
3670   for (i = 0; i < size; i++) {
3671     const GValue *cur = VALUE_LIST_GET_VALUE (minuend, i);
3672
3673     /* quicker version when we can discard the result */
3674     if (!dest) {
3675       if (gst_value_subtract (NULL, cur, subtrahend)) {
3676         ret = TRUE;
3677         break;
3678       }
3679       continue;
3680     }
3681
3682     if (gst_value_subtract (&subtraction, cur, subtrahend)) {
3683       if (!ret) {
3684         gst_value_init_and_copy (dest, &subtraction);
3685         ret = TRUE;
3686       } else if (G_VALUE_HOLDS (dest, ltype)
3687           && !G_VALUE_HOLDS (&subtraction, ltype)) {
3688         gst_value_list_append_value (dest, &subtraction);
3689       } else {
3690         GValue temp = { 0, };
3691
3692         gst_value_init_and_copy (&temp, dest);
3693         g_value_unset (dest);
3694         gst_value_list_concat (dest, &temp, &subtraction);
3695         g_value_unset (&temp);
3696       }
3697       g_value_unset (&subtraction);
3698     }
3699   }
3700   return ret;
3701 }
3702
3703 static gboolean
3704 gst_value_subtract_list (GValue * dest, const GValue * minuend,
3705     const GValue * subtrahend)
3706 {
3707   guint i, size;
3708   GValue data[2] = { {0,}, {0,} };
3709   GValue *subtraction = &data[0], *result = &data[1];
3710
3711   gst_value_init_and_copy (result, minuend);
3712   size = VALUE_LIST_SIZE (subtrahend);
3713   for (i = 0; i < size; i++) {
3714     const GValue *cur = VALUE_LIST_GET_VALUE (subtrahend, i);
3715
3716     if (gst_value_subtract (subtraction, result, cur)) {
3717       GValue *temp = result;
3718
3719       result = subtraction;
3720       subtraction = temp;
3721       g_value_unset (subtraction);
3722     } else {
3723       g_value_unset (result);
3724       return FALSE;
3725     }
3726   }
3727   if (dest)
3728     gst_value_init_and_copy (dest, result);
3729   g_value_unset (result);
3730   return TRUE;
3731 }
3732
3733 static gboolean
3734 gst_value_subtract_fraction_fraction_range (GValue * dest,
3735     const GValue * minuend, const GValue * subtrahend)
3736 {
3737   const GValue *min = gst_value_get_fraction_range_min (subtrahend);
3738   const GValue *max = gst_value_get_fraction_range_max (subtrahend);
3739   GstValueCompareFunc compare;
3740
3741   if ((compare = gst_value_get_compare_func (minuend))) {
3742     /* subtracting a range from an fraction only works if the fraction
3743      * is not in the range */
3744     if (gst_value_compare_with_func (minuend, min, compare) ==
3745         GST_VALUE_LESS_THAN ||
3746         gst_value_compare_with_func (minuend, max, compare) ==
3747         GST_VALUE_GREATER_THAN) {
3748       /* and the result is the value */
3749       if (dest)
3750         gst_value_init_and_copy (dest, minuend);
3751       return TRUE;
3752     }
3753   }
3754   return FALSE;
3755 }
3756
3757 static gboolean
3758 gst_value_subtract_fraction_range_fraction (GValue * dest,
3759     const GValue * minuend, const GValue * subtrahend)
3760 {
3761   /* since we don't have open ranges, we cannot create a hole in
3762    * a range. We return the original range */
3763   if (dest)
3764     gst_value_init_and_copy (dest, minuend);
3765   return TRUE;
3766 }
3767
3768 static gboolean
3769 gst_value_subtract_fraction_range_fraction_range (GValue * dest,
3770     const GValue * minuend, const GValue * subtrahend)
3771 {
3772   /* since we don't have open ranges, we have to approximate */
3773   /* done like with ints and doubles. Creates a list of 2 fraction ranges */
3774   const GValue *min1 = gst_value_get_fraction_range_min (minuend);
3775   const GValue *max2 = gst_value_get_fraction_range_max (minuend);
3776   const GValue *max1 = gst_value_get_fraction_range_min (subtrahend);
3777   const GValue *min2 = gst_value_get_fraction_range_max (subtrahend);
3778   gint cmp1, cmp2;
3779   GValue v1 = { 0, };
3780   GValue v2 = { 0, };
3781   GValue *pv1, *pv2;            /* yeah, hungarian! */
3782   GstValueCompareFunc compare;
3783
3784   g_return_val_if_fail (min1 != NULL && max1 != NULL, FALSE);
3785   g_return_val_if_fail (min2 != NULL && max2 != NULL, FALSE);
3786
3787   compare = gst_value_get_compare_func (min1);
3788   g_return_val_if_fail (compare, FALSE);
3789
3790   cmp1 = gst_value_compare_with_func (max2, max1, compare);
3791   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
3792   if (cmp1 == GST_VALUE_LESS_THAN)
3793     max1 = max2;
3794   cmp1 = gst_value_compare_with_func (min1, min2, compare);
3795   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
3796   if (cmp1 == GST_VALUE_GREATER_THAN)
3797     min2 = min1;
3798
3799   cmp1 = gst_value_compare_with_func (min1, max1, compare);
3800   cmp2 = gst_value_compare_with_func (min2, max2, compare);
3801
3802   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
3803     pv1 = &v1;
3804     pv2 = &v2;
3805   } else if (cmp1 == GST_VALUE_LESS_THAN) {
3806     pv1 = dest;
3807     pv2 = NULL;
3808   } else if (cmp2 == GST_VALUE_LESS_THAN) {
3809     pv1 = NULL;
3810     pv2 = dest;
3811   } else {
3812     return FALSE;
3813   }
3814
3815   if (!dest)
3816     return TRUE;
3817
3818   if (cmp1 == GST_VALUE_LESS_THAN) {
3819     g_value_init (pv1, GST_TYPE_FRACTION_RANGE);
3820     gst_value_set_fraction_range (pv1, min1, max1);
3821   }
3822   if (cmp2 == GST_VALUE_LESS_THAN) {
3823     g_value_init (pv2, GST_TYPE_FRACTION_RANGE);
3824     gst_value_set_fraction_range (pv2, min2, max2);
3825   }
3826
3827   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
3828     gst_value_list_concat (dest, pv1, pv2);
3829     g_value_unset (pv1);
3830     g_value_unset (pv2);
3831   }
3832   return TRUE;
3833 }
3834
3835
3836 /**************
3837  * comparison *
3838  **************/
3839
3840 /*
3841  * gst_value_get_compare_func:
3842  * @value1: a value to get the compare function for
3843  *
3844  * Determines the compare function to be used with values of the same type as
3845  * @value1. The function can be given to gst_value_compare_with_func().
3846  *
3847  * Returns: A #GstValueCompareFunc value
3848  */
3849 static GstValueCompareFunc
3850 gst_value_get_compare_func (const GValue * value1)
3851 {
3852   GstValueTable *table, *best = NULL;
3853   guint i;
3854   GType type1;
3855
3856   type1 = G_VALUE_TYPE (value1);
3857
3858   /* this is a fast check */
3859   best = gst_value_hash_lookup_type (type1);
3860
3861   /* slower checks */
3862   if (G_UNLIKELY (!best || !best->compare)) {
3863     guint len = gst_value_table->len;
3864
3865     best = NULL;
3866     for (i = 0; i < len; i++) {
3867       table = &g_array_index (gst_value_table, GstValueTable, i);
3868       if (table->compare && g_type_is_a (type1, table->type)) {
3869         if (!best || g_type_is_a (table->type, best->type))
3870           best = table;
3871       }
3872     }
3873   }
3874   if (G_LIKELY (best))
3875     return best->compare;
3876
3877   return NULL;
3878 }
3879
3880 /**
3881  * gst_value_can_compare:
3882  * @value1: a value to compare
3883  * @value2: another value to compare
3884  *
3885  * Determines if @value1 and @value2 can be compared.
3886  *
3887  * Returns: TRUE if the values can be compared
3888  */
3889 gboolean
3890 gst_value_can_compare (const GValue * value1, const GValue * value2)
3891 {
3892   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
3893   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
3894
3895   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
3896     return FALSE;
3897
3898   return gst_value_get_compare_func (value1) != NULL;
3899 }
3900
3901 static gboolean
3902 gst_value_list_equals_range (const GValue * list, const GValue * value)
3903 {
3904   const GValue *first;
3905   guint list_size, n;
3906
3907   g_return_val_if_fail (G_IS_VALUE (list), FALSE);
3908   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
3909   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (list), FALSE);
3910
3911   /* TODO: compare against an empty list ? No type though... */
3912   list_size = VALUE_LIST_SIZE (list);
3913   if (list_size == 0)
3914     return FALSE;
3915
3916   /* compare the basic types - they have to match */
3917   first = VALUE_LIST_GET_VALUE (list, 0);
3918 #define CHECK_TYPES(type,prefix) \
3919   (prefix##_VALUE_HOLDS_##type(first) && GST_VALUE_HOLDS_##type##_RANGE (value))
3920   if (CHECK_TYPES (INT, G)) {
3921     const gint rmin = gst_value_get_int_range_min (value);
3922     const gint rmax = gst_value_get_int_range_max (value);
3923     const gint rstep = gst_value_get_int_range_step (value);
3924     /* note: this will overflow for min 0 and max INT_MAX, but this
3925        would only be equal to a list of INT_MAX elements, which seems
3926        very unlikely */
3927     if (list_size != rmax / rstep - rmin / rstep + 1)
3928       return FALSE;
3929     for (n = 0; n < list_size; ++n) {
3930       gint v = g_value_get_int (VALUE_LIST_GET_VALUE (list, n));
3931       if (v < rmin || v > rmax || v % rstep) {
3932         return FALSE;
3933       }
3934     }
3935     return TRUE;
3936   } else if (CHECK_TYPES (INT64, G)) {
3937     const gint64 rmin = gst_value_get_int64_range_min (value);
3938     const gint64 rmax = gst_value_get_int64_range_max (value);
3939     const gint64 rstep = gst_value_get_int64_range_step (value);
3940     GST_DEBUG ("List/range of int64s");
3941     if (list_size != rmax / rstep - rmin / rstep + 1)
3942       return FALSE;
3943     for (n = 0; n < list_size; ++n) {
3944       gint64 v = g_value_get_int64 (VALUE_LIST_GET_VALUE (list, n));
3945       if (v < rmin || v > rmax || v % rstep)
3946         return FALSE;
3947     }
3948     return TRUE;
3949   }
3950 #undef CHECK_TYPES
3951
3952   /* other combinations don't make sense for equality */
3953   return FALSE;
3954 }
3955
3956 /**
3957  * gst_value_compare:
3958  * @value1: a value to compare
3959  * @value2: another value to compare
3960  *
3961  * Compares @value1 and @value2.  If @value1 and @value2 cannot be
3962  * compared, the function returns GST_VALUE_UNORDERED.  Otherwise,
3963  * if @value1 is greater than @value2, GST_VALUE_GREATER_THAN is returned.
3964  * If @value1 is less than @value2, GST_VALUE_LESS_THAN is returned.
3965  * If the values are equal, GST_VALUE_EQUAL is returned.
3966  *
3967  * Returns: comparison result
3968  */
3969 gint
3970 gst_value_compare (const GValue * value1, const GValue * value2)
3971 {
3972   GstValueCompareFunc compare;
3973   GType ltype;
3974
3975   g_return_val_if_fail (G_IS_VALUE (value1), GST_VALUE_LESS_THAN);
3976   g_return_val_if_fail (G_IS_VALUE (value2), GST_VALUE_GREATER_THAN);
3977
3978   /* Special cases: lists and scalar values ("{ 1 }" and "1" are equal),
3979      as well as lists and ranges ("{ 1, 2 }" and "[ 1, 2 ]" are equal) */
3980   ltype = gst_value_list_get_type ();
3981   if (G_VALUE_HOLDS (value1, ltype) && !G_VALUE_HOLDS (value2, ltype)) {
3982
3983     if (gst_value_list_equals_range (value1, value2)) {
3984       return GST_VALUE_EQUAL;
3985     } else if (gst_value_list_get_size (value1) == 1) {
3986       const GValue *elt;
3987
3988       elt = gst_value_list_get_value (value1, 0);
3989       return gst_value_compare (elt, value2);
3990     }
3991   } else if (G_VALUE_HOLDS (value2, ltype) && !G_VALUE_HOLDS (value1, ltype)) {
3992     if (gst_value_list_equals_range (value2, value1)) {
3993       return GST_VALUE_EQUAL;
3994     } else if (gst_value_list_get_size (value2) == 1) {
3995       const GValue *elt;
3996
3997       elt = gst_value_list_get_value (value2, 0);
3998       return gst_value_compare (elt, value1);
3999     }
4000   }
4001
4002   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
4003     return GST_VALUE_UNORDERED;
4004
4005   compare = gst_value_get_compare_func (value1);
4006   if (compare) {
4007     return compare (value1, value2);
4008   }
4009
4010   g_critical ("unable to compare values of type %s\n",
4011       g_type_name (G_VALUE_TYPE (value1)));
4012   return GST_VALUE_UNORDERED;
4013 }
4014
4015 /*
4016  * gst_value_compare_with_func:
4017  * @value1: a value to compare
4018  * @value2: another value to compare
4019  * @compare: compare function
4020  *
4021  * Compares @value1 and @value2 using the @compare function. Works like
4022  * gst_value_compare() but allows to save time determining the compare function
4023  * a multiple times. 
4024  *
4025  * Returns: comparison result
4026  */
4027 static gint
4028 gst_value_compare_with_func (const GValue * value1, const GValue * value2,
4029     GstValueCompareFunc compare)
4030 {
4031   g_assert (compare);
4032
4033   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
4034     return GST_VALUE_UNORDERED;
4035
4036   return compare (value1, value2);
4037 }
4038
4039 /* union */
4040
4041 /**
4042  * gst_value_can_union:
4043  * @value1: a value to union
4044  * @value2: another value to union
4045  *
4046  * Determines if @value1 and @value2 can be non-trivially unioned.
4047  * Any two values can be trivially unioned by adding both of them
4048  * to a GstValueList.  However, certain types have the possibility
4049  * to be unioned in a simpler way.  For example, an integer range
4050  * and an integer can be unioned if the integer is a subset of the
4051  * integer range.  If there is the possibility that two values can
4052  * be unioned, this function returns TRUE.
4053  *
4054  * Returns: TRUE if there is a function allowing the two values to
4055  * be unioned.
4056  */
4057 gboolean
4058 gst_value_can_union (const GValue * value1, const GValue * value2)
4059 {
4060   GstValueUnionInfo *union_info;
4061   guint i, len;
4062
4063   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4064   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4065
4066   len = gst_value_union_funcs->len;
4067
4068   for (i = 0; i < len; i++) {
4069     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
4070     if (union_info->type1 == G_VALUE_TYPE (value1) &&
4071         union_info->type2 == G_VALUE_TYPE (value2))
4072       return TRUE;
4073     if (union_info->type1 == G_VALUE_TYPE (value2) &&
4074         union_info->type2 == G_VALUE_TYPE (value1))
4075       return TRUE;
4076   }
4077
4078   return FALSE;
4079 }
4080
4081 /**
4082  * gst_value_union:
4083  * @dest: (out caller-allocates): the destination value
4084  * @value1: a value to union
4085  * @value2: another value to union
4086  *
4087  * Creates a GValue corresponding to the union of @value1 and @value2.
4088  *
4089  * Returns: TRUE if the union suceeded.
4090  */
4091 gboolean
4092 gst_value_union (GValue * dest, const GValue * value1, const GValue * value2)
4093 {
4094   const GstValueUnionInfo *union_info;
4095   guint i, len;
4096   GType type1, type2;
4097
4098   g_return_val_if_fail (dest != NULL, FALSE);
4099   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4100   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4101   g_return_val_if_fail (gst_value_list_or_array_are_compatible (value1, value2),
4102       FALSE);
4103
4104   len = gst_value_union_funcs->len;
4105   type1 = G_VALUE_TYPE (value1);
4106   type2 = G_VALUE_TYPE (value2);
4107
4108   for (i = 0; i < len; i++) {
4109     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
4110     if (union_info->type1 == type1 && union_info->type2 == type2) {
4111       return union_info->func (dest, value1, value2);
4112     }
4113     if (union_info->type1 == type2 && union_info->type2 == type1) {
4114       return union_info->func (dest, value2, value1);
4115     }
4116   }
4117
4118   gst_value_list_concat (dest, value1, value2);
4119   return TRUE;
4120 }
4121
4122 /**
4123  * gst_value_register_union_func: (skip)
4124  * @type1: a type to union
4125  * @type2: another type to union
4126  * @func: a function that implements creating a union between the two types
4127  *
4128  * Registers a union function that can create a union between #GValue items
4129  * of the type @type1 and @type2.
4130  *
4131  * Union functions should be registered at startup before any pipelines are
4132  * started, as gst_value_register_union_func() is not thread-safe and cannot
4133  * be used at the same time as gst_value_union() or gst_value_can_union().
4134  */
4135 void
4136 gst_value_register_union_func (GType type1, GType type2, GstValueUnionFunc func)
4137 {
4138   GstValueUnionInfo union_info;
4139
4140   union_info.type1 = type1;
4141   union_info.type2 = type2;
4142   union_info.func = func;
4143
4144   g_array_append_val (gst_value_union_funcs, union_info);
4145 }
4146
4147 /* intersection */
4148
4149 /**
4150  * gst_value_can_intersect:
4151  * @value1: a value to intersect
4152  * @value2: another value to intersect
4153  *
4154  * Determines if intersecting two values will produce a valid result.
4155  * Two values will produce a valid intersection if they have the same
4156  * type, or if there is a method (registered by
4157  * gst_value_register_intersect_func()) to calculate the intersection.
4158  *
4159  * Returns: TRUE if the values can intersect
4160  */
4161 gboolean
4162 gst_value_can_intersect (const GValue * value1, const GValue * value2)
4163 {
4164   GstValueIntersectInfo *intersect_info;
4165   guint i, len;
4166   GType ltype, type1, type2;
4167
4168   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4169   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4170
4171   ltype = gst_value_list_get_type ();
4172
4173   /* special cases */
4174   if (G_VALUE_HOLDS (value1, ltype) || G_VALUE_HOLDS (value2, ltype))
4175     return TRUE;
4176
4177   type1 = G_VALUE_TYPE (value1);
4178   type2 = G_VALUE_TYPE (value2);
4179
4180   /* practically all GstValue types have a compare function (_can_compare=TRUE)
4181    * GstStructure and GstCaps have npot, but are intersectable */
4182   if (type1 == type2)
4183     return TRUE;
4184
4185   /* check registered intersect functions */
4186   len = gst_value_intersect_funcs->len;
4187   for (i = 0; i < len; i++) {
4188     intersect_info = &g_array_index (gst_value_intersect_funcs,
4189         GstValueIntersectInfo, i);
4190     if ((intersect_info->type1 == type1 && intersect_info->type2 == type2) ||
4191         (intersect_info->type1 == type2 && intersect_info->type2 == type1))
4192       return TRUE;
4193   }
4194
4195   return gst_value_can_compare (value1, value2);
4196 }
4197
4198 /**
4199  * gst_value_intersect:
4200  * @dest: (out caller-allocates) (transfer full): a uninitialized #GValue that will hold the calculated
4201  * intersection value. May be NULL if the resulting set if not needed.
4202  * @value1: a value to intersect
4203  * @value2: another value to intersect
4204  *
4205  * Calculates the intersection of two values.  If the values have
4206  * a non-empty intersection, the value representing the intersection
4207  * is placed in @dest, unless NULL.  If the intersection is non-empty,
4208  * @dest is not modified.
4209  *
4210  * Returns: TRUE if the intersection is non-empty
4211  */
4212 gboolean
4213 gst_value_intersect (GValue * dest, const GValue * value1,
4214     const GValue * value2)
4215 {
4216   GstValueIntersectInfo *intersect_info;
4217   guint i, len;
4218   GType ltype, type1, type2;
4219
4220   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4221   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4222
4223   ltype = gst_value_list_get_type ();
4224
4225   /* special cases first */
4226   if (G_VALUE_HOLDS (value1, ltype))
4227     return gst_value_intersect_list (dest, value1, value2);
4228   if (G_VALUE_HOLDS (value2, ltype))
4229     return gst_value_intersect_list (dest, value2, value1);
4230
4231   if (gst_value_compare (value1, value2) == GST_VALUE_EQUAL) {
4232     if (dest)
4233       gst_value_init_and_copy (dest, value1);
4234     return TRUE;
4235   }
4236
4237   type1 = G_VALUE_TYPE (value1);
4238   type2 = G_VALUE_TYPE (value2);
4239
4240   len = gst_value_intersect_funcs->len;
4241   for (i = 0; i < len; i++) {
4242     intersect_info = &g_array_index (gst_value_intersect_funcs,
4243         GstValueIntersectInfo, i);
4244     if (intersect_info->type1 == type1 && intersect_info->type2 == type2) {
4245       return intersect_info->func (dest, value1, value2);
4246     }
4247     if (intersect_info->type1 == type2 && intersect_info->type2 == type1) {
4248       return intersect_info->func (dest, value2, value1);
4249     }
4250   }
4251   return FALSE;
4252 }
4253
4254
4255
4256 /**
4257  * gst_value_register_intersect_func: (skip)
4258  * @type1: the first type to intersect
4259  * @type2: the second type to intersect
4260  * @func: the intersection function
4261  *
4262  * Registers a function that is called to calculate the intersection
4263  * of the values having the types @type1 and @type2.
4264  *
4265  * Intersect functions should be registered at startup before any pipelines are
4266  * started, as gst_value_register_intersect_func() is not thread-safe and
4267  * cannot be used at the same time as gst_value_intersect() or
4268  * gst_value_can_intersect().
4269  */
4270 void
4271 gst_value_register_intersect_func (GType type1, GType type2,
4272     GstValueIntersectFunc func)
4273 {
4274   GstValueIntersectInfo intersect_info;
4275
4276   intersect_info.type1 = type1;
4277   intersect_info.type2 = type2;
4278   intersect_info.func = func;
4279
4280   g_array_append_val (gst_value_intersect_funcs, intersect_info);
4281 }
4282
4283
4284 /* subtraction */
4285
4286 /**
4287  * gst_value_subtract:
4288  * @dest: (out caller-allocates): the destination value for the result if the
4289  *     subtraction is not empty. May be NULL, in which case the resulting set
4290  *     will not be computed, which can give a fair speedup.
4291  * @minuend: the value to subtract from
4292  * @subtrahend: the value to subtract
4293  *
4294  * Subtracts @subtrahend from @minuend and stores the result in @dest.
4295  * Note that this means subtraction as in sets, not as in mathematics.
4296  *
4297  * Returns: %TRUE if the subtraction is not empty
4298  */
4299 gboolean
4300 gst_value_subtract (GValue * dest, const GValue * minuend,
4301     const GValue * subtrahend)
4302 {
4303   GstValueSubtractInfo *info;
4304   guint i, len;
4305   GType ltype, mtype, stype;
4306
4307   g_return_val_if_fail (G_IS_VALUE (minuend), FALSE);
4308   g_return_val_if_fail (G_IS_VALUE (subtrahend), FALSE);
4309
4310   ltype = gst_value_list_get_type ();
4311
4312   /* special cases first */
4313   if (G_VALUE_HOLDS (minuend, ltype))
4314     return gst_value_subtract_from_list (dest, minuend, subtrahend);
4315   if (G_VALUE_HOLDS (subtrahend, ltype))
4316     return gst_value_subtract_list (dest, minuend, subtrahend);
4317
4318   mtype = G_VALUE_TYPE (minuend);
4319   stype = G_VALUE_TYPE (subtrahend);
4320
4321   len = gst_value_subtract_funcs->len;
4322   for (i = 0; i < len; i++) {
4323     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
4324     if (info->minuend == mtype && info->subtrahend == stype) {
4325       return info->func (dest, minuend, subtrahend);
4326     }
4327   }
4328
4329   if (gst_value_compare (minuend, subtrahend) != GST_VALUE_EQUAL) {
4330     if (dest)
4331       gst_value_init_and_copy (dest, minuend);
4332     return TRUE;
4333   }
4334
4335   return FALSE;
4336 }
4337
4338 #if 0
4339 gboolean
4340 gst_value_subtract (GValue * dest, const GValue * minuend,
4341     const GValue * subtrahend)
4342 {
4343   gboolean ret = gst_value_subtract2 (dest, minuend, subtrahend);
4344
4345   g_printerr ("\"%s\"  -  \"%s\"  =  \"%s\"\n", gst_value_serialize (minuend),
4346       gst_value_serialize (subtrahend),
4347       ret ? gst_value_serialize (dest) : "---");
4348   return ret;
4349 }
4350 #endif
4351
4352 /**
4353  * gst_value_can_subtract:
4354  * @minuend: the value to subtract from
4355  * @subtrahend: the value to subtract
4356  *
4357  * Checks if it's possible to subtract @subtrahend from @minuend.
4358  *
4359  * Returns: TRUE if a subtraction is possible
4360  */
4361 gboolean
4362 gst_value_can_subtract (const GValue * minuend, const GValue * subtrahend)
4363 {
4364   GstValueSubtractInfo *info;
4365   guint i, len;
4366   GType ltype, mtype, stype;
4367
4368   g_return_val_if_fail (G_IS_VALUE (minuend), FALSE);
4369   g_return_val_if_fail (G_IS_VALUE (subtrahend), FALSE);
4370
4371   ltype = gst_value_list_get_type ();
4372
4373   /* special cases */
4374   if (G_VALUE_HOLDS (minuend, ltype) || G_VALUE_HOLDS (subtrahend, ltype))
4375     return TRUE;
4376
4377   mtype = G_VALUE_TYPE (minuend);
4378   stype = G_VALUE_TYPE (subtrahend);
4379
4380   len = gst_value_subtract_funcs->len;
4381   for (i = 0; i < len; i++) {
4382     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
4383     if (info->minuend == mtype && info->subtrahend == stype)
4384       return TRUE;
4385   }
4386
4387   return gst_value_can_compare (minuend, subtrahend);
4388 }
4389
4390 /**
4391  * gst_value_register_subtract_func: (skip)
4392  * @minuend_type: type of the minuend
4393  * @subtrahend_type: type of the subtrahend
4394  * @func: function to use
4395  *
4396  * Registers @func as a function capable of subtracting the values of
4397  * @subtrahend_type from values of @minuend_type.
4398  *
4399  * Subtract functions should be registered at startup before any pipelines are
4400  * started, as gst_value_register_subtract_func() is not thread-safe and
4401  * cannot be used at the same time as gst_value_subtract().
4402  */
4403 void
4404 gst_value_register_subtract_func (GType minuend_type, GType subtrahend_type,
4405     GstValueSubtractFunc func)
4406 {
4407   GstValueSubtractInfo info;
4408
4409   /* one type must be unfixed, other subtractions can be done as comparisons,
4410    * special case: bitmasks */
4411   if (minuend_type != GST_TYPE_BITMASK)
4412     g_return_if_fail (!gst_type_is_fixed (minuend_type)
4413         || !gst_type_is_fixed (subtrahend_type));
4414
4415   info.minuend = minuend_type;
4416   info.subtrahend = subtrahend_type;
4417   info.func = func;
4418
4419   g_array_append_val (gst_value_subtract_funcs, info);
4420 }
4421
4422 /**
4423  * gst_value_register:
4424  * @table: structure containing functions to register
4425  *
4426  * Registers functions to perform calculations on #GValue items of a given
4427  * type. Each type can only be added once.
4428  */
4429 void
4430 gst_value_register (const GstValueTable * table)
4431 {
4432   GstValueTable *found;
4433
4434   g_return_if_fail (table != NULL);
4435
4436   g_array_append_val (gst_value_table, *table);
4437
4438   found = gst_value_hash_lookup_type (table->type);
4439   if (found)
4440     g_warning ("adding type %s multiple times", g_type_name (table->type));
4441
4442   /* FIXME: we're not really doing the const justice, we assume the table is
4443    * static */
4444   gst_value_hash_add_type (table->type, table);
4445 }
4446
4447 /**
4448  * gst_value_init_and_copy:
4449  * @dest: (out caller-allocates): the target value
4450  * @src: the source value
4451  *
4452  * Initialises the target value to be of the same type as source and then copies
4453  * the contents from source to target.
4454  */
4455 void
4456 gst_value_init_and_copy (GValue * dest, const GValue * src)
4457 {
4458   g_return_if_fail (G_IS_VALUE (src));
4459   g_return_if_fail (dest != NULL);
4460
4461   g_value_init (dest, G_VALUE_TYPE (src));
4462   g_value_copy (src, dest);
4463 }
4464
4465 /**
4466  * gst_value_serialize:
4467  * @value: a #GValue to serialize
4468  *
4469  * tries to transform the given @value into a string representation that allows
4470  * getting back this string later on using gst_value_deserialize().
4471  *
4472  * Free-function: g_free
4473  *
4474  * Returns: (transfer full): the serialization for @value or NULL if none exists
4475  */
4476 gchar *
4477 gst_value_serialize (const GValue * value)
4478 {
4479   guint i, len;
4480   GValue s_val = { 0 };
4481   GstValueTable *table, *best;
4482   gchar *s;
4483   GType type;
4484
4485   g_return_val_if_fail (G_IS_VALUE (value), NULL);
4486
4487   type = G_VALUE_TYPE (value);
4488
4489   best = gst_value_hash_lookup_type (type);
4490
4491   if (G_UNLIKELY (!best || !best->serialize)) {
4492     len = gst_value_table->len;
4493     best = NULL;
4494     for (i = 0; i < len; i++) {
4495       table = &g_array_index (gst_value_table, GstValueTable, i);
4496       if (table->serialize && g_type_is_a (type, table->type)) {
4497         if (!best || g_type_is_a (table->type, best->type))
4498           best = table;
4499       }
4500     }
4501   }
4502   if (G_LIKELY (best))
4503     return best->serialize (value);
4504
4505   g_value_init (&s_val, G_TYPE_STRING);
4506   if (g_value_transform (value, &s_val)) {
4507     s = gst_string_wrap (g_value_get_string (&s_val));
4508   } else {
4509     s = NULL;
4510   }
4511   g_value_unset (&s_val);
4512
4513   return s;
4514 }
4515
4516 /**
4517  * gst_value_deserialize:
4518  * @dest: (out caller-allocates): #GValue to fill with contents of
4519  *     deserialization
4520  * @src: string to deserialize
4521  *
4522  * Tries to deserialize a string into the type specified by the given GValue.
4523  * If the operation succeeds, TRUE is returned, FALSE otherwise.
4524  *
4525  * Returns: TRUE on success
4526  */
4527 gboolean
4528 gst_value_deserialize (GValue * dest, const gchar * src)
4529 {
4530   GstValueTable *table, *best;
4531   guint i, len;
4532   GType type;
4533
4534   g_return_val_if_fail (src != NULL, FALSE);
4535   g_return_val_if_fail (G_IS_VALUE (dest), FALSE);
4536
4537   type = G_VALUE_TYPE (dest);
4538
4539   best = gst_value_hash_lookup_type (type);
4540   if (G_UNLIKELY (!best || !best->deserialize)) {
4541     len = gst_value_table->len;
4542     best = NULL;
4543     for (i = 0; i < len; i++) {
4544       table = &g_array_index (gst_value_table, GstValueTable, i);
4545       if (table->deserialize && g_type_is_a (type, table->type)) {
4546         if (!best || g_type_is_a (table->type, best->type))
4547           best = table;
4548       }
4549     }
4550   }
4551   if (G_LIKELY (best))
4552     return best->deserialize (dest, src);
4553
4554   return FALSE;
4555 }
4556
4557 /**
4558  * gst_value_is_fixed:
4559  * @value: the #GValue to check
4560  *
4561  * Tests if the given GValue, if available in a GstStructure (or any other
4562  * container) contains a "fixed" (which means: one value) or an "unfixed"
4563  * (which means: multiple possible values, such as data lists or data
4564  * ranges) value.
4565  *
4566  * Returns: true if the value is "fixed".
4567  */
4568
4569 gboolean
4570 gst_value_is_fixed (const GValue * value)
4571 {
4572   GType type;
4573
4574   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
4575
4576   type = G_VALUE_TYPE (value);
4577
4578   /* the most common types are just basic plain glib types */
4579   if (type <= G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
4580     return TRUE;
4581   }
4582
4583   if (type == GST_TYPE_ARRAY) {
4584     gint size, n;
4585     const GValue *kid;
4586
4587     /* check recursively */
4588     size = gst_value_array_get_size (value);
4589     for (n = 0; n < size; n++) {
4590       kid = gst_value_array_get_value (value, n);
4591       if (!gst_value_is_fixed (kid))
4592         return FALSE;
4593     }
4594     return TRUE;
4595   }
4596   return gst_type_is_fixed (type);
4597 }
4598
4599 /**
4600  * gst_value_fixate:
4601  * @dest: the #GValue destination
4602  * @src: the #GValue to fixate
4603  *
4604  * Fixate @src into a new value @dest.
4605  * For ranges, the first element is taken. For lists and arrays, the
4606  * first item is fixated and returned.
4607  * If @src is already fixed, this function returns FALSE.
4608  *
4609  * Returns: true if @dest contains a fixated version of @src.
4610  */
4611 gboolean
4612 gst_value_fixate (GValue * dest, const GValue * src)
4613 {
4614   g_return_val_if_fail (G_IS_VALUE (src), FALSE);
4615   g_return_val_if_fail (dest != NULL, FALSE);
4616
4617   if (G_VALUE_TYPE (src) == GST_TYPE_INT_RANGE) {
4618     g_value_init (dest, G_TYPE_INT);
4619     g_value_set_int (dest, gst_value_get_int_range_min (src));
4620   } else if (G_VALUE_TYPE (src) == GST_TYPE_DOUBLE_RANGE) {
4621     g_value_init (dest, G_TYPE_DOUBLE);
4622     g_value_set_double (dest, gst_value_get_double_range_min (src));
4623   } else if (G_VALUE_TYPE (src) == GST_TYPE_FRACTION_RANGE) {
4624     gst_value_init_and_copy (dest, gst_value_get_fraction_range_min (src));
4625   } else if (G_VALUE_TYPE (src) == GST_TYPE_LIST) {
4626     GValue temp = { 0 };
4627
4628     /* list could be empty */
4629     if (gst_value_list_get_size (src) <= 0)
4630       return FALSE;
4631
4632     gst_value_init_and_copy (&temp, gst_value_list_get_value (src, 0));
4633
4634     if (!gst_value_fixate (dest, &temp))
4635       gst_value_init_and_copy (dest, &temp);
4636     g_value_unset (&temp);
4637   } else if (G_VALUE_TYPE (src) == GST_TYPE_ARRAY) {
4638     gboolean res = FALSE;
4639     guint n, len;
4640
4641     len = gst_value_array_get_size (src);
4642     g_value_init (dest, GST_TYPE_ARRAY);
4643     for (n = 0; n < len; n++) {
4644       GValue kid = { 0 };
4645       const GValue *orig_kid = gst_value_array_get_value (src, n);
4646
4647       if (!gst_value_fixate (&kid, orig_kid))
4648         gst_value_init_and_copy (&kid, orig_kid);
4649       else
4650         res = TRUE;
4651       gst_value_array_append_value (dest, &kid);
4652       g_value_unset (&kid);
4653     }
4654
4655     if (!res)
4656       g_value_unset (dest);
4657
4658     return res;
4659   } else {
4660     return FALSE;
4661   }
4662   return TRUE;
4663 }
4664
4665
4666 /************
4667  * fraction *
4668  ************/
4669
4670 /* helper functions */
4671 static void
4672 gst_value_init_fraction (GValue * value)
4673 {
4674   value->data[0].v_int = 0;
4675   value->data[1].v_int = 1;
4676 }
4677
4678 static void
4679 gst_value_copy_fraction (const GValue * src_value, GValue * dest_value)
4680 {
4681   dest_value->data[0].v_int = src_value->data[0].v_int;
4682   dest_value->data[1].v_int = src_value->data[1].v_int;
4683 }
4684
4685 static gchar *
4686 gst_value_collect_fraction (GValue * value, guint n_collect_values,
4687     GTypeCValue * collect_values, guint collect_flags)
4688 {
4689   if (n_collect_values != 2)
4690     return g_strdup_printf ("not enough value locations for `%s' passed",
4691         G_VALUE_TYPE_NAME (value));
4692   if (collect_values[1].v_int == 0)
4693     return g_strdup_printf ("passed '0' as denominator for `%s'",
4694         G_VALUE_TYPE_NAME (value));
4695   if (collect_values[0].v_int < -G_MAXINT)
4696     return
4697         g_strdup_printf
4698         ("passed value smaller than -G_MAXINT as numerator for `%s'",
4699         G_VALUE_TYPE_NAME (value));
4700   if (collect_values[1].v_int < -G_MAXINT)
4701     return
4702         g_strdup_printf
4703         ("passed value smaller than -G_MAXINT as denominator for `%s'",
4704         G_VALUE_TYPE_NAME (value));
4705
4706   gst_value_set_fraction (value,
4707       collect_values[0].v_int, collect_values[1].v_int);
4708
4709   return NULL;
4710 }
4711
4712 static gchar *
4713 gst_value_lcopy_fraction (const GValue * value, guint n_collect_values,
4714     GTypeCValue * collect_values, guint collect_flags)
4715 {
4716   gint *numerator = collect_values[0].v_pointer;
4717   gint *denominator = collect_values[1].v_pointer;
4718
4719   if (!numerator)
4720     return g_strdup_printf ("numerator for `%s' passed as NULL",
4721         G_VALUE_TYPE_NAME (value));
4722   if (!denominator)
4723     return g_strdup_printf ("denominator for `%s' passed as NULL",
4724         G_VALUE_TYPE_NAME (value));
4725
4726   *numerator = value->data[0].v_int;
4727   *denominator = value->data[1].v_int;
4728
4729   return NULL;
4730 }
4731
4732 /**
4733  * gst_value_set_fraction:
4734  * @value: a GValue initialized to #GST_TYPE_FRACTION
4735  * @numerator: the numerator of the fraction
4736  * @denominator: the denominator of the fraction
4737  *
4738  * Sets @value to the fraction specified by @numerator over @denominator.
4739  * The fraction gets reduced to the smallest numerator and denominator,
4740  * and if necessary the sign is moved to the numerator.
4741  */
4742 void
4743 gst_value_set_fraction (GValue * value, gint numerator, gint denominator)
4744 {
4745   gint gcd = 0;
4746
4747   g_return_if_fail (GST_VALUE_HOLDS_FRACTION (value));
4748   g_return_if_fail (denominator != 0);
4749   g_return_if_fail (denominator >= -G_MAXINT);
4750   g_return_if_fail (numerator >= -G_MAXINT);
4751
4752   /* normalize sign */
4753   if (denominator < 0) {
4754     numerator = -numerator;
4755     denominator = -denominator;
4756   }
4757
4758   /* check for reduction */
4759   gcd = gst_util_greatest_common_divisor (numerator, denominator);
4760   if (gcd) {
4761     numerator /= gcd;
4762     denominator /= gcd;
4763   }
4764
4765   g_assert (denominator > 0);
4766
4767   value->data[0].v_int = numerator;
4768   value->data[1].v_int = denominator;
4769 }
4770
4771 /**
4772  * gst_value_get_fraction_numerator:
4773  * @value: a GValue initialized to #GST_TYPE_FRACTION
4774  *
4775  * Gets the numerator of the fraction specified by @value.
4776  *
4777  * Returns: the numerator of the fraction.
4778  */
4779 gint
4780 gst_value_get_fraction_numerator (const GValue * value)
4781 {
4782   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 0);
4783
4784   return value->data[0].v_int;
4785 }
4786
4787 /**
4788  * gst_value_get_fraction_denominator:
4789  * @value: a GValue initialized to #GST_TYPE_FRACTION
4790  *
4791  * Gets the denominator of the fraction specified by @value.
4792  *
4793  * Returns: the denominator of the fraction.
4794  */
4795 gint
4796 gst_value_get_fraction_denominator (const GValue * value)
4797 {
4798   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 1);
4799
4800   return value->data[1].v_int;
4801 }
4802
4803 /**
4804  * gst_value_fraction_multiply:
4805  * @product: a GValue initialized to #GST_TYPE_FRACTION
4806  * @factor1: a GValue initialized to #GST_TYPE_FRACTION
4807  * @factor2: a GValue initialized to #GST_TYPE_FRACTION
4808  *
4809  * Multiplies the two #GValue items containing a #GST_TYPE_FRACTION and sets
4810  * @product to the product of the two fractions.
4811  *
4812  * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise.
4813  */
4814 gboolean
4815 gst_value_fraction_multiply (GValue * product, const GValue * factor1,
4816     const GValue * factor2)
4817 {
4818   gint n1, n2, d1, d2;
4819   gint res_n, res_d;
4820
4821   g_return_val_if_fail (product != NULL, FALSE);
4822   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor1), FALSE);
4823   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor2), FALSE);
4824
4825   n1 = factor1->data[0].v_int;
4826   n2 = factor2->data[0].v_int;
4827   d1 = factor1->data[1].v_int;
4828   d2 = factor2->data[1].v_int;
4829
4830   if (!gst_util_fraction_multiply (n1, d1, n2, d2, &res_n, &res_d))
4831     return FALSE;
4832
4833   gst_value_set_fraction (product, res_n, res_d);
4834
4835   return TRUE;
4836 }
4837
4838 /**
4839  * gst_value_fraction_subtract:
4840  * @dest: a GValue initialized to #GST_TYPE_FRACTION
4841  * @minuend: a GValue initialized to #GST_TYPE_FRACTION
4842  * @subtrahend: a GValue initialized to #GST_TYPE_FRACTION
4843  *
4844  * Subtracts the @subtrahend from the @minuend and sets @dest to the result.
4845  *
4846  * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise.
4847  */
4848 gboolean
4849 gst_value_fraction_subtract (GValue * dest,
4850     const GValue * minuend, const GValue * subtrahend)
4851 {
4852   gint n1, n2, d1, d2;
4853   gint res_n, res_d;
4854
4855   g_return_val_if_fail (dest != NULL, FALSE);
4856   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (minuend), FALSE);
4857   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (subtrahend), FALSE);
4858
4859   n1 = minuend->data[0].v_int;
4860   n2 = subtrahend->data[0].v_int;
4861   d1 = minuend->data[1].v_int;
4862   d2 = subtrahend->data[1].v_int;
4863
4864   if (!gst_util_fraction_add (n1, d1, -n2, d2, &res_n, &res_d))
4865     return FALSE;
4866   gst_value_set_fraction (dest, res_n, res_d);
4867
4868   return TRUE;
4869 }
4870
4871 static gchar *
4872 gst_value_serialize_fraction (const GValue * value)
4873 {
4874   gint32 numerator = value->data[0].v_int;
4875   gint32 denominator = value->data[1].v_int;
4876   gboolean positive = TRUE;
4877
4878   /* get the sign and make components absolute */
4879   if (numerator < 0) {
4880     numerator = -numerator;
4881     positive = !positive;
4882   }
4883   if (denominator < 0) {
4884     denominator = -denominator;
4885     positive = !positive;
4886   }
4887
4888   return g_strdup_printf ("%s%d/%d",
4889       positive ? "" : "-", numerator, denominator);
4890 }
4891
4892 static gboolean
4893 gst_value_deserialize_fraction (GValue * dest, const gchar * s)
4894 {
4895   gint num, den;
4896   gint num_chars;
4897
4898   if (G_UNLIKELY (s == NULL))
4899     return FALSE;
4900
4901   if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_FRACTION (dest)))
4902     return FALSE;
4903
4904   if (sscanf (s, "%d/%d%n", &num, &den, &num_chars) >= 2) {
4905     if (s[num_chars] != 0)
4906       return FALSE;
4907     if (den == 0)
4908       return FALSE;
4909
4910     gst_value_set_fraction (dest, num, den);
4911     return TRUE;
4912   } else if (g_ascii_strcasecmp (s, "1/max") == 0) {
4913     gst_value_set_fraction (dest, 1, G_MAXINT);
4914     return TRUE;
4915   } else if (sscanf (s, "%d%n", &num, &num_chars) >= 1) {
4916     if (s[num_chars] != 0)
4917       return FALSE;
4918     gst_value_set_fraction (dest, num, 1);
4919     return TRUE;
4920   } else if (g_ascii_strcasecmp (s, "min") == 0) {
4921     gst_value_set_fraction (dest, -G_MAXINT, 1);
4922     return TRUE;
4923   } else if (g_ascii_strcasecmp (s, "max") == 0) {
4924     gst_value_set_fraction (dest, G_MAXINT, 1);
4925     return TRUE;
4926   }
4927
4928   return FALSE;
4929 }
4930
4931 static void
4932 gst_value_transform_fraction_string (const GValue * src_value,
4933     GValue * dest_value)
4934 {
4935   dest_value->data[0].v_pointer = gst_value_serialize_fraction (src_value);
4936 }
4937
4938 static void
4939 gst_value_transform_string_fraction (const GValue * src_value,
4940     GValue * dest_value)
4941 {
4942   if (!gst_value_deserialize_fraction (dest_value,
4943           src_value->data[0].v_pointer))
4944     /* If the deserialize fails, ensure we leave the fraction in a
4945      * valid, if incorrect, state */
4946     gst_value_set_fraction (dest_value, 0, 1);
4947 }
4948
4949 static void
4950 gst_value_transform_double_fraction (const GValue * src_value,
4951     GValue * dest_value)
4952 {
4953   gdouble src = g_value_get_double (src_value);
4954   gint n, d;
4955
4956   gst_util_double_to_fraction (src, &n, &d);
4957   gst_value_set_fraction (dest_value, n, d);
4958 }
4959
4960 static void
4961 gst_value_transform_float_fraction (const GValue * src_value,
4962     GValue * dest_value)
4963 {
4964   gfloat src = g_value_get_float (src_value);
4965   gint n, d;
4966
4967   gst_util_double_to_fraction (src, &n, &d);
4968   gst_value_set_fraction (dest_value, n, d);
4969 }
4970
4971 static void
4972 gst_value_transform_fraction_double (const GValue * src_value,
4973     GValue * dest_value)
4974 {
4975   dest_value->data[0].v_double = ((double) src_value->data[0].v_int) /
4976       ((double) src_value->data[1].v_int);
4977 }
4978
4979 static void
4980 gst_value_transform_fraction_float (const GValue * src_value,
4981     GValue * dest_value)
4982 {
4983   dest_value->data[0].v_float = ((float) src_value->data[0].v_int) /
4984       ((float) src_value->data[1].v_int);
4985 }
4986
4987 static gint
4988 gst_value_compare_fraction (const GValue * value1, const GValue * value2)
4989 {
4990   gint n1, n2;
4991   gint d1, d2;
4992   gint ret;
4993
4994   n1 = value1->data[0].v_int;
4995   n2 = value2->data[0].v_int;
4996   d1 = value1->data[1].v_int;
4997   d2 = value2->data[1].v_int;
4998
4999   /* fractions are reduced when set, so we can quickly see if they're equal */
5000   if (n1 == n2 && d1 == d2)
5001     return GST_VALUE_EQUAL;
5002
5003   if (d1 == 0 && d2 == 0)
5004     return GST_VALUE_UNORDERED;
5005   else if (d1 == 0)
5006     return GST_VALUE_GREATER_THAN;
5007   else if (d2 == 0)
5008     return GST_VALUE_LESS_THAN;
5009
5010   ret = gst_util_fraction_compare (n1, d1, n2, d2);
5011   if (ret == -1)
5012     return GST_VALUE_LESS_THAN;
5013   else if (ret == 1)
5014     return GST_VALUE_GREATER_THAN;
5015
5016   /* Equality can't happen here because we check for that
5017    * first already */
5018   g_return_val_if_reached (GST_VALUE_UNORDERED);
5019 }
5020
5021 /*********
5022  * GDate *
5023  *********/
5024
5025 static gint
5026 gst_value_compare_date (const GValue * value1, const GValue * value2)
5027 {
5028   const GDate *date1 = (const GDate *) g_value_get_boxed (value1);
5029   const GDate *date2 = (const GDate *) g_value_get_boxed (value2);
5030   guint32 j1, j2;
5031
5032   if (date1 == date2)
5033     return GST_VALUE_EQUAL;
5034
5035   if ((date1 == NULL || !g_date_valid (date1))
5036       && (date2 != NULL && g_date_valid (date2))) {
5037     return GST_VALUE_LESS_THAN;
5038   }
5039
5040   if ((date2 == NULL || !g_date_valid (date2))
5041       && (date1 != NULL && g_date_valid (date1))) {
5042     return GST_VALUE_GREATER_THAN;
5043   }
5044
5045   if (date1 == NULL || date2 == NULL || !g_date_valid (date1)
5046       || !g_date_valid (date2)) {
5047     return GST_VALUE_UNORDERED;
5048   }
5049
5050   j1 = g_date_get_julian (date1);
5051   j2 = g_date_get_julian (date2);
5052
5053   if (j1 == j2)
5054     return GST_VALUE_EQUAL;
5055   else if (j1 < j2)
5056     return GST_VALUE_LESS_THAN;
5057   else
5058     return GST_VALUE_GREATER_THAN;
5059 }
5060
5061 static gchar *
5062 gst_value_serialize_date (const GValue * val)
5063 {
5064   const GDate *date = (const GDate *) g_value_get_boxed (val);
5065
5066   if (date == NULL || !g_date_valid (date))
5067     return g_strdup ("9999-99-99");
5068
5069   return g_strdup_printf ("%04u-%02u-%02u", g_date_get_year (date),
5070       g_date_get_month (date), g_date_get_day (date));
5071 }
5072
5073 static gboolean
5074 gst_value_deserialize_date (GValue * dest, const gchar * s)
5075 {
5076   guint year, month, day;
5077
5078   if (!s || sscanf (s, "%04u-%02u-%02u", &year, &month, &day) != 3)
5079     return FALSE;
5080
5081   if (!g_date_valid_dmy (day, month, year))
5082     return FALSE;
5083
5084   g_value_take_boxed (dest, g_date_new_dmy (day, month, year));
5085   return TRUE;
5086 }
5087
5088 /*************
5089  * GstDateTime *
5090  *************/
5091
5092 static gint
5093 gst_value_compare_date_time (const GValue * value1, const GValue * value2)
5094 {
5095   const GstDateTime *date1 = (const GstDateTime *) g_value_get_boxed (value1);
5096   const GstDateTime *date2 = (const GstDateTime *) g_value_get_boxed (value2);
5097   gint ret;
5098
5099   if (date1 == date2)
5100     return GST_VALUE_EQUAL;
5101
5102   if ((date1 == NULL) && (date2 != NULL)) {
5103     return GST_VALUE_LESS_THAN;
5104   }
5105   if ((date2 == NULL) && (date1 != NULL)) {
5106     return GST_VALUE_LESS_THAN;
5107   }
5108
5109   ret = priv_gst_date_time_compare (date1, date2);
5110
5111   if (ret == 0)
5112     return GST_VALUE_EQUAL;
5113   else if (ret < 0)
5114     return GST_VALUE_LESS_THAN;
5115   else
5116     return GST_VALUE_GREATER_THAN;
5117 }
5118
5119 static gchar *
5120 gst_value_serialize_date_time (const GValue * val)
5121 {
5122   GstDateTime *date = (GstDateTime *) g_value_get_boxed (val);
5123   gfloat offset;
5124   gint tzhour, tzminute;
5125
5126   if (date == NULL)
5127     return g_strdup ("null");
5128
5129   offset = gst_date_time_get_time_zone_offset (date);
5130
5131   tzhour = (gint) ABS (offset);
5132   tzminute = (gint) ((ABS (offset) - tzhour) * 60);
5133
5134   return g_strdup_printf ("\"%04d-%02d-%02dT%02d:%02d:%02d.%06d"
5135       "%c%02d%02d\"", gst_date_time_get_year (date),
5136       gst_date_time_get_month (date), gst_date_time_get_day (date),
5137       gst_date_time_get_hour (date), gst_date_time_get_minute (date),
5138       gst_date_time_get_second (date), gst_date_time_get_microsecond (date),
5139       offset >= 0 ? '+' : '-', tzhour, tzminute);
5140 }
5141
5142 static gboolean
5143 gst_value_deserialize_date_time (GValue * dest, const gchar * s)
5144 {
5145   gint year, month, day, hour, minute, second, usecond;
5146   gchar signal;
5147   gint offset = 0;
5148   gfloat tzoffset = 0;
5149   gint ret;
5150
5151   if (!s || strcmp (s, "null") == 0) {
5152     return FALSE;
5153   }
5154
5155   ret = sscanf (s, "%04d-%02d-%02dT%02d:%02d:%02d.%06d%c%04d",
5156       &year, &month, &day, &hour, &minute, &second, &usecond, &signal, &offset);
5157   if (ret >= 9) {
5158     tzoffset = (offset / 100) + ((offset % 100) / 60.0);
5159     if (signal == '-')
5160       tzoffset = -tzoffset;
5161   } else
5162     return FALSE;
5163
5164   g_value_take_boxed (dest, gst_date_time_new (tzoffset, year, month, day, hour,
5165           minute, second + (usecond / 1000000.0)));
5166   return TRUE;
5167 }
5168
5169 static void
5170 gst_value_transform_date_string (const GValue * src_value, GValue * dest_value)
5171 {
5172   dest_value->data[0].v_pointer = gst_value_serialize_date (src_value);
5173 }
5174
5175 static void
5176 gst_value_transform_string_date (const GValue * src_value, GValue * dest_value)
5177 {
5178   gst_value_deserialize_date (dest_value, src_value->data[0].v_pointer);
5179 }
5180
5181
5182 /************
5183  * bitmask *
5184  ************/
5185
5186 /* helper functions */
5187 static void
5188 gst_value_init_bitmask (GValue * value)
5189 {
5190   value->data[0].v_uint64 = 0;
5191 }
5192
5193 static void
5194 gst_value_copy_bitmask (const GValue * src_value, GValue * dest_value)
5195 {
5196   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
5197 }
5198
5199 static gchar *
5200 gst_value_collect_bitmask (GValue * value, guint n_collect_values,
5201     GTypeCValue * collect_values, guint collect_flags)
5202 {
5203   if (n_collect_values != 1)
5204     return g_strdup_printf ("not enough value locations for `%s' passed",
5205         G_VALUE_TYPE_NAME (value));
5206
5207   gst_value_set_bitmask (value, (guint64) collect_values[0].v_int64);
5208
5209   return NULL;
5210 }
5211
5212 static gchar *
5213 gst_value_lcopy_bitmask (const GValue * value, guint n_collect_values,
5214     GTypeCValue * collect_values, guint collect_flags)
5215 {
5216   guint64 *bitmask = collect_values[0].v_pointer;
5217
5218   if (!bitmask)
5219     return g_strdup_printf ("value for `%s' passed as NULL",
5220         G_VALUE_TYPE_NAME (value));
5221
5222   *bitmask = value->data[0].v_uint64;
5223
5224   return NULL;
5225 }
5226
5227 /**
5228  * gst_value_set_bitmask:
5229  * @value: a GValue initialized to #GST_TYPE_FRACTION
5230  * @bitmask: the bitmask
5231  *
5232  * Sets @value to the bitmask specified by @bitmask.
5233  */
5234 void
5235 gst_value_set_bitmask (GValue * value, guint64 bitmask)
5236 {
5237   g_return_if_fail (GST_VALUE_HOLDS_BITMASK (value));
5238
5239   value->data[0].v_uint64 = bitmask;
5240 }
5241
5242 /**
5243  * gst_value_get_bitmask:
5244  * @value: a GValue initialized to #GST_TYPE_FRACTION
5245  *
5246  * Gets the bitmask specified by @value.
5247  *
5248  * Returns: the bitmask.
5249  */
5250 guint64
5251 gst_value_get_bitmask (const GValue * value)
5252 {
5253   g_return_val_if_fail (GST_VALUE_HOLDS_BITMASK (value), 0);
5254
5255   return value->data[0].v_uint64;
5256 }
5257
5258 static gchar *
5259 gst_value_serialize_bitmask (const GValue * value)
5260 {
5261   guint64 bitmask = value->data[0].v_uint64;
5262
5263   return g_strdup_printf ("0x%016" G_GINT64_MODIFIER "x", bitmask);
5264 }
5265
5266 static gboolean
5267 gst_value_deserialize_bitmask (GValue * dest, const gchar * s)
5268 {
5269   gchar *endptr = NULL;
5270   guint64 val;
5271
5272   if (G_UNLIKELY (s == NULL))
5273     return FALSE;
5274
5275   if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_BITMASK (dest)))
5276     return FALSE;
5277
5278   val = g_ascii_strtoull (s, &endptr, 16);
5279   if (val == G_MAXUINT64 && (errno == ERANGE || errno == EINVAL))
5280     return FALSE;
5281   if (val == 0 && endptr == s)
5282     return FALSE;
5283
5284   gst_value_set_bitmask (dest, val);
5285
5286   return TRUE;
5287 }
5288
5289 static void
5290 gst_value_transform_bitmask_string (const GValue * src_value,
5291     GValue * dest_value)
5292 {
5293   dest_value->data[0].v_pointer = gst_value_serialize_bitmask (src_value);
5294 }
5295
5296 static void
5297 gst_value_transform_string_bitmask (const GValue * src_value,
5298     GValue * dest_value)
5299 {
5300   if (!gst_value_deserialize_bitmask (dest_value, src_value->data[0].v_pointer))
5301     gst_value_set_bitmask (dest_value, 0);
5302 }
5303
5304 static void
5305 gst_value_transform_uint64_bitmask (const GValue * src_value,
5306     GValue * dest_value)
5307 {
5308   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
5309 }
5310
5311 static void
5312 gst_value_transform_bitmask_uint64 (const GValue * src_value,
5313     GValue * dest_value)
5314 {
5315   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
5316 }
5317
5318 static gboolean
5319 gst_value_intersect_bitmask_bitmask (GValue * dest, const GValue * src1,
5320     const GValue * src2)
5321 {
5322   guint64 s1, s2;
5323
5324   s1 = gst_value_get_bitmask (src1);
5325   s2 = gst_value_get_bitmask (src2);
5326
5327   if (dest) {
5328     g_value_init (dest, GST_TYPE_BITMASK);
5329     gst_value_set_bitmask (dest, s1 & s2);
5330   }
5331
5332   return TRUE;
5333 }
5334
5335 static gboolean
5336 gst_value_union_bitmask_bitmask (GValue * dest, const GValue * src1,
5337     const GValue * src2)
5338 {
5339   guint64 s1, s2;
5340
5341   s1 = gst_value_get_bitmask (src1);
5342   s2 = gst_value_get_bitmask (src2);
5343
5344   g_value_init (dest, GST_TYPE_BITMASK);
5345   gst_value_set_bitmask (dest, s1 | s2);
5346
5347   return TRUE;
5348 }
5349
5350 static gboolean
5351 gst_value_subtract_bitmask_bitmask (GValue * dest,
5352     const GValue * minuend, const GValue * subtrahend)
5353 {
5354   guint64 m, s, r;
5355
5356   g_return_val_if_fail (GST_VALUE_HOLDS_BITMASK (minuend), FALSE);
5357   g_return_val_if_fail (GST_VALUE_HOLDS_BITMASK (subtrahend), FALSE);
5358
5359   m = minuend->data[0].v_uint64;
5360   s = subtrahend->data[0].v_uint64;
5361   r = m & (~s);
5362
5363   if (dest) {
5364     g_value_init (dest, GST_TYPE_BITMASK);
5365     gst_value_set_bitmask (dest, r);
5366   }
5367   return (r != 0);
5368 }
5369
5370 static gint
5371 gst_value_compare_bitmask (const GValue * value1, const GValue * value2)
5372 {
5373   guint64 v1, v2;
5374
5375   v1 = value1->data[0].v_uint64;
5376   v2 = value2->data[0].v_uint64;
5377
5378   if (v1 == v2)
5379     return GST_VALUE_EQUAL;
5380
5381   return GST_VALUE_UNORDERED;
5382 }
5383
5384 static void
5385 gst_value_transform_object_string (const GValue * src_value,
5386     GValue * dest_value)
5387 {
5388   GstObject *obj;
5389   gchar *str;
5390
5391   obj = g_value_get_object (src_value);
5392   if (obj) {
5393     str =
5394         g_strdup_printf ("(%s) %s", G_OBJECT_TYPE_NAME (obj),
5395         GST_OBJECT_NAME (obj));
5396   } else {
5397     str = g_strdup ("NULL");
5398   }
5399
5400   dest_value->data[0].v_pointer = str;
5401 }
5402
5403 static GTypeInfo _info = {
5404   0,
5405   NULL,
5406   NULL,
5407   NULL,
5408   NULL,
5409   NULL,
5410   0,
5411   0,
5412   NULL,
5413   NULL,
5414 };
5415
5416 static GTypeFundamentalInfo _finfo = {
5417   0
5418 };
5419
5420 #define FUNC_VALUE_GET_TYPE(type, name)                         \
5421 GType gst_ ## type ## _get_type (void)                          \
5422 {                                                               \
5423   static volatile GType gst_ ## type ## _type = 0;                       \
5424                                                                 \
5425   if (g_once_init_enter (&gst_ ## type ## _type)) {             \
5426     GType _type;                                        \
5427     _info.value_table = & _gst_ ## type ## _value_table;        \
5428     _type = g_type_register_fundamental (       \
5429         g_type_fundamental_next (),                             \
5430         name, &_info, &_finfo, 0);                              \
5431     g_once_init_leave(&gst_ ## type ## _type, _type);   \
5432   }                                                             \
5433                                                                 \
5434   return gst_ ## type ## _type;                                 \
5435 }
5436
5437 static const GTypeValueTable _gst_int_range_value_table = {
5438   gst_value_init_int_range,
5439   gst_value_free_int_range,
5440   gst_value_copy_int_range,
5441   NULL,
5442   (char *) "ii",
5443   gst_value_collect_int_range,
5444   (char *) "pp",
5445   gst_value_lcopy_int_range
5446 };
5447
5448 FUNC_VALUE_GET_TYPE (int_range, "GstIntRange");
5449
5450 static const GTypeValueTable _gst_int64_range_value_table = {
5451   gst_value_init_int64_range,
5452   gst_value_free_int64_range,
5453   gst_value_copy_int64_range,
5454   NULL,
5455   (char *) "qq",
5456   gst_value_collect_int64_range,
5457   (char *) "pp",
5458   gst_value_lcopy_int64_range
5459 };
5460
5461 FUNC_VALUE_GET_TYPE (int64_range, "GstInt64Range");
5462
5463 static const GTypeValueTable _gst_double_range_value_table = {
5464   gst_value_init_double_range,
5465   NULL,
5466   gst_value_copy_double_range,
5467   NULL,
5468   (char *) "dd",
5469   gst_value_collect_double_range,
5470   (char *) "pp",
5471   gst_value_lcopy_double_range
5472 };
5473
5474 FUNC_VALUE_GET_TYPE (double_range, "GstDoubleRange");
5475
5476 static const GTypeValueTable _gst_fraction_range_value_table = {
5477   gst_value_init_fraction_range,
5478   gst_value_free_fraction_range,
5479   gst_value_copy_fraction_range,
5480   NULL,
5481   (char *) "iiii",
5482   gst_value_collect_fraction_range,
5483   (char *) "pppp",
5484   gst_value_lcopy_fraction_range
5485 };
5486
5487 FUNC_VALUE_GET_TYPE (fraction_range, "GstFractionRange");
5488
5489 static const GTypeValueTable _gst_value_list_value_table = {
5490   gst_value_init_list_or_array,
5491   gst_value_free_list_or_array,
5492   gst_value_copy_list_or_array,
5493   gst_value_list_or_array_peek_pointer,
5494   (char *) "p",
5495   gst_value_collect_list_or_array,
5496   (char *) "p",
5497   gst_value_lcopy_list_or_array
5498 };
5499
5500 FUNC_VALUE_GET_TYPE (value_list, "GstValueList");
5501
5502 static const GTypeValueTable _gst_value_array_value_table = {
5503   gst_value_init_list_or_array,
5504   gst_value_free_list_or_array,
5505   gst_value_copy_list_or_array,
5506   gst_value_list_or_array_peek_pointer,
5507   (char *) "p",
5508   gst_value_collect_list_or_array,
5509   (char *) "p",
5510   gst_value_lcopy_list_or_array
5511 };
5512
5513 FUNC_VALUE_GET_TYPE (value_array, "GstValueArray");
5514
5515 static const GTypeValueTable _gst_fraction_value_table = {
5516   gst_value_init_fraction,
5517   NULL,
5518   gst_value_copy_fraction,
5519   NULL,
5520   (char *) "ii",
5521   gst_value_collect_fraction,
5522   (char *) "pp",
5523   gst_value_lcopy_fraction
5524 };
5525
5526 FUNC_VALUE_GET_TYPE (fraction, "GstFraction");
5527
5528 G_DEFINE_BOXED_TYPE (GstDateTime, gst_date_time,
5529     (GBoxedCopyFunc) gst_date_time_ref, (GBoxedFreeFunc) gst_date_time_unref);
5530
5531 static const GTypeValueTable _gst_bitmask_value_table = {
5532   gst_value_init_bitmask,
5533   NULL,
5534   gst_value_copy_bitmask,
5535   NULL,
5536   (char *) "q",
5537   gst_value_collect_bitmask,
5538   (char *) "p",
5539   gst_value_lcopy_bitmask
5540 };
5541
5542 FUNC_VALUE_GET_TYPE (bitmask, "GstBitmask");
5543
5544
5545 void
5546 _priv_gst_value_initialize (void)
5547 {
5548   gst_value_table = g_array_new (FALSE, FALSE, sizeof (GstValueTable));
5549   gst_value_hash = g_hash_table_new (NULL, NULL);
5550   gst_value_union_funcs = g_array_new (FALSE, FALSE,
5551       sizeof (GstValueUnionInfo));
5552   gst_value_intersect_funcs = g_array_new (FALSE, FALSE,
5553       sizeof (GstValueIntersectInfo));
5554   gst_value_subtract_funcs = g_array_new (FALSE, FALSE,
5555       sizeof (GstValueSubtractInfo));
5556
5557   {
5558     static GstValueTable gst_value = {
5559       0,
5560       gst_value_compare_int_range,
5561       gst_value_serialize_int_range,
5562       gst_value_deserialize_int_range,
5563     };
5564
5565     gst_value.type = gst_int_range_get_type ();
5566     gst_value_register (&gst_value);
5567   }
5568
5569   {
5570     static GstValueTable gst_value = {
5571       0,
5572       gst_value_compare_int64_range,
5573       gst_value_serialize_int64_range,
5574       gst_value_deserialize_int64_range,
5575     };
5576
5577     gst_value.type = gst_int64_range_get_type ();
5578     gst_value_register (&gst_value);
5579   }
5580
5581   {
5582     static GstValueTable gst_value = {
5583       0,
5584       gst_value_compare_double_range,
5585       gst_value_serialize_double_range,
5586       gst_value_deserialize_double_range,
5587     };
5588
5589     gst_value.type = gst_double_range_get_type ();
5590     gst_value_register (&gst_value);
5591   }
5592
5593   {
5594     static GstValueTable gst_value = {
5595       0,
5596       gst_value_compare_fraction_range,
5597       gst_value_serialize_fraction_range,
5598       gst_value_deserialize_fraction_range,
5599     };
5600
5601     gst_value.type = gst_fraction_range_get_type ();
5602     gst_value_register (&gst_value);
5603   }
5604
5605   {
5606     static GstValueTable gst_value = {
5607       0,
5608       gst_value_compare_list,
5609       gst_value_serialize_list,
5610       gst_value_deserialize_list,
5611     };
5612
5613     gst_value.type = gst_value_list_get_type ();
5614     gst_value_register (&gst_value);
5615   }
5616
5617   {
5618     static GstValueTable gst_value = {
5619       0,
5620       gst_value_compare_array,
5621       gst_value_serialize_array,
5622       gst_value_deserialize_array,
5623     };
5624
5625     gst_value.type = gst_value_array_get_type ();
5626     gst_value_register (&gst_value);
5627   }
5628
5629   {
5630 #if 0
5631     static const GTypeValueTable value_table = {
5632       gst_value_init_buffer,
5633       NULL,
5634       gst_value_copy_buffer,
5635       NULL,
5636       "i",
5637       NULL,                     /*gst_value_collect_buffer, */
5638       "p",
5639       NULL                      /*gst_value_lcopy_buffer */
5640     };
5641 #endif
5642     static GstValueTable gst_value = {
5643       0,
5644       gst_value_compare_buffer,
5645       gst_value_serialize_buffer,
5646       gst_value_deserialize_buffer,
5647     };
5648
5649     gst_value.type = GST_TYPE_BUFFER;
5650     gst_value_register (&gst_value);
5651   }
5652   {
5653     static GstValueTable gst_value = {
5654       0,
5655       gst_value_compare_fraction,
5656       gst_value_serialize_fraction,
5657       gst_value_deserialize_fraction,
5658     };
5659
5660     gst_value.type = gst_fraction_get_type ();
5661     gst_value_register (&gst_value);
5662   }
5663   {
5664     static GstValueTable gst_value = {
5665       0,
5666       NULL,
5667       gst_value_serialize_caps,
5668       gst_value_deserialize_caps,
5669     };
5670
5671     gst_value.type = GST_TYPE_CAPS;
5672     gst_value_register (&gst_value);
5673   }
5674   {
5675     static GstValueTable gst_value = {
5676       0,
5677       NULL,
5678       gst_value_serialize_structure,
5679       gst_value_deserialize_structure,
5680     };
5681
5682     gst_value.type = GST_TYPE_STRUCTURE;
5683     gst_value_register (&gst_value);
5684   }
5685   {
5686     static GstValueTable gst_value = {
5687       0,
5688       gst_value_compare_date,
5689       gst_value_serialize_date,
5690       gst_value_deserialize_date,
5691     };
5692
5693     gst_value.type = G_TYPE_DATE;
5694     gst_value_register (&gst_value);
5695   }
5696   {
5697     static GstValueTable gst_value = {
5698       0,
5699       gst_value_compare_date_time,
5700       gst_value_serialize_date_time,
5701       gst_value_deserialize_date_time,
5702     };
5703
5704     gst_value.type = gst_date_time_get_type ();
5705     gst_value_register (&gst_value);
5706   }
5707
5708   {
5709     static GstValueTable gst_value = {
5710       0,
5711       gst_value_compare_bitmask,
5712       gst_value_serialize_bitmask,
5713       gst_value_deserialize_bitmask,
5714     };
5715
5716     gst_value.type = gst_bitmask_get_type ();
5717     gst_value_register (&gst_value);
5718   }
5719
5720   REGISTER_SERIALIZATION (G_TYPE_DOUBLE, double);
5721   REGISTER_SERIALIZATION (G_TYPE_FLOAT, float);
5722
5723   REGISTER_SERIALIZATION (G_TYPE_STRING, string);
5724   REGISTER_SERIALIZATION (G_TYPE_BOOLEAN, boolean);
5725   REGISTER_SERIALIZATION (G_TYPE_ENUM, enum);
5726
5727   REGISTER_SERIALIZATION (G_TYPE_FLAGS, flags);
5728
5729   REGISTER_SERIALIZATION (G_TYPE_INT, int);
5730
5731   REGISTER_SERIALIZATION (G_TYPE_INT64, int64);
5732   REGISTER_SERIALIZATION (G_TYPE_LONG, long);
5733
5734   REGISTER_SERIALIZATION (G_TYPE_UINT, uint);
5735   REGISTER_SERIALIZATION (G_TYPE_UINT64, uint64);
5736   REGISTER_SERIALIZATION (G_TYPE_ULONG, ulong);
5737
5738   REGISTER_SERIALIZATION (G_TYPE_UCHAR, uchar);
5739
5740   g_value_register_transform_func (GST_TYPE_INT_RANGE, G_TYPE_STRING,
5741       gst_value_transform_int_range_string);
5742   g_value_register_transform_func (GST_TYPE_INT64_RANGE, G_TYPE_STRING,
5743       gst_value_transform_int64_range_string);
5744   g_value_register_transform_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_STRING,
5745       gst_value_transform_double_range_string);
5746   g_value_register_transform_func (GST_TYPE_FRACTION_RANGE, G_TYPE_STRING,
5747       gst_value_transform_fraction_range_string);
5748   g_value_register_transform_func (GST_TYPE_LIST, G_TYPE_STRING,
5749       gst_value_transform_list_string);
5750   g_value_register_transform_func (GST_TYPE_ARRAY, G_TYPE_STRING,
5751       gst_value_transform_array_string);
5752   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_STRING,
5753       gst_value_transform_fraction_string);
5754   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_FRACTION,
5755       gst_value_transform_string_fraction);
5756   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_DOUBLE,
5757       gst_value_transform_fraction_double);
5758   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_FLOAT,
5759       gst_value_transform_fraction_float);
5760   g_value_register_transform_func (G_TYPE_DOUBLE, GST_TYPE_FRACTION,
5761       gst_value_transform_double_fraction);
5762   g_value_register_transform_func (G_TYPE_FLOAT, GST_TYPE_FRACTION,
5763       gst_value_transform_float_fraction);
5764   g_value_register_transform_func (G_TYPE_DATE, G_TYPE_STRING,
5765       gst_value_transform_date_string);
5766   g_value_register_transform_func (G_TYPE_STRING, G_TYPE_DATE,
5767       gst_value_transform_string_date);
5768   g_value_register_transform_func (GST_TYPE_OBJECT, G_TYPE_STRING,
5769       gst_value_transform_object_string);
5770   g_value_register_transform_func (GST_TYPE_BITMASK, G_TYPE_UINT64,
5771       gst_value_transform_bitmask_uint64);
5772   g_value_register_transform_func (GST_TYPE_BITMASK, G_TYPE_STRING,
5773       gst_value_transform_bitmask_string);
5774   g_value_register_transform_func (G_TYPE_UINT64, GST_TYPE_BITMASK,
5775       gst_value_transform_uint64_bitmask);
5776   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_BITMASK,
5777       gst_value_transform_string_bitmask);
5778
5779   gst_value_register_intersect_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
5780       gst_value_intersect_int_int_range);
5781   gst_value_register_intersect_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
5782       gst_value_intersect_int_range_int_range);
5783   gst_value_register_intersect_func (G_TYPE_INT64, GST_TYPE_INT64_RANGE,
5784       gst_value_intersect_int64_int64_range);
5785   gst_value_register_intersect_func (GST_TYPE_INT64_RANGE, GST_TYPE_INT64_RANGE,
5786       gst_value_intersect_int64_range_int64_range);
5787   gst_value_register_intersect_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
5788       gst_value_intersect_double_double_range);
5789   gst_value_register_intersect_func (GST_TYPE_DOUBLE_RANGE,
5790       GST_TYPE_DOUBLE_RANGE, gst_value_intersect_double_range_double_range);
5791   gst_value_register_intersect_func (GST_TYPE_ARRAY,
5792       GST_TYPE_ARRAY, gst_value_intersect_array);
5793   gst_value_register_intersect_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
5794       gst_value_intersect_fraction_fraction_range);
5795   gst_value_register_intersect_func (GST_TYPE_FRACTION_RANGE,
5796       GST_TYPE_FRACTION_RANGE,
5797       gst_value_intersect_fraction_range_fraction_range);
5798   gst_value_register_intersect_func (GST_TYPE_BITMASK,
5799       GST_TYPE_BITMASK, gst_value_intersect_bitmask_bitmask);
5800
5801   gst_value_register_subtract_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
5802       gst_value_subtract_int_int_range);
5803   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, G_TYPE_INT,
5804       gst_value_subtract_int_range_int);
5805   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
5806       gst_value_subtract_int_range_int_range);
5807   gst_value_register_subtract_func (G_TYPE_INT64, GST_TYPE_INT64_RANGE,
5808       gst_value_subtract_int64_int64_range);
5809   gst_value_register_subtract_func (GST_TYPE_INT64_RANGE, G_TYPE_INT64,
5810       gst_value_subtract_int64_range_int64);
5811   gst_value_register_subtract_func (GST_TYPE_INT64_RANGE, GST_TYPE_INT64_RANGE,
5812       gst_value_subtract_int64_range_int64_range);
5813   gst_value_register_subtract_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
5814       gst_value_subtract_double_double_range);
5815   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_DOUBLE,
5816       gst_value_subtract_double_range_double);
5817   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE,
5818       GST_TYPE_DOUBLE_RANGE, gst_value_subtract_double_range_double_range);
5819   gst_value_register_subtract_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
5820       gst_value_subtract_fraction_fraction_range);
5821   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE, GST_TYPE_FRACTION,
5822       gst_value_subtract_fraction_range_fraction);
5823   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE,
5824       GST_TYPE_FRACTION_RANGE,
5825       gst_value_subtract_fraction_range_fraction_range);
5826   gst_value_register_subtract_func (GST_TYPE_BITMASK,
5827       GST_TYPE_BITMASK, gst_value_subtract_bitmask_bitmask);
5828
5829   /* see bug #317246, #64994, #65041 */
5830   {
5831     volatile GType date_type = G_TYPE_DATE;
5832
5833     g_type_name (date_type);
5834   }
5835
5836   gst_value_register_union_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
5837       gst_value_union_int_int_range);
5838   gst_value_register_union_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
5839       gst_value_union_int_range_int_range);
5840   gst_value_register_union_func (GST_TYPE_BITMASK,
5841       GST_TYPE_BITMASK, gst_value_union_bitmask_bitmask);
5842
5843 #if 0
5844   /* Implement these if needed */
5845   gst_value_register_union_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
5846       gst_value_union_fraction_fraction_range);
5847   gst_value_register_union_func (GST_TYPE_FRACTION_RANGE,
5848       GST_TYPE_FRACTION_RANGE, gst_value_union_fraction_range_fraction_range);
5849 #endif
5850 }