gst/gstvalue.c: Remove unused and uninitialised type variables that were still export...
[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 and GParamSpec implementations specific
23  * to GStreamer
24  *
25  * GValue and GParamSpec implementations specific to GStreamer.
26  *
27  * Note that operations on the same GstValue (or GValue) from multiple
28  * threads may lead to undefined behaviour. 
29  *
30  * Last reviewed on 2006-03-07 (0.10.4)
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36 #include <math.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <ctype.h>
40
41 #include "gst_private.h"
42 #include "glib-compat-private.h"
43 #include <gst/gst.h>
44 #include <gobject/gvaluecollector.h>
45
46 typedef struct _GstValueUnionInfo GstValueUnionInfo;
47 struct _GstValueUnionInfo
48 {
49   GType type1;
50   GType type2;
51   GstValueUnionFunc func;
52 };
53
54 typedef struct _GstValueIntersectInfo GstValueIntersectInfo;
55 struct _GstValueIntersectInfo
56 {
57   GType type1;
58   GType type2;
59   GstValueIntersectFunc func;
60 };
61
62 typedef struct _GstValueSubtractInfo GstValueSubtractInfo;
63 struct _GstValueSubtractInfo
64 {
65   GType minuend;
66   GType subtrahend;
67   GstValueSubtractFunc func;
68 };
69
70 static GArray *gst_value_table;
71 static GArray *gst_value_union_funcs;
72 static GArray *gst_value_intersect_funcs;
73 static GArray *gst_value_subtract_funcs;
74
75 /* Forward declarations */
76 static gint gst_greatest_common_divisor (gint a, gint b);
77 static gchar *gst_value_serialize_fraction (const GValue * value);
78
79 static GstValueCompareFunc gst_value_get_compare_func (const GValue * value1);
80 static gint gst_value_compare_with_func (const GValue * value1,
81     const GValue * value2, GstValueCompareFunc compare);
82
83 /********
84  * list *
85  ********/
86
87 /* two helper functions to serialize/stringify any type of list
88  * regular lists are done with { }, arrays with < >
89  */
90 static gchar *
91 gst_value_serialize_any_list (const GValue * value, const gchar * begin,
92     const gchar * end)
93 {
94   guint i;
95   GArray *array = value->data[0].v_pointer;
96   GString *s;
97   GValue *v;
98   gchar *s_val;
99
100   s = g_string_new (begin);
101   for (i = 0; i < array->len; i++) {
102     v = &g_array_index (array, GValue, i);
103     s_val = gst_value_serialize (v);
104     g_string_append (s, s_val);
105     g_free (s_val);
106     if (i < array->len - 1) {
107       g_string_append (s, ", ");
108     }
109   }
110   g_string_append (s, end);
111   return g_string_free (s, FALSE);
112 }
113
114 static void
115 gst_value_transform_any_list_string (const GValue * src_value,
116     GValue * dest_value, const gchar * begin, const gchar * end)
117 {
118   GValue *list_value;
119   GArray *array;
120   GString *s;
121   guint i;
122   gchar *list_s;
123
124   array = src_value->data[0].v_pointer;
125
126   s = g_string_new (begin);
127   for (i = 0; i < array->len; i++) {
128     list_value = &g_array_index (array, GValue, i);
129
130     if (i != 0) {
131       g_string_append (s, ", ");
132     }
133     list_s = g_strdup_value_contents (list_value);
134     g_string_append (s, list_s);
135     g_free (list_s);
136   }
137   g_string_append (s, end);
138
139   dest_value->data[0].v_pointer = g_string_free (s, FALSE);
140 }
141
142 /*
143  * helper function to see if a type is fixed. Is used internally here and
144  * there. Do not export, since it doesn't work for types where the content
145  * decides the fixedness (e.g. GST_TYPE_ARRAY).
146  */
147
148 static gboolean
149 gst_type_is_fixed (GType type)
150 {
151   if (type == GST_TYPE_INT_RANGE || type == GST_TYPE_DOUBLE_RANGE ||
152       type == GST_TYPE_LIST) {
153     return FALSE;
154   }
155   if (G_TYPE_FUNDAMENTAL (type) <=
156       G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
157     return TRUE;
158   }
159   if (type == GST_TYPE_BUFFER || type == GST_TYPE_FOURCC
160       || type == GST_TYPE_ARRAY || type == GST_TYPE_FRACTION) {
161     return TRUE;
162   }
163
164   return FALSE;
165 }
166
167 /* GValue functions usable for both regular lists and arrays */
168 static void
169 gst_value_init_list_or_array (GValue * value)
170 {
171   value->data[0].v_pointer = g_array_new (FALSE, TRUE, sizeof (GValue));
172 }
173
174 static GArray *
175 copy_garray_of_gstvalue (const GArray * src)
176 {
177   GArray *dest;
178   guint i;
179
180   dest = g_array_sized_new (FALSE, TRUE, sizeof (GValue), src->len);
181   g_array_set_size (dest, src->len);
182   for (i = 0; i < src->len; i++) {
183     gst_value_init_and_copy (&g_array_index (dest, GValue, i),
184         &g_array_index (src, GValue, i));
185   }
186
187   return dest;
188 }
189
190 static void
191 gst_value_copy_list_or_array (const GValue * src_value, GValue * dest_value)
192 {
193   dest_value->data[0].v_pointer =
194       copy_garray_of_gstvalue ((GArray *) src_value->data[0].v_pointer);
195 }
196
197 static void
198 gst_value_free_list_or_array (GValue * value)
199 {
200   guint i;
201   GArray *src = (GArray *) value->data[0].v_pointer;
202
203   if ((value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS) == 0) {
204     for (i = 0; i < src->len; i++) {
205       g_value_unset (&g_array_index (src, GValue, i));
206     }
207     g_array_free (src, TRUE);
208   }
209 }
210
211 static gpointer
212 gst_value_list_or_array_peek_pointer (const GValue * value)
213 {
214   return value->data[0].v_pointer;
215 }
216
217 static gchar *
218 gst_value_collect_list_or_array (GValue * value, guint n_collect_values,
219     GTypeCValue * collect_values, guint collect_flags)
220 {
221   if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
222     value->data[0].v_pointer = collect_values[0].v_pointer;
223     value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
224   } else {
225     value->data[0].v_pointer =
226         copy_garray_of_gstvalue ((GArray *) collect_values[0].v_pointer);
227   }
228   return NULL;
229 }
230
231 static gchar *
232 gst_value_lcopy_list_or_array (const GValue * value, guint n_collect_values,
233     GTypeCValue * collect_values, guint collect_flags)
234 {
235   GArray **dest = collect_values[0].v_pointer;
236
237   if (!dest)
238     return g_strdup_printf ("value location for `%s' passed as NULL",
239         G_VALUE_TYPE_NAME (value));
240   if (!value->data[0].v_pointer)
241     return g_strdup_printf ("invalid value given for `%s'",
242         G_VALUE_TYPE_NAME (value));
243   if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
244     *dest = (GArray *) value->data[0].v_pointer;
245   } else {
246     *dest = copy_garray_of_gstvalue ((GArray *) value->data[0].v_pointer);
247   }
248   return NULL;
249 }
250
251 /**
252  * gst_value_list_append_value:
253  * @value: a #GValue of type #GST_TYPE_LIST
254  * @append_value: the value to append
255  *
256  * Appends @append_value to the GstValueList in @value.
257  */
258 void
259 gst_value_list_append_value (GValue * value, const GValue * append_value)
260 {
261   GValue val = { 0, };
262
263   g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
264
265   gst_value_init_and_copy (&val, append_value);
266   g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1);
267 }
268
269 /**
270  * gst_value_list_prepend_value:
271  * @value: a #GValue of type #GST_TYPE_LIST
272  * @prepend_value: the value to prepend
273  *
274  * Prepends @prepend_value to the GstValueList in @value.
275  */
276 void
277 gst_value_list_prepend_value (GValue * value, const GValue * prepend_value)
278 {
279   GValue val = { 0, };
280
281   g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
282
283   gst_value_init_and_copy (&val, prepend_value);
284   g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1);
285 }
286
287 /**
288  * gst_value_list_concat:
289  * @dest: an uninitialized #GValue to take the result
290  * @value1: a #GValue
291  * @value2: a #GValue
292  *
293  * Concatenates copies of @value1 and @value2 into a list.  Values that are not
294  * of type #GST_TYPE_LIST are treated as if they were lists of length 1.
295  * @dest will be initialized to the type #GST_TYPE_LIST.
296  */
297 void
298 gst_value_list_concat (GValue * dest, const GValue * value1,
299     const GValue * value2)
300 {
301   guint i, value1_length, value2_length;
302   GArray *array;
303
304   g_return_if_fail (dest != NULL);
305   g_return_if_fail (G_VALUE_TYPE (dest) == 0);
306   g_return_if_fail (G_IS_VALUE (value1));
307   g_return_if_fail (G_IS_VALUE (value2));
308
309   value1_length =
310       (GST_VALUE_HOLDS_LIST (value1) ? gst_value_list_get_size (value1) : 1);
311   value2_length =
312       (GST_VALUE_HOLDS_LIST (value2) ? gst_value_list_get_size (value2) : 1);
313   g_value_init (dest, GST_TYPE_LIST);
314   array = (GArray *) dest->data[0].v_pointer;
315   g_array_set_size (array, value1_length + value2_length);
316
317   if (GST_VALUE_HOLDS_LIST (value1)) {
318     for (i = 0; i < value1_length; i++) {
319       gst_value_init_and_copy (&g_array_index (array, GValue, i),
320           gst_value_list_get_value (value1, i));
321     }
322   } else {
323     gst_value_init_and_copy (&g_array_index (array, GValue, 0), value1);
324   }
325
326   if (GST_VALUE_HOLDS_LIST (value2)) {
327     for (i = 0; i < value2_length; i++) {
328       gst_value_init_and_copy (&g_array_index (array, GValue,
329               i + value1_length), gst_value_list_get_value (value2, i));
330     }
331   } else {
332     gst_value_init_and_copy (&g_array_index (array, GValue, value1_length),
333         value2);
334   }
335 }
336
337 /**
338  * gst_value_list_get_size:
339  * @value: a #GValue of type #GST_TYPE_LIST
340  *
341  * Gets the number of values contained in @value.
342  *
343  * Returns: the number of values
344  */
345 guint
346 gst_value_list_get_size (const GValue * value)
347 {
348   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), 0);
349
350   return ((GArray *) value->data[0].v_pointer)->len;
351 }
352
353 /**
354  * gst_value_list_get_value:
355  * @value: a #GValue of type #GST_TYPE_LIST
356  * @index: index of value to get from the list
357  *
358  * Gets the value that is a member of the list contained in @value and
359  * has the index @index.
360  *
361  * Returns: the value at the given index
362  */
363 const GValue *
364 gst_value_list_get_value (const GValue * value, guint index)
365 {
366   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), NULL);
367   g_return_val_if_fail (index < gst_value_list_get_size (value), NULL);
368
369   return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer,
370       GValue, index);
371 }
372
373 /**
374  * gst_value_array_append_value:
375  * @value: a #GValue of type #GST_TYPE_ARRAY
376  * @append_value: the value to append
377  *
378  * Appends @append_value to the GstValueArray in @value.
379  */
380 void
381 gst_value_array_append_value (GValue * value, const GValue * append_value)
382 {
383   GValue val = { 0, };
384
385   g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value));
386
387   gst_value_init_and_copy (&val, append_value);
388   g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1);
389 }
390
391 /**
392  * gst_value_array_prepend_value:
393  * @value: a #GValue of type #GST_TYPE_ARRAY
394  * @prepend_value: the value to prepend
395  *
396  * Prepends @prepend_value to the GstValueArray in @value.
397  */
398 void
399 gst_value_array_prepend_value (GValue * value, const GValue * prepend_value)
400 {
401   GValue val = { 0, };
402
403   g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value));
404
405   gst_value_init_and_copy (&val, prepend_value);
406   g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1);
407 }
408
409 /**
410  * gst_value_array_get_size:
411  * @value: a #GValue of type #GST_TYPE_ARRAY
412  *
413  * Gets the number of values contained in @value.
414  *
415  * Returns: the number of values
416  */
417 guint
418 gst_value_array_get_size (const GValue * value)
419 {
420   g_return_val_if_fail (GST_VALUE_HOLDS_ARRAY (value), 0);
421
422   return ((GArray *) value->data[0].v_pointer)->len;
423 }
424
425 /**
426  * gst_value_array_get_value:
427  * @value: a #GValue of type #GST_TYPE_ARRAY
428  * @index: index of value to get from the array
429  *
430  * Gets the value that is a member of the array contained in @value and
431  * has the index @index.
432  *
433  * Returns: the value at the given index
434  */
435 const GValue *
436 gst_value_array_get_value (const GValue * value, guint index)
437 {
438   g_return_val_if_fail (GST_VALUE_HOLDS_ARRAY (value), NULL);
439   g_return_val_if_fail (index < gst_value_array_get_size (value), NULL);
440
441   return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer,
442       GValue, index);
443 }
444
445 static void
446 gst_value_transform_list_string (const GValue * src_value, GValue * dest_value)
447 {
448   gst_value_transform_any_list_string (src_value, dest_value, "{ ", " }");
449 }
450
451 static void
452 gst_value_transform_array_string (const GValue * src_value, GValue * dest_value)
453 {
454   gst_value_transform_any_list_string (src_value, dest_value, "< ", " >");
455 }
456
457 /* Do an unordered compare of the contents of a list */
458 static int
459 gst_value_compare_list (const GValue * value1, const GValue * value2)
460 {
461   guint i, j;
462   GArray *array1 = value1->data[0].v_pointer;
463   GArray *array2 = value2->data[0].v_pointer;
464   GValue *v1;
465   GValue *v2;
466   gint len, to_remove;
467   guint8 *removed;
468   GstValueCompareFunc compare;
469
470   /* get length and do initial length check. */
471   len = array1->len;
472   if (len != array2->len)
473     return GST_VALUE_UNORDERED;
474
475   /* place to mark removed value indices of array2 */
476   removed = g_newa (guint8, len);
477   memset (removed, 0, len);
478   to_remove = len;
479
480   /* loop over array1, all items should be in array2. When we find an
481    * item in array2, remove it from array2 by marking it as removed */
482   for (i = 0; i < len; i++) {
483     v1 = &g_array_index (array1, GValue, i);
484     if ((compare = gst_value_get_compare_func (v1))) {
485       for (j = 0; j < len; j++) {
486         /* item is removed, we can skip it */
487         if (removed[j])
488           continue;
489         v2 = &g_array_index (array2, GValue, j);
490         if (gst_value_compare_with_func (v1, v2, compare) == GST_VALUE_EQUAL) {
491           /* mark item as removed now that we found it in array2 and 
492            * decrement the number of remaining items in array2. */
493           removed[j] = 1;
494           to_remove--;
495           break;
496         }
497       }
498       /* item in array1 and not in array2, UNORDERED */
499       if (j == len)
500         return GST_VALUE_UNORDERED;
501     } else
502       return GST_VALUE_UNORDERED;
503   }
504   /* if not all items were removed, array2 contained something not in array1 */
505   if (to_remove != 0)
506     return GST_VALUE_UNORDERED;
507
508   /* arrays are equal */
509   return GST_VALUE_EQUAL;
510 }
511
512 /* Perform an ordered comparison of the contents of an array */
513 static int
514 gst_value_compare_array (const GValue * value1, const GValue * value2)
515 {
516   guint i;
517   GArray *array1 = value1->data[0].v_pointer;
518   GArray *array2 = value2->data[0].v_pointer;
519   GValue *v1;
520   GValue *v2;
521
522   if (array1->len != array2->len)
523     return GST_VALUE_UNORDERED;
524
525   for (i = 0; i < array1->len; i++) {
526     v1 = &g_array_index (array1, GValue, i);
527     v2 = &g_array_index (array2, GValue, i);
528     if (gst_value_compare (v1, v2) != GST_VALUE_EQUAL)
529       return GST_VALUE_UNORDERED;
530   }
531
532   return GST_VALUE_EQUAL;
533 }
534
535 static gchar *
536 gst_value_serialize_list (const GValue * value)
537 {
538   return gst_value_serialize_any_list (value, "{ ", " }");
539 }
540
541 static gboolean
542 gst_value_deserialize_list (GValue * dest, const gchar * s)
543 {
544   g_warning ("gst_value_deserialize_list: unimplemented");
545   return FALSE;
546 }
547
548 static gchar *
549 gst_value_serialize_array (const GValue * value)
550 {
551   return gst_value_serialize_any_list (value, "< ", " >");
552 }
553
554 static gboolean
555 gst_value_deserialize_array (GValue * dest, const gchar * s)
556 {
557   g_warning ("gst_value_deserialize_array: unimplemented");
558   return FALSE;
559 }
560
561 /**********
562  * fourcc *
563  **********/
564
565 static void
566 gst_value_init_fourcc (GValue * value)
567 {
568   value->data[0].v_int = 0;
569 }
570
571 static void
572 gst_value_copy_fourcc (const GValue * src_value, GValue * dest_value)
573 {
574   dest_value->data[0].v_int = src_value->data[0].v_int;
575 }
576
577 static gchar *
578 gst_value_collect_fourcc (GValue * value, guint n_collect_values,
579     GTypeCValue * collect_values, guint collect_flags)
580 {
581   value->data[0].v_int = collect_values[0].v_int;
582
583   return NULL;
584 }
585
586 static gchar *
587 gst_value_lcopy_fourcc (const GValue * value, guint n_collect_values,
588     GTypeCValue * collect_values, guint collect_flags)
589 {
590   guint32 *fourcc_p = collect_values[0].v_pointer;
591
592   if (!fourcc_p)
593     return g_strdup_printf ("value location for `%s' passed as NULL",
594         G_VALUE_TYPE_NAME (value));
595
596   *fourcc_p = value->data[0].v_int;
597
598   return NULL;
599 }
600
601 /**
602  * gst_value_set_fourcc:
603  * @value: a GValue initialized to #GST_TYPE_FOURCC
604  * @fourcc: the #guint32 fourcc to set
605  *
606  * Sets @value to @fourcc.
607  */
608 void
609 gst_value_set_fourcc (GValue * value, guint32 fourcc)
610 {
611   g_return_if_fail (GST_VALUE_HOLDS_FOURCC (value));
612
613   value->data[0].v_int = fourcc;
614 }
615
616 /**
617  * gst_value_get_fourcc:
618  * @value: a GValue initialized to #GST_TYPE_FOURCC
619  *
620  * Gets the #guint32 fourcc contained in @value.
621  *
622  * Returns: the #guint32 fourcc contained in @value.
623  */
624 guint32
625 gst_value_get_fourcc (const GValue * value)
626 {
627   g_return_val_if_fail (GST_VALUE_HOLDS_FOURCC (value), 0);
628
629   return value->data[0].v_int;
630 }
631
632 static void
633 gst_value_transform_fourcc_string (const GValue * src_value,
634     GValue * dest_value)
635 {
636   guint32 fourcc = src_value->data[0].v_int;
637
638   if (g_ascii_isprint ((fourcc >> 0) & 0xff) &&
639       g_ascii_isprint ((fourcc >> 8) & 0xff) &&
640       g_ascii_isprint ((fourcc >> 16) & 0xff) &&
641       g_ascii_isprint ((fourcc >> 24) & 0xff)) {
642     dest_value->data[0].v_pointer =
643         g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
644   } else {
645     dest_value->data[0].v_pointer = g_strdup_printf ("0x%08x", fourcc);
646   }
647 }
648
649 static gint
650 gst_value_compare_fourcc (const GValue * value1, const GValue * value2)
651 {
652   if (value2->data[0].v_int == value1->data[0].v_int)
653     return GST_VALUE_EQUAL;
654   return GST_VALUE_UNORDERED;
655 }
656
657 static gchar *
658 gst_value_serialize_fourcc (const GValue * value)
659 {
660   guint32 fourcc = value->data[0].v_int;
661
662   if (g_ascii_isalnum ((fourcc >> 0) & 0xff) &&
663       g_ascii_isalnum ((fourcc >> 8) & 0xff) &&
664       g_ascii_isalnum ((fourcc >> 16) & 0xff) &&
665       g_ascii_isalnum ((fourcc >> 24) & 0xff)) {
666     return g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
667   } else {
668     return g_strdup_printf ("0x%08x", fourcc);
669   }
670 }
671
672 static gboolean
673 gst_value_deserialize_fourcc (GValue * dest, const char *s)
674 {
675   gboolean ret = FALSE;
676   guint32 fourcc = 0;
677   char *end;
678
679   if (strlen (s) == 4) {
680     fourcc = GST_MAKE_FOURCC (s[0], s[1], s[2], s[3]);
681     ret = TRUE;
682   } else if (g_ascii_isdigit (*s)) {
683     fourcc = strtoul (s, &end, 0);
684     if (*end == 0) {
685       ret = TRUE;
686     }
687   }
688   gst_value_set_fourcc (dest, fourcc);
689
690   return ret;
691 }
692
693 /*************
694  * int range *
695  *************/
696
697 static void
698 gst_value_init_int_range (GValue * value)
699 {
700   value->data[0].v_int = 0;
701   value->data[1].v_int = 0;
702 }
703
704 static void
705 gst_value_copy_int_range (const GValue * src_value, GValue * dest_value)
706 {
707   dest_value->data[0].v_int = src_value->data[0].v_int;
708   dest_value->data[1].v_int = src_value->data[1].v_int;
709 }
710
711 static gchar *
712 gst_value_collect_int_range (GValue * value, guint n_collect_values,
713     GTypeCValue * collect_values, guint collect_flags)
714 {
715   value->data[0].v_int = collect_values[0].v_int;
716   value->data[1].v_int = collect_values[1].v_int;
717
718   return NULL;
719 }
720
721 static gchar *
722 gst_value_lcopy_int_range (const GValue * value, guint n_collect_values,
723     GTypeCValue * collect_values, guint collect_flags)
724 {
725   guint32 *int_range_start = collect_values[0].v_pointer;
726   guint32 *int_range_end = collect_values[1].v_pointer;
727
728   if (!int_range_start)
729     return g_strdup_printf ("start value location for `%s' passed as NULL",
730         G_VALUE_TYPE_NAME (value));
731   if (!int_range_end)
732     return g_strdup_printf ("end value location for `%s' passed as NULL",
733         G_VALUE_TYPE_NAME (value));
734
735   *int_range_start = value->data[0].v_int;
736   *int_range_end = value->data[1].v_int;
737
738   return NULL;
739 }
740
741 /**
742  * gst_value_set_int_range:
743  * @value: a GValue initialized to GST_TYPE_INT_RANGE
744  * @start: the start of the range
745  * @end: the end of the range
746  *
747  * Sets @value to the range specified by @start and @end.
748  */
749 void
750 gst_value_set_int_range (GValue * value, gint start, gint end)
751 {
752   g_return_if_fail (GST_VALUE_HOLDS_INT_RANGE (value));
753   g_return_if_fail (start < end);
754
755   value->data[0].v_int = start;
756   value->data[1].v_int = end;
757 }
758
759 /**
760  * gst_value_get_int_range_min:
761  * @value: a GValue initialized to GST_TYPE_INT_RANGE
762  *
763  * Gets the minimum of the range specified by @value.
764  *
765  * Returns: the minimum of the range
766  */
767 gint
768 gst_value_get_int_range_min (const GValue * value)
769 {
770   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
771
772   return value->data[0].v_int;
773 }
774
775 /**
776  * gst_value_get_int_range_max:
777  * @value: a GValue initialized to GST_TYPE_INT_RANGE
778  *
779  * Gets the maximum of the range specified by @value.
780  *
781  * Returns: the maxumum of the range
782  */
783 gint
784 gst_value_get_int_range_max (const GValue * value)
785 {
786   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
787
788   return value->data[1].v_int;
789 }
790
791 static void
792 gst_value_transform_int_range_string (const GValue * src_value,
793     GValue * dest_value)
794 {
795   dest_value->data[0].v_pointer = g_strdup_printf ("[%d,%d]",
796       (int) src_value->data[0].v_int, (int) src_value->data[1].v_int);
797 }
798
799 static gint
800 gst_value_compare_int_range (const GValue * value1, const GValue * value2)
801 {
802   if (value2->data[0].v_int == value1->data[0].v_int &&
803       value2->data[1].v_int == value1->data[1].v_int)
804     return GST_VALUE_EQUAL;
805   return GST_VALUE_UNORDERED;
806 }
807
808 static gchar *
809 gst_value_serialize_int_range (const GValue * value)
810 {
811   return g_strdup_printf ("[ %d, %d ]", value->data[0].v_int,
812       value->data[1].v_int);
813 }
814
815 static gboolean
816 gst_value_deserialize_int_range (GValue * dest, const gchar * s)
817 {
818   g_warning ("unimplemented");
819   return FALSE;
820 }
821
822 /****************
823  * double range *
824  ****************/
825
826 static void
827 gst_value_init_double_range (GValue * value)
828 {
829   value->data[0].v_double = 0;
830   value->data[1].v_double = 0;
831 }
832
833 static void
834 gst_value_copy_double_range (const GValue * src_value, GValue * dest_value)
835 {
836   dest_value->data[0].v_double = src_value->data[0].v_double;
837   dest_value->data[1].v_double = src_value->data[1].v_double;
838 }
839
840 static gchar *
841 gst_value_collect_double_range (GValue * value, guint n_collect_values,
842     GTypeCValue * collect_values, guint collect_flags)
843 {
844   value->data[0].v_double = collect_values[0].v_double;
845   value->data[1].v_double = collect_values[1].v_double;
846
847   return NULL;
848 }
849
850 static gchar *
851 gst_value_lcopy_double_range (const GValue * value, guint n_collect_values,
852     GTypeCValue * collect_values, guint collect_flags)
853 {
854   gdouble *double_range_start = collect_values[0].v_pointer;
855   gdouble *double_range_end = collect_values[1].v_pointer;
856
857   if (!double_range_start)
858     return g_strdup_printf ("start value location for `%s' passed as NULL",
859         G_VALUE_TYPE_NAME (value));
860   if (!double_range_end)
861     return g_strdup_printf ("end value location for `%s' passed as NULL",
862         G_VALUE_TYPE_NAME (value));
863
864   *double_range_start = value->data[0].v_double;
865   *double_range_end = value->data[1].v_double;
866
867   return NULL;
868 }
869
870 /**
871  * gst_value_set_double_range:
872  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
873  * @start: the start of the range
874  * @end: the end of the range
875  *
876  * Sets @value to the range specified by @start and @end.
877  */
878 void
879 gst_value_set_double_range (GValue * value, gdouble start, gdouble end)
880 {
881   g_return_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value));
882
883   value->data[0].v_double = start;
884   value->data[1].v_double = end;
885 }
886
887 /**
888  * gst_value_get_double_range_min:
889  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
890  *
891  * Gets the minimum of the range specified by @value.
892  *
893  * Returns: the minumum of the range
894  */
895 gdouble
896 gst_value_get_double_range_min (const GValue * value)
897 {
898   g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
899
900   return value->data[0].v_double;
901 }
902
903 /**
904  * gst_value_get_double_range_max:
905  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
906  *
907  * Gets the maximum of the range specified by @value.
908  *
909  * Returns: the maxumum of the range
910  */
911 gdouble
912 gst_value_get_double_range_max (const GValue * value)
913 {
914   g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
915
916   return value->data[1].v_double;
917 }
918
919 static void
920 gst_value_transform_double_range_string (const GValue * src_value,
921     GValue * dest_value)
922 {
923   char s1[G_ASCII_DTOSTR_BUF_SIZE], s2[G_ASCII_DTOSTR_BUF_SIZE];
924
925   dest_value->data[0].v_pointer = g_strdup_printf ("[%s,%s]",
926       g_ascii_dtostr (s1, G_ASCII_DTOSTR_BUF_SIZE,
927           src_value->data[0].v_double),
928       g_ascii_dtostr (s2, G_ASCII_DTOSTR_BUF_SIZE,
929           src_value->data[1].v_double));
930 }
931
932 static gint
933 gst_value_compare_double_range (const GValue * value1, const GValue * value2)
934 {
935   if (value2->data[0].v_double == value1->data[0].v_double &&
936       value2->data[0].v_double == value1->data[0].v_double)
937     return GST_VALUE_EQUAL;
938   return GST_VALUE_UNORDERED;
939 }
940
941 static gchar *
942 gst_value_serialize_double_range (const GValue * value)
943 {
944   char d1[G_ASCII_DTOSTR_BUF_SIZE];
945   char d2[G_ASCII_DTOSTR_BUF_SIZE];
946
947   g_ascii_dtostr (d1, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
948   g_ascii_dtostr (d2, G_ASCII_DTOSTR_BUF_SIZE, value->data[1].v_double);
949   return g_strdup_printf ("[ %s, %s ]", d1, d2);
950 }
951
952 static gboolean
953 gst_value_deserialize_double_range (GValue * dest, const gchar * s)
954 {
955   g_warning ("unimplemented");
956   return FALSE;
957 }
958
959 /****************
960  * fraction range *
961  ****************/
962
963 static void
964 gst_value_init_fraction_range (GValue * value)
965 {
966   GValue *vals;
967
968   value->data[0].v_pointer = vals = g_new0 (GValue, 2);
969   g_value_init (&vals[0], GST_TYPE_FRACTION);
970   g_value_init (&vals[1], GST_TYPE_FRACTION);
971 }
972
973 static void
974 gst_value_free_fraction_range (GValue * value)
975 {
976   GValue *vals = (GValue *) value->data[0].v_pointer;
977
978   if (vals != NULL) {
979     g_value_unset (&vals[0]);
980     g_value_unset (&vals[1]);
981     g_free (vals);
982     value->data[0].v_pointer = NULL;
983   }
984 }
985
986 static void
987 gst_value_copy_fraction_range (const GValue * src_value, GValue * dest_value)
988 {
989   GValue *vals = (GValue *) dest_value->data[0].v_pointer;
990   GValue *src_vals = (GValue *) src_value->data[0].v_pointer;
991
992   if (vals == NULL) {
993     dest_value->data[0].v_pointer = vals = g_new0 (GValue, 2);
994     g_return_if_fail (vals != NULL);
995     g_value_init (&vals[0], GST_TYPE_FRACTION);
996     g_value_init (&vals[1], GST_TYPE_FRACTION);
997   }
998
999   if (src_vals != NULL) {
1000     g_value_copy (&src_vals[0], &vals[0]);
1001     g_value_copy (&src_vals[1], &vals[1]);
1002   }
1003 }
1004
1005 static gchar *
1006 gst_value_collect_fraction_range (GValue * value, guint n_collect_values,
1007     GTypeCValue * collect_values, guint collect_flags)
1008 {
1009   GValue *vals = (GValue *) value->data[0].v_pointer;
1010
1011   if (n_collect_values != 4)
1012     return g_strdup_printf ("not enough value locations for `%s' passed",
1013         G_VALUE_TYPE_NAME (value));
1014   if (vals == NULL) {
1015     value->data[0].v_pointer = vals = g_new0 (GValue, 2);
1016     if (vals == NULL)
1017       return g_strdup_printf ("Could not initialise`%s' during collect",
1018           G_VALUE_TYPE_NAME (value));
1019     g_value_init (&vals[0], GST_TYPE_FRACTION);
1020     g_value_init (&vals[1], GST_TYPE_FRACTION);
1021   }
1022
1023   gst_value_set_fraction (&vals[0], collect_values[0].v_int,
1024       collect_values[1].v_int);
1025   gst_value_set_fraction (&vals[1], collect_values[2].v_int,
1026       collect_values[3].v_int);
1027
1028   return NULL;
1029 }
1030
1031 static gchar *
1032 gst_value_lcopy_fraction_range (const GValue * value, guint n_collect_values,
1033     GTypeCValue * collect_values, guint collect_flags)
1034 {
1035   int i;
1036   int *dest_values[4];
1037   GValue *vals = (GValue *) value->data[0].v_pointer;
1038
1039   if (n_collect_values != 4)
1040     return g_strdup_printf ("not enough value locations for `%s' passed",
1041         G_VALUE_TYPE_NAME (value));
1042
1043   for (i = 0; i < 4; i++) {
1044     if (collect_values[i].v_pointer == NULL) {
1045       return g_strdup_printf ("value location for `%s' passed as NULL",
1046           G_VALUE_TYPE_NAME (value));
1047     }
1048     dest_values[i] = collect_values[i].v_pointer;
1049   }
1050
1051   if (vals == NULL) {
1052     return g_strdup_printf ("Uninitialised `%s' passed",
1053         G_VALUE_TYPE_NAME (value));
1054   }
1055
1056   dest_values[0][0] = gst_value_get_fraction_numerator (&vals[0]);
1057   dest_values[1][0] = gst_value_get_fraction_denominator (&vals[0]);
1058   dest_values[2][0] = gst_value_get_fraction_denominator (&vals[1]);
1059   dest_values[3][0] = gst_value_get_fraction_denominator (&vals[1]);
1060   return NULL;
1061 }
1062
1063 /**
1064  * gst_value_set_fraction_range:
1065  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1066  * @start: the start of the range (a GST_TYPE_FRACTION GValue)
1067  * @end: the end of the range (a GST_TYPE_FRACTION GValue)
1068  *
1069  * Sets @value to the range specified by @start and @end.
1070  */
1071 void
1072 gst_value_set_fraction_range (GValue * value, const GValue * start,
1073     const GValue * end)
1074 {
1075   GValue *vals;
1076
1077   g_return_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value));
1078
1079   vals = (GValue *) value->data[0].v_pointer;
1080   if (vals == NULL) {
1081     value->data[0].v_pointer = vals = g_new0 (GValue, 2);
1082     g_value_init (&vals[0], GST_TYPE_FRACTION);
1083     g_value_init (&vals[1], GST_TYPE_FRACTION);
1084   }
1085
1086   g_value_copy (start, &vals[0]);
1087   g_value_copy (end, &vals[1]);
1088 }
1089
1090 /**
1091  * gst_value_set_fraction_range_full:
1092  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1093  * @numerator_start: the numerator start of the range
1094  * @denominator_start: the denominator start of the range
1095  * @numerator_end: the numerator end of the range
1096  * @denominator_end: the denominator end of the range
1097  *
1098  * Sets @value to the range specified by @numerator_start/@denominator_start
1099  * and @numerator_end/@denominator_end.
1100  */
1101 void
1102 gst_value_set_fraction_range_full (GValue * value,
1103     gint numerator_start, gint denominator_start,
1104     gint numerator_end, gint denominator_end)
1105 {
1106   GValue start = { 0 };
1107   GValue end = { 0 };
1108
1109   g_value_init (&start, GST_TYPE_FRACTION);
1110   g_value_init (&end, GST_TYPE_FRACTION);
1111
1112   gst_value_set_fraction (&start, numerator_start, denominator_start);
1113   gst_value_set_fraction (&end, numerator_end, denominator_end);
1114   gst_value_set_fraction_range (value, &start, &end);
1115
1116   g_value_unset (&start);
1117   g_value_unset (&end);
1118 }
1119
1120 /**
1121  * gst_value_get_fraction_range_min:
1122  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1123  *
1124  * Gets the minimum of the range specified by @value.
1125  *
1126  * Returns: the minumum of the range
1127  */
1128 const GValue *
1129 gst_value_get_fraction_range_min (const GValue * value)
1130 {
1131   GValue *vals;
1132
1133   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value), FALSE);
1134
1135   vals = (GValue *) value->data[0].v_pointer;
1136   if (vals != NULL) {
1137     return &vals[0];
1138   }
1139
1140   return NULL;
1141 }
1142
1143 /**
1144  * gst_value_get_fraction_range_max:
1145  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1146  *
1147  * Gets the maximum of the range specified by @value.
1148  *
1149  * Returns: the maximum of the range
1150  */
1151 const GValue *
1152 gst_value_get_fraction_range_max (const GValue * value)
1153 {
1154   GValue *vals;
1155
1156   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value), FALSE);
1157
1158   vals = (GValue *) value->data[0].v_pointer;
1159   if (vals != NULL) {
1160     return &vals[1];
1161   }
1162
1163   return NULL;
1164 }
1165
1166 static char *
1167 gst_value_serialize_fraction_range (const GValue * value)
1168 {
1169   GValue *vals = (GValue *) value->data[0].v_pointer;
1170   gchar *retval;
1171
1172   if (vals == NULL) {
1173     retval = g_strdup ("[ 0/1, 0/1 ]");
1174   } else {
1175     gchar *start, *end;
1176
1177     start = gst_value_serialize_fraction (&vals[0]);
1178     end = gst_value_serialize_fraction (&vals[1]);
1179
1180     retval = g_strdup_printf ("[ %s, %s ]", start, end);
1181     g_free (start);
1182     g_free (end);
1183   }
1184
1185   return retval;
1186 }
1187
1188 static void
1189 gst_value_transform_fraction_range_string (const GValue * src_value,
1190     GValue * dest_value)
1191 {
1192   dest_value->data[0].v_pointer =
1193       gst_value_serialize_fraction_range (src_value);
1194 }
1195
1196 static gint
1197 gst_value_compare_fraction_range (const GValue * value1, const GValue * value2)
1198 {
1199   GValue *vals1, *vals2;
1200   GstValueCompareFunc compare;
1201
1202   if (value2->data[0].v_pointer == value1->data[0].v_pointer)
1203     return GST_VALUE_EQUAL;     /* Only possible if both are NULL */
1204
1205   if (value2->data[0].v_pointer == NULL || value1->data[0].v_pointer == NULL)
1206     return GST_VALUE_UNORDERED;
1207
1208   vals1 = (GValue *) value1->data[0].v_pointer;
1209   vals2 = (GValue *) value2->data[0].v_pointer;
1210   if ((compare = gst_value_get_compare_func (&vals1[0]))) {
1211     if (gst_value_compare_with_func (&vals1[0], &vals2[0], compare) ==
1212         GST_VALUE_EQUAL &&
1213         gst_value_compare_with_func (&vals1[1], &vals2[1], compare) ==
1214         GST_VALUE_EQUAL)
1215       return GST_VALUE_EQUAL;
1216   }
1217   return GST_VALUE_UNORDERED;
1218 }
1219
1220 static gboolean
1221 gst_value_deserialize_fraction_range (GValue * dest, const gchar * s)
1222 {
1223   g_warning ("unimplemented");
1224   return FALSE;
1225 }
1226
1227 /***********
1228  * GstCaps *
1229  ***********/
1230
1231 /**
1232  * gst_value_set_caps:
1233  * @value: a GValue initialized to GST_TYPE_CAPS
1234  * @caps: the caps to set the value to
1235  *
1236  * Sets the contents of @value to @caps.  The actual
1237  * #GstCaps structure is copied before it is used.
1238  */
1239 void
1240 gst_value_set_caps (GValue * value, const GstCaps * caps)
1241 {
1242   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS);
1243
1244   g_value_set_boxed (value, caps);
1245 }
1246
1247 /**
1248  * gst_value_get_caps:
1249  * @value: a GValue initialized to GST_TYPE_CAPS
1250  *
1251  * Gets the contents of @value.
1252  *
1253  * Returns: the contents of @value
1254  */
1255 const GstCaps *
1256 gst_value_get_caps (const GValue * value)
1257 {
1258   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS, NULL);
1259
1260   return (GstCaps *) g_value_get_boxed (value);
1261 }
1262
1263 static char *
1264 gst_value_serialize_caps (const GValue * value)
1265 {
1266   GstCaps *caps = g_value_get_boxed (value);
1267
1268   return gst_caps_to_string (caps);
1269 }
1270
1271 static gboolean
1272 gst_value_deserialize_caps (GValue * dest, const gchar * s)
1273 {
1274   GstCaps *caps;
1275
1276   caps = gst_caps_from_string (s);
1277
1278   if (caps) {
1279     g_value_set_boxed (dest, caps);
1280     return TRUE;
1281   }
1282   return FALSE;
1283 }
1284
1285 /****************
1286  * GstStructure *
1287  ****************/
1288
1289 /**
1290  * gst_value_set_structure:
1291  * @value: a GValue initialized to GST_TYPE_STRUCTURE
1292  * @structure: the structure to set the value to
1293  *
1294  * Sets the contents of @value to @structure.  The actual
1295  */
1296 void
1297 gst_value_set_structure (GValue * value, const GstStructure * structure)
1298 {
1299   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE);
1300
1301   g_value_set_boxed (value, structure);
1302 }
1303
1304 /**
1305  * gst_value_get_structure:
1306  * @value: a GValue initialized to GST_TYPE_STRUCTURE
1307  *
1308  * Gets the contents of @value.
1309  *
1310  * Returns: the contents of @value
1311  */
1312 const GstStructure *
1313 gst_value_get_structure (const GValue * value)
1314 {
1315   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE, NULL);
1316
1317   return (GstStructure *) g_value_get_boxed (value);
1318 }
1319
1320 static char *
1321 gst_value_serialize_structure (const GValue * value)
1322 {
1323   GstStructure *structure = g_value_get_boxed (value);
1324
1325   return gst_structure_to_string (structure);
1326 }
1327
1328 static gboolean
1329 gst_value_deserialize_structure (GValue * dest, const gchar * s)
1330 {
1331   GstStructure *structure;
1332
1333   structure = gst_structure_from_string (s, NULL);
1334
1335   if (structure) {
1336     g_value_set_boxed (dest, structure);
1337     return TRUE;
1338   }
1339   return FALSE;
1340 }
1341
1342 /*************
1343  * GstBuffer *
1344  *************/
1345
1346 static int
1347 gst_value_compare_buffer (const GValue * value1, const GValue * value2)
1348 {
1349   GstBuffer *buf1 = GST_BUFFER (gst_value_get_mini_object (value1));
1350   GstBuffer *buf2 = GST_BUFFER (gst_value_get_mini_object (value2));
1351
1352   if (GST_BUFFER_SIZE (buf1) != GST_BUFFER_SIZE (buf2))
1353     return GST_VALUE_UNORDERED;
1354   if (GST_BUFFER_SIZE (buf1) == 0)
1355     return GST_VALUE_EQUAL;
1356   g_assert (GST_BUFFER_DATA (buf1));
1357   g_assert (GST_BUFFER_DATA (buf2));
1358   if (memcmp (GST_BUFFER_DATA (buf1), GST_BUFFER_DATA (buf2),
1359           GST_BUFFER_SIZE (buf1)) == 0)
1360     return GST_VALUE_EQUAL;
1361
1362   return GST_VALUE_UNORDERED;
1363 }
1364
1365 static char *
1366 gst_value_serialize_buffer (const GValue * value)
1367 {
1368   guint8 *data;
1369   int i;
1370   int size;
1371   char *string;
1372   GstBuffer *buffer;
1373
1374   buffer = gst_value_get_buffer (value);
1375   if (buffer == NULL)
1376     return NULL;
1377
1378   data = GST_BUFFER_DATA (buffer);
1379   size = GST_BUFFER_SIZE (buffer);
1380
1381   string = g_malloc (size * 2 + 1);
1382   for (i = 0; i < size; i++) {
1383     sprintf (string + i * 2, "%02x", data[i]);
1384   }
1385   string[size * 2] = 0;
1386
1387   return string;
1388 }
1389
1390 static gboolean
1391 gst_value_deserialize_buffer (GValue * dest, const gchar * s)
1392 {
1393   GstBuffer *buffer;
1394   int len;
1395   char ts[3];
1396   guint8 *data;
1397   int i;
1398
1399   len = strlen (s);
1400   if (len & 1)
1401     goto wrong_length;
1402
1403   buffer = gst_buffer_new_and_alloc (len / 2);
1404   data = GST_BUFFER_DATA (buffer);
1405   for (i = 0; i < len / 2; i++) {
1406     if (!isxdigit ((int) s[i * 2]) || !isxdigit ((int) s[i * 2 + 1]))
1407       goto wrong_char;
1408
1409     ts[0] = s[i * 2 + 0];
1410     ts[1] = s[i * 2 + 1];
1411     ts[2] = 0;
1412
1413     data[i] = (guint8) strtoul (ts, NULL, 16);
1414   }
1415
1416   gst_value_take_buffer (dest, buffer);
1417
1418   return TRUE;
1419
1420   /* ERRORS */
1421 wrong_length:
1422   {
1423     return FALSE;
1424   }
1425 wrong_char:
1426   {
1427     gst_buffer_unref (buffer);
1428     return FALSE;
1429   }
1430 }
1431
1432
1433 /***********
1434  * boolean *
1435  ***********/
1436
1437 static int
1438 gst_value_compare_boolean (const GValue * value1, const GValue * value2)
1439 {
1440   if ((value1->data[0].v_int != 0) == (value2->data[0].v_int != 0))
1441     return GST_VALUE_EQUAL;
1442   return GST_VALUE_UNORDERED;
1443 }
1444
1445 static char *
1446 gst_value_serialize_boolean (const GValue * value)
1447 {
1448   if (value->data[0].v_int) {
1449     return g_strdup ("true");
1450   }
1451   return g_strdup ("false");
1452 }
1453
1454 static gboolean
1455 gst_value_deserialize_boolean (GValue * dest, const gchar * s)
1456 {
1457   gboolean ret = FALSE;
1458
1459   if (g_ascii_strcasecmp (s, "true") == 0 ||
1460       g_ascii_strcasecmp (s, "yes") == 0 ||
1461       g_ascii_strcasecmp (s, "t") == 0 || strcmp (s, "1") == 0) {
1462     g_value_set_boolean (dest, TRUE);
1463     ret = TRUE;
1464   } else if (g_ascii_strcasecmp (s, "false") == 0 ||
1465       g_ascii_strcasecmp (s, "no") == 0 ||
1466       g_ascii_strcasecmp (s, "f") == 0 || strcmp (s, "0") == 0) {
1467     g_value_set_boolean (dest, FALSE);
1468     ret = TRUE;
1469   }
1470
1471   return ret;
1472 }
1473
1474 #define CREATE_SERIALIZATION_START(_type,_macro)                        \
1475 static gint                                                             \
1476 gst_value_compare_ ## _type                                             \
1477 (const GValue * value1, const GValue * value2)                          \
1478 {                                                                       \
1479   g ## _type val1 = g_value_get_ ## _type (value1);                     \
1480   g ## _type val2 = g_value_get_ ## _type (value2);                     \
1481   if (val1 > val2)                                                      \
1482     return GST_VALUE_GREATER_THAN;                                      \
1483   if (val1 < val2)                                                      \
1484     return GST_VALUE_LESS_THAN;                                         \
1485   return GST_VALUE_EQUAL;                                               \
1486 }                                                                       \
1487                                                                         \
1488 static char *                                                           \
1489 gst_value_serialize_ ## _type (const GValue * value)                    \
1490 {                                                                       \
1491   GValue val = { 0, };                                                  \
1492   g_value_init (&val, G_TYPE_STRING);                                   \
1493   if (!g_value_transform (value, &val))                                 \
1494     g_assert_not_reached ();                                            \
1495   /* NO_COPY_MADNESS!!! */                                              \
1496   return (char *) g_value_get_string (&val);                            \
1497 }
1498
1499 /* deserialize the given s into to as a gint64.
1500  * check if the result is actually storeable in the given size number of
1501  * bytes.
1502  */
1503 static gboolean
1504 gst_value_deserialize_int_helper (gint64 * to, const gchar * s,
1505     gint64 min, gint64 max, gint size)
1506 {
1507   gboolean ret = FALSE;
1508   char *end;
1509   gint64 mask = -1;
1510
1511   errno = 0;
1512   *to = g_ascii_strtoull (s, &end, 0);
1513   /* a range error is a definitive no-no */
1514   if (errno == ERANGE) {
1515     return FALSE;
1516   }
1517
1518   if (*end == 0) {
1519     ret = TRUE;
1520   } else {
1521     if (g_ascii_strcasecmp (s, "little_endian") == 0) {
1522       *to = G_LITTLE_ENDIAN;
1523       ret = TRUE;
1524     } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {
1525       *to = G_BIG_ENDIAN;
1526       ret = TRUE;
1527     } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {
1528       *to = G_BYTE_ORDER;
1529       ret = TRUE;
1530     } else if (g_ascii_strcasecmp (s, "min") == 0) {
1531       *to = min;
1532       ret = TRUE;
1533     } else if (g_ascii_strcasecmp (s, "max") == 0) {
1534       *to = max;
1535       ret = TRUE;
1536     }
1537   }
1538   if (ret) {
1539     /* by definition, a gint64 fits into a gint64; so ignore those */
1540     if (size != sizeof (mask)) {
1541       if (*to >= 0) {
1542         /* for positive numbers, we create a mask of 1's outside of the range
1543          * and 0's inside the range.  An and will thus keep only 1 bits
1544          * outside of the range */
1545         mask <<= (size * 8);
1546         if ((mask & *to) != 0) {
1547           ret = FALSE;
1548         }
1549       } else {
1550         /* for negative numbers, we do a 2's complement version */
1551         mask <<= ((size * 8) - 1);
1552         if ((mask & *to) != mask) {
1553           ret = FALSE;
1554         }
1555       }
1556     }
1557   }
1558   return ret;
1559 }
1560
1561 #define CREATE_SERIALIZATION(_type,_macro)                              \
1562 CREATE_SERIALIZATION_START(_type,_macro)                                \
1563                                                                         \
1564 static gboolean                                                         \
1565 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s)         \
1566 {                                                                       \
1567   gint64 x;                                                             \
1568                                                                         \
1569   if (gst_value_deserialize_int_helper (&x, s, G_MIN ## _macro,         \
1570       G_MAX ## _macro, sizeof (g ## _type))) {                          \
1571     g_value_set_ ## _type (dest, /*(g ## _type)*/ x);                   \
1572     return TRUE;                                                        \
1573   } else {                                                              \
1574     return FALSE;                                                       \
1575   }                                                                     \
1576 }
1577
1578 #define CREATE_USERIALIZATION(_type,_macro)                             \
1579 CREATE_SERIALIZATION_START(_type,_macro)                                \
1580                                                                         \
1581 static gboolean                                                         \
1582 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s)         \
1583 {                                                                       \
1584   gint64 x;                                                             \
1585   char *end;                                                            \
1586   gboolean ret = FALSE;                                                 \
1587                                                                         \
1588   errno = 0;                                                            \
1589   x = g_ascii_strtoull (s, &end, 0);                                    \
1590   /* a range error is a definitive no-no */                             \
1591   if (errno == ERANGE) {                                                \
1592     return FALSE;                                                       \
1593   }                                                                     \
1594   /* the cast ensures the range check later on makes sense */           \
1595   x = (g ## _type) x;                                                   \
1596   if (*end == 0) {                                                      \
1597     ret = TRUE;                                                         \
1598   } else {                                                              \
1599     if (g_ascii_strcasecmp (s, "little_endian") == 0) {                 \
1600       x = G_LITTLE_ENDIAN;                                              \
1601       ret = TRUE;                                                       \
1602     } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {             \
1603       x = G_BIG_ENDIAN;                                                 \
1604       ret = TRUE;                                                       \
1605     } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {             \
1606       x = G_BYTE_ORDER;                                                 \
1607       ret = TRUE;                                                       \
1608     } else if (g_ascii_strcasecmp (s, "min") == 0) {                    \
1609       x = 0;                                                            \
1610       ret = TRUE;                                                       \
1611     } else if (g_ascii_strcasecmp (s, "max") == 0) {                    \
1612       x = G_MAX ## _macro;                                              \
1613       ret = TRUE;                                                       \
1614     }                                                                   \
1615   }                                                                     \
1616   if (ret) {                                                            \
1617     if (x > G_MAX ## _macro) {                                          \
1618       ret = FALSE;                                                      \
1619     } else {                                                            \
1620       g_value_set_ ## _type (dest, x);                                  \
1621     }                                                                   \
1622   }                                                                     \
1623   return ret;                                                           \
1624 }
1625
1626 #define REGISTER_SERIALIZATION(_gtype, _type)                           \
1627 G_STMT_START {                                                          \
1628   static const GstValueTable gst_value = {                              \
1629     _gtype,                                                             \
1630     gst_value_compare_ ## _type,                                        \
1631     gst_value_serialize_ ## _type,                                      \
1632     gst_value_deserialize_ ## _type,                                    \
1633   };                                                                    \
1634                                                                         \
1635   gst_value_register (&gst_value);                                      \
1636 } G_STMT_END
1637
1638 CREATE_SERIALIZATION (int, INT);
1639 CREATE_SERIALIZATION (int64, INT64);
1640 CREATE_SERIALIZATION (long, LONG);
1641
1642 CREATE_USERIALIZATION (uint, UINT);
1643 CREATE_USERIALIZATION (uint64, UINT64);
1644 CREATE_USERIALIZATION (ulong, ULONG);
1645
1646 /**********
1647  * double *
1648  **********/
1649 static int
1650 gst_value_compare_double (const GValue * value1, const GValue * value2)
1651 {
1652   if (value1->data[0].v_double > value2->data[0].v_double)
1653     return GST_VALUE_GREATER_THAN;
1654   if (value1->data[0].v_double < value2->data[0].v_double)
1655     return GST_VALUE_LESS_THAN;
1656   if (value1->data[0].v_double == value2->data[0].v_double)
1657     return GST_VALUE_EQUAL;
1658   return GST_VALUE_UNORDERED;
1659 }
1660
1661 static char *
1662 gst_value_serialize_double (const GValue * value)
1663 {
1664   char d[G_ASCII_DTOSTR_BUF_SIZE];
1665
1666   g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
1667   return g_strdup (d);
1668 }
1669
1670 static gboolean
1671 gst_value_deserialize_double (GValue * dest, const gchar * s)
1672 {
1673   double x;
1674   gboolean ret = FALSE;
1675   char *end;
1676
1677   x = g_ascii_strtod (s, &end);
1678   if (*end == 0) {
1679     ret = TRUE;
1680   } else {
1681     if (g_ascii_strcasecmp (s, "min") == 0) {
1682       x = -G_MAXDOUBLE;
1683       ret = TRUE;
1684     } else if (g_ascii_strcasecmp (s, "max") == 0) {
1685       x = G_MAXDOUBLE;
1686       ret = TRUE;
1687     }
1688   }
1689   if (ret) {
1690     g_value_set_double (dest, x);
1691   }
1692   return ret;
1693 }
1694
1695 /*********
1696  * float *
1697  *********/
1698
1699 static gint
1700 gst_value_compare_float (const GValue * value1, const GValue * value2)
1701 {
1702   if (value1->data[0].v_float > value2->data[0].v_float)
1703     return GST_VALUE_GREATER_THAN;
1704   if (value1->data[0].v_float < value2->data[0].v_float)
1705     return GST_VALUE_LESS_THAN;
1706   if (value1->data[0].v_float == value2->data[0].v_float)
1707     return GST_VALUE_EQUAL;
1708   return GST_VALUE_UNORDERED;
1709 }
1710
1711 static gchar *
1712 gst_value_serialize_float (const GValue * value)
1713 {
1714   gchar d[G_ASCII_DTOSTR_BUF_SIZE];
1715
1716   g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_float);
1717   return g_strdup (d);
1718 }
1719
1720 static gboolean
1721 gst_value_deserialize_float (GValue * dest, const gchar * s)
1722 {
1723   double x;
1724   gboolean ret = FALSE;
1725   char *end;
1726
1727   x = g_ascii_strtod (s, &end);
1728   if (*end == 0) {
1729     ret = TRUE;
1730   } else {
1731     if (g_ascii_strcasecmp (s, "min") == 0) {
1732       x = -G_MAXFLOAT;
1733       ret = TRUE;
1734     } else if (g_ascii_strcasecmp (s, "max") == 0) {
1735       x = G_MAXFLOAT;
1736       ret = TRUE;
1737     }
1738   }
1739   if (x > G_MAXFLOAT || x < -G_MAXFLOAT)
1740     ret = FALSE;
1741   if (ret) {
1742     g_value_set_float (dest, (float) x);
1743   }
1744   return ret;
1745 }
1746
1747 /**********
1748  * string *
1749  **********/
1750
1751 static gint
1752 gst_value_compare_string (const GValue * value1, const GValue * value2)
1753 {
1754   int x = strcmp (value1->data[0].v_pointer, value2->data[0].v_pointer);
1755
1756   if (x < 0)
1757     return GST_VALUE_LESS_THAN;
1758   if (x > 0)
1759     return GST_VALUE_GREATER_THAN;
1760   return GST_VALUE_EQUAL;
1761 }
1762
1763 /* keep in sync with gststructure.c */
1764 #define GST_ASCII_IS_STRING(c) (g_ascii_isalnum((c)) || ((c) == '_') || \
1765     ((c) == '-') || ((c) == '+') || ((c) == '/') || ((c) == ':') || \
1766     ((c) == '.'))
1767
1768 static gchar *
1769 gst_string_wrap (const gchar * s)
1770 {
1771   const gchar *t;
1772   int len;
1773   gchar *d, *e;
1774   gboolean wrap = FALSE;
1775
1776   len = 0;
1777   t = s;
1778   if (!s)
1779     return NULL;
1780   while (*t) {
1781     if (GST_ASCII_IS_STRING (*t)) {
1782       len++;
1783     } else if (*t < 0x20 || *t >= 0x7f) {
1784       wrap = TRUE;
1785       len += 4;
1786     } else {
1787       wrap = TRUE;
1788       len += 2;
1789     }
1790     t++;
1791   }
1792
1793   if (!wrap)
1794     return g_strdup (s);
1795
1796   e = d = g_malloc (len + 3);
1797
1798   *e++ = '\"';
1799   t = s;
1800   while (*t) {
1801     if (GST_ASCII_IS_STRING (*t)) {
1802       *e++ = *t++;
1803     } else if (*t < 0x20 || *t >= 0x7f) {
1804       *e++ = '\\';
1805       *e++ = '0' + ((*(guchar *) t) >> 6);
1806       *e++ = '0' + (((*t) >> 3) & 0x7);
1807       *e++ = '0' + ((*t++) & 0x7);
1808     } else {
1809       *e++ = '\\';
1810       *e++ = *t++;
1811     }
1812   }
1813   *e++ = '\"';
1814   *e = 0;
1815
1816   return d;
1817 }
1818
1819 /*
1820  * This function takes a string delimited with double quotes (")
1821  * and unescapes any \xxx octal numbers.
1822  *
1823  * If sequences of \y are found where y is not in the range of
1824  * 0->3, y is copied unescaped.
1825  *
1826  * If \xyy is found where x is an octal number but y is not, an
1827  * error is encountered and NULL is returned.
1828  *
1829  * the input string must be \0 terminated.
1830  */
1831 static gchar *
1832 gst_string_unwrap (const gchar * s)
1833 {
1834   gchar *ret;
1835   gchar *read, *write;
1836
1837   /* NULL string returns NULL */
1838   if (s == NULL)
1839     return NULL;
1840
1841   /* strings not starting with " are invalid */
1842   if (*s != '"')
1843     return NULL;
1844
1845   /* make copy of original string to hold the result. This
1846    * string will always be smaller than the original */
1847   ret = g_strdup (s);
1848   read = ret;
1849   write = ret;
1850
1851   /* need to move to the next position as we parsed the " */
1852   read++;
1853
1854   while (*read) {
1855     if (GST_ASCII_IS_STRING (*read)) {
1856       /* normal chars are just copied */
1857       *write++ = *read++;
1858     } else if (*read == '"') {
1859       /* quote marks end of string */
1860       break;
1861     } else if (*read == '\\') {
1862       /* got an escape char, move to next position to read a tripplet
1863        * of octal numbers */
1864       read++;
1865       /* is the next char a possible first octal number? */
1866       if (*read >= '0' && *read <= '3') {
1867         /* parse other 2 numbers, if one of them is not in the range of
1868          * an octal number, we error. We also catch the case where a zero
1869          * byte is found here. */
1870         if (read[1] < '0' || read[1] > '7' || read[2] < '0' || read[2] > '7')
1871           goto beach;
1872
1873         /* now convert the octal number to a byte again. */
1874         *write++ = ((read[0] - '0') << 6) +
1875             ((read[1] - '0') << 3) + (read[2] - '0');
1876
1877         read += 3;
1878       } else {
1879         /* if we run into a \0 here, we definately won't get a quote later */
1880         if (*read == 0)
1881           goto beach;
1882
1883         /* else copy \X sequence */
1884         *write++ = *read++;
1885       }
1886     } else {
1887       /* weird character, error */
1888       goto beach;
1889     }
1890   }
1891   /* if the string is not ending in " and zero terminated, we error */
1892   if (*read != '"' || read[1] != '\0')
1893     goto beach;
1894
1895   /* null terminate result string and return */
1896   *write++ = '\0';
1897   return ret;
1898
1899 beach:
1900   g_free (ret);
1901   return NULL;
1902 }
1903
1904 static gchar *
1905 gst_value_serialize_string (const GValue * value)
1906 {
1907   return gst_string_wrap (value->data[0].v_pointer);
1908 }
1909
1910 static gboolean
1911 gst_value_deserialize_string (GValue * dest, const gchar * s)
1912 {
1913   if (*s != '"') {
1914     if (!g_utf8_validate (s, -1, NULL))
1915       return FALSE;
1916     g_value_set_string (dest, s);
1917     return TRUE;
1918   } else {
1919     gchar *str = gst_string_unwrap (s);
1920
1921     if (!str)
1922       return FALSE;
1923     g_value_take_string (dest, str);
1924   }
1925
1926   return TRUE;
1927 }
1928
1929 /********
1930  * enum *
1931  ********/
1932
1933 static gint
1934 gst_value_compare_enum (const GValue * value1, const GValue * value2)
1935 {
1936   GEnumValue *en1, *en2;
1937   GEnumClass *klass1 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value1));
1938   GEnumClass *klass2 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value2));
1939
1940   g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
1941   g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
1942   en1 = g_enum_get_value (klass1, g_value_get_enum (value1));
1943   en2 = g_enum_get_value (klass2, g_value_get_enum (value2));
1944   g_type_class_unref (klass1);
1945   g_type_class_unref (klass2);
1946   g_return_val_if_fail (en1, GST_VALUE_UNORDERED);
1947   g_return_val_if_fail (en2, GST_VALUE_UNORDERED);
1948   if (en1->value < en2->value)
1949     return GST_VALUE_LESS_THAN;
1950   if (en1->value > en2->value)
1951     return GST_VALUE_GREATER_THAN;
1952
1953   return GST_VALUE_EQUAL;
1954 }
1955
1956 static gchar *
1957 gst_value_serialize_enum (const GValue * value)
1958 {
1959   GEnumValue *en;
1960   GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value));
1961
1962   g_return_val_if_fail (klass, NULL);
1963   en = g_enum_get_value (klass, g_value_get_enum (value));
1964   g_type_class_unref (klass);
1965
1966   /* might be one of the custom formats registered later */
1967   if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (value) == GST_TYPE_FORMAT)) {
1968     const GstFormatDefinition *format_def;
1969
1970     format_def = gst_format_get_details (g_value_get_enum (value));
1971     g_return_val_if_fail (format_def != NULL, NULL);
1972     return g_strdup (format_def->description);
1973   }
1974
1975   g_return_val_if_fail (en, NULL);
1976   return g_strdup (en->value_name);
1977 }
1978
1979 static gint
1980 gst_value_deserialize_enum_iter_cmp (const GstFormatDefinition * format_def,
1981     const gchar * s)
1982 {
1983   if (g_ascii_strcasecmp (s, format_def->nick) == 0)
1984     return 0;
1985
1986   return g_ascii_strcasecmp (s, format_def->description);
1987 }
1988
1989 static gboolean
1990 gst_value_deserialize_enum (GValue * dest, const gchar * s)
1991 {
1992   GEnumValue *en;
1993   gchar *endptr = NULL;
1994   GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (dest));
1995
1996   g_return_val_if_fail (klass, FALSE);
1997   if (!(en = g_enum_get_value_by_name (klass, s))) {
1998     if (!(en = g_enum_get_value_by_nick (klass, s))) {
1999       gint i = strtol (s, &endptr, 0);
2000
2001       if (endptr && *endptr == '\0') {
2002         en = g_enum_get_value (klass, i);
2003       }
2004     }
2005   }
2006   g_type_class_unref (klass);
2007
2008   /* might be one of the custom formats registered later */
2009   if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (dest) == GST_TYPE_FORMAT)) {
2010     const GstFormatDefinition *format_def;
2011     GstIterator *iter;
2012
2013     iter = gst_format_iterate_definitions ();
2014
2015     format_def = gst_iterator_find_custom (iter,
2016         (GCompareFunc) gst_value_deserialize_enum_iter_cmp, (gpointer) s);
2017
2018     g_return_val_if_fail (format_def != NULL, FALSE);
2019     g_value_set_enum (dest, (gint) format_def->value);
2020     gst_iterator_free (iter);
2021     return TRUE;
2022   }
2023
2024   g_return_val_if_fail (en, FALSE);
2025   g_value_set_enum (dest, en->value);
2026   return TRUE;
2027 }
2028
2029 /********
2030  * flags *
2031  ********/
2032
2033 /* we just compare the value here */
2034 static gint
2035 gst_value_compare_flags (const GValue * value1, const GValue * value2)
2036 {
2037   guint fl1, fl2;
2038   GFlagsClass *klass1 =
2039       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value1));
2040   GFlagsClass *klass2 =
2041       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value2));
2042
2043   g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
2044   g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
2045   fl1 = g_value_get_flags (value1);
2046   fl2 = g_value_get_flags (value2);
2047   g_type_class_unref (klass1);
2048   g_type_class_unref (klass2);
2049   if (fl1 < fl2)
2050     return GST_VALUE_LESS_THAN;
2051   if (fl1 > fl2)
2052     return GST_VALUE_GREATER_THAN;
2053
2054   return GST_VALUE_EQUAL;
2055 }
2056
2057 /* the different flags are serialized separated with a + */
2058 static gchar *
2059 gst_value_serialize_flags (const GValue * value)
2060 {
2061   guint flags;
2062   GFlagsValue *fl;
2063   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value));
2064   gchar *result, *tmp;
2065   gboolean first = TRUE;
2066
2067   g_return_val_if_fail (klass, NULL);
2068
2069   flags = g_value_get_flags (value);
2070
2071   /* if no flags are set, try to serialize to the _NONE string */
2072   if (!flags) {
2073     fl = g_flags_get_first_value (klass, flags);
2074     return g_strdup (fl->value_name);
2075   }
2076
2077   /* some flags are set, so serialize one by one */
2078   result = g_strdup ("");
2079   while (flags) {
2080     fl = g_flags_get_first_value (klass, flags);
2081     if (fl != NULL) {
2082       tmp = g_strconcat (result, (first ? "" : "+"), fl->value_name, NULL);
2083       g_free (result);
2084       result = tmp;
2085       first = FALSE;
2086
2087       /* clear flag */
2088       flags &= ~fl->value;
2089     }
2090   }
2091   g_type_class_unref (klass);
2092
2093   return result;
2094 }
2095
2096 static gboolean
2097 gst_value_deserialize_flags (GValue * dest, const gchar * s)
2098 {
2099   GFlagsValue *fl;
2100   gchar *endptr = NULL;
2101   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (dest));
2102   gchar **split;
2103   guint flags;
2104   gint i;
2105
2106   g_return_val_if_fail (klass, FALSE);
2107
2108   /* split into parts delimited with + */
2109   split = g_strsplit (s, "+", 0);
2110
2111   flags = 0;
2112   i = 0;
2113   /* loop over each part */
2114   while (split[i]) {
2115     if (!(fl = g_flags_get_value_by_name (klass, split[i]))) {
2116       if (!(fl = g_flags_get_value_by_nick (klass, split[i]))) {
2117         gint val = strtol (split[i], &endptr, 0);
2118
2119         /* just or numeric value */
2120         if (endptr && *endptr == '\0') {
2121           flags |= val;
2122         }
2123       }
2124     }
2125     if (fl) {
2126       flags |= fl->value;
2127     }
2128     i++;
2129   }
2130   g_strfreev (split);
2131   g_type_class_unref (klass);
2132   g_value_set_flags (dest, flags);
2133
2134   return TRUE;
2135 }
2136
2137 /*********
2138  * union *
2139  *********/
2140
2141 static gboolean
2142 gst_value_union_int_int_range (GValue * dest, const GValue * src1,
2143     const GValue * src2)
2144 {
2145   if (src2->data[0].v_int <= src1->data[0].v_int &&
2146       src2->data[1].v_int >= src1->data[0].v_int) {
2147     gst_value_init_and_copy (dest, src2);
2148     return TRUE;
2149   }
2150   return FALSE;
2151 }
2152
2153 static gboolean
2154 gst_value_union_int_range_int_range (GValue * dest, const GValue * src1,
2155     const GValue * src2)
2156 {
2157   gint min;
2158   gint max;
2159
2160   min = MAX (src1->data[0].v_int, src2->data[0].v_int);
2161   max = MIN (src1->data[1].v_int, src2->data[1].v_int);
2162
2163   if (min <= max) {
2164     g_value_init (dest, GST_TYPE_INT_RANGE);
2165     gst_value_set_int_range (dest,
2166         MIN (src1->data[0].v_int, src2->data[0].v_int),
2167         MAX (src1->data[1].v_int, src2->data[1].v_int));
2168     return TRUE;
2169   }
2170
2171   return FALSE;
2172 }
2173
2174 /****************
2175  * intersection *
2176  ****************/
2177
2178 static gboolean
2179 gst_value_intersect_int_int_range (GValue * dest, const GValue * src1,
2180     const GValue * src2)
2181 {
2182   if (src2->data[0].v_int <= src1->data[0].v_int &&
2183       src2->data[1].v_int >= src1->data[0].v_int) {
2184     gst_value_init_and_copy (dest, src1);
2185     return TRUE;
2186   }
2187
2188   return FALSE;
2189 }
2190
2191 static gboolean
2192 gst_value_intersect_int_range_int_range (GValue * dest, const GValue * src1,
2193     const GValue * src2)
2194 {
2195   gint min;
2196   gint max;
2197
2198   min = MAX (src1->data[0].v_int, src2->data[0].v_int);
2199   max = MIN (src1->data[1].v_int, src2->data[1].v_int);
2200
2201   if (min < max) {
2202     g_value_init (dest, GST_TYPE_INT_RANGE);
2203     gst_value_set_int_range (dest, min, max);
2204     return TRUE;
2205   }
2206   if (min == max) {
2207     g_value_init (dest, G_TYPE_INT);
2208     g_value_set_int (dest, min);
2209     return TRUE;
2210   }
2211
2212   return FALSE;
2213 }
2214
2215 static gboolean
2216 gst_value_intersect_double_double_range (GValue * dest, const GValue * src1,
2217     const GValue * src2)
2218 {
2219   if (src2->data[0].v_double <= src1->data[0].v_double &&
2220       src2->data[1].v_double >= src1->data[0].v_double) {
2221     gst_value_init_and_copy (dest, src1);
2222     return TRUE;
2223   }
2224
2225   return FALSE;
2226 }
2227
2228 static gboolean
2229 gst_value_intersect_double_range_double_range (GValue * dest,
2230     const GValue * src1, const GValue * src2)
2231 {
2232   gdouble min;
2233   gdouble max;
2234
2235   min = MAX (src1->data[0].v_double, src2->data[0].v_double);
2236   max = MIN (src1->data[1].v_double, src2->data[1].v_double);
2237
2238   if (min < max) {
2239     g_value_init (dest, GST_TYPE_DOUBLE_RANGE);
2240     gst_value_set_double_range (dest, min, max);
2241     return TRUE;
2242   }
2243   if (min == max) {
2244     g_value_init (dest, G_TYPE_DOUBLE);
2245     g_value_set_int (dest, (int) min);
2246     return TRUE;
2247   }
2248
2249   return FALSE;
2250 }
2251
2252 static gboolean
2253 gst_value_intersect_list (GValue * dest, const GValue * value1,
2254     const GValue * value2)
2255 {
2256   guint i, size;
2257   GValue intersection = { 0, };
2258   gboolean ret = FALSE;
2259
2260   size = gst_value_list_get_size (value1);
2261   for (i = 0; i < size; i++) {
2262     const GValue *cur = gst_value_list_get_value (value1, i);
2263
2264     if (gst_value_intersect (&intersection, cur, value2)) {
2265       /* append value */
2266       if (!ret) {
2267         gst_value_init_and_copy (dest, &intersection);
2268         ret = TRUE;
2269       } else if (GST_VALUE_HOLDS_LIST (dest)) {
2270         gst_value_list_append_value (dest, &intersection);
2271       } else {
2272         GValue temp = { 0, };
2273
2274         gst_value_init_and_copy (&temp, dest);
2275         g_value_unset (dest);
2276         gst_value_list_concat (dest, &temp, &intersection);
2277         g_value_unset (&temp);
2278       }
2279       g_value_unset (&intersection);
2280     }
2281   }
2282
2283   return ret;
2284 }
2285
2286 static gboolean
2287 gst_value_intersect_array (GValue * dest, const GValue * src1,
2288     const GValue * src2)
2289 {
2290   guint size;
2291   guint n;
2292   GValue val = { 0 };
2293
2294   /* only works on similar-sized arrays */
2295   size = gst_value_array_get_size (src1);
2296   if (size != gst_value_array_get_size (src2))
2297     return FALSE;
2298   g_value_init (dest, GST_TYPE_ARRAY);
2299
2300   for (n = 0; n < size; n++) {
2301     if (!gst_value_intersect (&val, gst_value_array_get_value (src1, n),
2302             gst_value_array_get_value (src2, n))) {
2303       g_value_unset (dest);
2304       return FALSE;
2305     }
2306     gst_value_array_append_value (dest, &val);
2307     g_value_unset (&val);
2308   }
2309
2310   return TRUE;
2311 }
2312
2313 static gboolean
2314 gst_value_intersect_fraction_fraction_range (GValue * dest, const GValue * src1,
2315     const GValue * src2)
2316 {
2317   int res1, res2;
2318   GValue *vals;
2319   GstValueCompareFunc compare;
2320
2321   vals = src2->data[0].v_pointer;
2322
2323   if (vals == NULL)
2324     return FALSE;
2325
2326   if ((compare = gst_value_get_compare_func (src1))) {
2327     res1 = gst_value_compare_with_func (&vals[0], src1, compare);
2328     res2 = gst_value_compare_with_func (&vals[1], src1, compare);
2329
2330     if ((res1 == GST_VALUE_EQUAL || res1 == GST_VALUE_LESS_THAN) &&
2331         (res2 == GST_VALUE_EQUAL || res2 == GST_VALUE_GREATER_THAN)) {
2332       gst_value_init_and_copy (dest, src1);
2333       return TRUE;
2334     }
2335   }
2336
2337   return FALSE;
2338 }
2339
2340 static gboolean
2341     gst_value_intersect_fraction_range_fraction_range
2342     (GValue * dest, const GValue * src1, const GValue * src2)
2343 {
2344   GValue *min;
2345   GValue *max;
2346   int res;
2347   GValue *vals1, *vals2;
2348   GstValueCompareFunc compare;
2349
2350   vals1 = src1->data[0].v_pointer;
2351   vals2 = src2->data[0].v_pointer;
2352   g_return_val_if_fail (vals1 != NULL && vals2 != NULL, FALSE);
2353
2354   if ((compare = gst_value_get_compare_func (&vals1[0]))) {
2355     /* min = MAX (src1.start, src2.start) */
2356     res = gst_value_compare_with_func (&vals1[0], &vals2[0], compare);
2357     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
2358     if (res == GST_VALUE_LESS_THAN)
2359       min = &vals2[0];          /* Take the max of the 2 */
2360     else
2361       min = &vals1[0];
2362
2363     /* max = MIN (src1.end, src2.end) */
2364     res = gst_value_compare_with_func (&vals1[1], &vals2[1], compare);
2365     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
2366     if (res == GST_VALUE_GREATER_THAN)
2367       max = &vals2[1];          /* Take the min of the 2 */
2368     else
2369       max = &vals1[1];
2370
2371     res = gst_value_compare_with_func (min, max, compare);
2372     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
2373     if (res == GST_VALUE_LESS_THAN) {
2374       g_value_init (dest, GST_TYPE_FRACTION_RANGE);
2375       vals1 = dest->data[0].v_pointer;
2376       g_value_copy (min, &vals1[0]);
2377       g_value_copy (max, &vals1[1]);
2378       return TRUE;
2379     }
2380     if (res == GST_VALUE_EQUAL) {
2381       gst_value_init_and_copy (dest, min);
2382       return TRUE;
2383     }
2384   }
2385
2386   return FALSE;
2387 }
2388
2389 /***************
2390  * subtraction *
2391  ***************/
2392
2393 static gboolean
2394 gst_value_subtract_int_int_range (GValue * dest, const GValue * minuend,
2395     const GValue * subtrahend)
2396 {
2397   int min = gst_value_get_int_range_min (subtrahend);
2398   int max = gst_value_get_int_range_max (subtrahend);
2399   int val = g_value_get_int (minuend);
2400
2401   /* subtracting a range from an int only works if the int is not in the
2402    * range */
2403   if (val < min || val > max) {
2404     /* and the result is the int */
2405     gst_value_init_and_copy (dest, minuend);
2406     return TRUE;
2407   }
2408   return FALSE;
2409 }
2410
2411 /* creates a new int range based on input values.
2412  */
2413 static gboolean
2414 gst_value_create_new_range (GValue * dest, gint min1, gint max1, gint min2,
2415     gint max2)
2416 {
2417   GValue v1 = { 0, };
2418   GValue v2 = { 0, };
2419   GValue *pv1, *pv2;            /* yeah, hungarian! */
2420
2421   if (min1 <= max1 && min2 <= max2) {
2422     pv1 = &v1;
2423     pv2 = &v2;
2424   } else if (min1 <= max1) {
2425     pv1 = dest;
2426     pv2 = NULL;
2427   } else if (min2 <= max2) {
2428     pv1 = NULL;
2429     pv2 = dest;
2430   } else {
2431     return FALSE;
2432   }
2433
2434   if (min1 < max1) {
2435     g_value_init (pv1, GST_TYPE_INT_RANGE);
2436     gst_value_set_int_range (pv1, min1, max1);
2437   } else if (min1 == max1) {
2438     g_value_init (pv1, G_TYPE_INT);
2439     g_value_set_int (pv1, min1);
2440   }
2441   if (min2 < max2) {
2442     g_value_init (pv2, GST_TYPE_INT_RANGE);
2443     gst_value_set_int_range (pv2, min2, max2);
2444   } else if (min2 == max2) {
2445     g_value_init (pv2, G_TYPE_INT);
2446     g_value_set_int (pv2, min2);
2447   }
2448
2449   if (min1 <= max1 && min2 <= max2) {
2450     gst_value_list_concat (dest, pv1, pv2);
2451     g_value_unset (pv1);
2452     g_value_unset (pv2);
2453   }
2454   return TRUE;
2455 }
2456
2457 static gboolean
2458 gst_value_subtract_int_range_int (GValue * dest, const GValue * minuend,
2459     const GValue * subtrahend)
2460 {
2461   gint min = gst_value_get_int_range_min (minuend);
2462   gint max = gst_value_get_int_range_max (minuend);
2463   gint val = g_value_get_int (subtrahend);
2464
2465   g_return_val_if_fail (min < max, FALSE);
2466
2467   /* value is outside of the range, return range unchanged */
2468   if (val < min || val > max) {
2469     gst_value_init_and_copy (dest, minuend);
2470     return TRUE;
2471   } else {
2472     /* max must be MAXINT too as val <= max */
2473     if (val == G_MAXINT) {
2474       max--;
2475       val--;
2476     }
2477     /* min must be MININT too as val >= max */
2478     if (val == G_MININT) {
2479       min++;
2480       val++;
2481     }
2482     gst_value_create_new_range (dest, min, val - 1, val + 1, max);
2483   }
2484   return TRUE;
2485 }
2486
2487 static gboolean
2488 gst_value_subtract_int_range_int_range (GValue * dest, const GValue * minuend,
2489     const GValue * subtrahend)
2490 {
2491   gint min1 = gst_value_get_int_range_min (minuend);
2492   gint max1 = gst_value_get_int_range_max (minuend);
2493   gint min2 = gst_value_get_int_range_min (subtrahend);
2494   gint max2 = gst_value_get_int_range_max (subtrahend);
2495
2496   if (max2 == G_MAXINT && min2 == G_MININT) {
2497     return FALSE;
2498   } else if (max2 == G_MAXINT) {
2499     return gst_value_create_new_range (dest, min1, MIN (min2 - 1, max1), 1, 0);
2500   } else if (min2 == G_MININT) {
2501     return gst_value_create_new_range (dest, MAX (max2 + 1, min1), max1, 1, 0);
2502   } else {
2503     return gst_value_create_new_range (dest, min1, MIN (min2 - 1, max1),
2504         MAX (max2 + 1, min1), max1);
2505   }
2506 }
2507
2508 static gboolean
2509 gst_value_subtract_double_double_range (GValue * dest, const GValue * minuend,
2510     const GValue * subtrahend)
2511 {
2512   gdouble min = gst_value_get_double_range_min (subtrahend);
2513   gdouble max = gst_value_get_double_range_max (subtrahend);
2514   gdouble val = g_value_get_double (minuend);
2515
2516   if (val < min || val > max) {
2517     gst_value_init_and_copy (dest, minuend);
2518     return TRUE;
2519   }
2520   return FALSE;
2521 }
2522
2523 static gboolean
2524 gst_value_subtract_double_range_double (GValue * dest, const GValue * minuend,
2525     const GValue * subtrahend)
2526 {
2527   /* since we don't have open ranges, we cannot create a hole in
2528    * a double range. We return the original range */
2529   gst_value_init_and_copy (dest, minuend);
2530   return TRUE;
2531 }
2532
2533 static gboolean
2534 gst_value_subtract_double_range_double_range (GValue * dest,
2535     const GValue * minuend, const GValue * subtrahend)
2536 {
2537   /* since we don't have open ranges, we have to approximate */
2538   /* done like with ints */
2539   gdouble min1 = gst_value_get_double_range_min (minuend);
2540   gdouble max2 = gst_value_get_double_range_max (minuend);
2541   gdouble max1 = MIN (gst_value_get_double_range_min (subtrahend), max2);
2542   gdouble min2 = MAX (gst_value_get_double_range_max (subtrahend), min1);
2543   GValue v1 = { 0, };
2544   GValue v2 = { 0, };
2545   GValue *pv1, *pv2;            /* yeah, hungarian! */
2546
2547   if (min1 < max1 && min2 < max2) {
2548     pv1 = &v1;
2549     pv2 = &v2;
2550   } else if (min1 < max1) {
2551     pv1 = dest;
2552     pv2 = NULL;
2553   } else if (min2 < max2) {
2554     pv1 = NULL;
2555     pv2 = dest;
2556   } else {
2557     return FALSE;
2558   }
2559
2560   if (min1 < max1) {
2561     g_value_init (pv1, GST_TYPE_DOUBLE_RANGE);
2562     gst_value_set_double_range (pv1, min1, max1);
2563   }
2564   if (min2 < max2) {
2565     g_value_init (pv2, GST_TYPE_DOUBLE_RANGE);
2566     gst_value_set_double_range (pv2, min2, max2);
2567   }
2568
2569   if (min1 < max1 && min2 < max2) {
2570     gst_value_list_concat (dest, pv1, pv2);
2571     g_value_unset (pv1);
2572     g_value_unset (pv2);
2573   }
2574   return TRUE;
2575 }
2576
2577 static gboolean
2578 gst_value_subtract_from_list (GValue * dest, const GValue * minuend,
2579     const GValue * subtrahend)
2580 {
2581   guint i, size;
2582   GValue subtraction = { 0, };
2583   gboolean ret = FALSE;
2584
2585   size = gst_value_list_get_size (minuend);
2586   for (i = 0; i < size; i++) {
2587     const GValue *cur = gst_value_list_get_value (minuend, i);
2588
2589     if (gst_value_subtract (&subtraction, cur, subtrahend)) {
2590       if (!ret) {
2591         gst_value_init_and_copy (dest, &subtraction);
2592         ret = TRUE;
2593       } else if (GST_VALUE_HOLDS_LIST (dest)
2594           && GST_VALUE_HOLDS_LIST (&subtraction)) {
2595         /* unroll */
2596         GValue unroll = { 0, };
2597
2598         gst_value_init_and_copy (&unroll, dest);
2599         g_value_unset (dest);
2600         gst_value_list_concat (dest, &unroll, &subtraction);
2601       } else if (GST_VALUE_HOLDS_LIST (dest)) {
2602         gst_value_list_append_value (dest, &subtraction);
2603       } else {
2604         GValue temp = { 0, };
2605
2606         gst_value_init_and_copy (&temp, dest);
2607         g_value_unset (dest);
2608         gst_value_list_concat (dest, &temp, &subtraction);
2609         g_value_unset (&temp);
2610       }
2611       g_value_unset (&subtraction);
2612     }
2613   }
2614   return ret;
2615 }
2616
2617 static gboolean
2618 gst_value_subtract_list (GValue * dest, const GValue * minuend,
2619     const GValue * subtrahend)
2620 {
2621   guint i, size;
2622   GValue data[2] = { {0,}, {0,} };
2623   GValue *subtraction = &data[0], *result = &data[1];
2624
2625   gst_value_init_and_copy (result, minuend);
2626   size = gst_value_list_get_size (subtrahend);
2627   for (i = 0; i < size; i++) {
2628     const GValue *cur = gst_value_list_get_value (subtrahend, i);
2629
2630     if (gst_value_subtract (subtraction, result, cur)) {
2631       GValue *temp = result;
2632
2633       result = subtraction;
2634       subtraction = temp;
2635       g_value_unset (subtraction);
2636     } else {
2637       g_value_unset (result);
2638       return FALSE;
2639     }
2640   }
2641   gst_value_init_and_copy (dest, result);
2642   g_value_unset (result);
2643   return TRUE;
2644 }
2645
2646 static gboolean
2647 gst_value_subtract_fraction_fraction_range (GValue * dest,
2648     const GValue * minuend, const GValue * subtrahend)
2649 {
2650   const GValue *min = gst_value_get_fraction_range_min (subtrahend);
2651   const GValue *max = gst_value_get_fraction_range_max (subtrahend);
2652   GstValueCompareFunc compare;
2653
2654   if ((compare = gst_value_get_compare_func (minuend))) {
2655     /* subtracting a range from an fraction only works if the fraction
2656      * is not in the range */
2657     if (gst_value_compare_with_func (minuend, min, compare) ==
2658         GST_VALUE_LESS_THAN ||
2659         gst_value_compare_with_func (minuend, max, compare) ==
2660         GST_VALUE_GREATER_THAN) {
2661       /* and the result is the value */
2662       gst_value_init_and_copy (dest, minuend);
2663       return TRUE;
2664     }
2665   }
2666   return FALSE;
2667 }
2668
2669 static gboolean
2670 gst_value_subtract_fraction_range_fraction (GValue * dest,
2671     const GValue * minuend, const GValue * subtrahend)
2672 {
2673   /* since we don't have open ranges, we cannot create a hole in
2674    * a range. We return the original range */
2675   gst_value_init_and_copy (dest, minuend);
2676   return TRUE;
2677 }
2678
2679 static gboolean
2680 gst_value_subtract_fraction_range_fraction_range (GValue * dest,
2681     const GValue * minuend, const GValue * subtrahend)
2682 {
2683   /* since we don't have open ranges, we have to approximate */
2684   /* done like with ints and doubles. Creates a list of 2 fraction ranges */
2685   const GValue *min1 = gst_value_get_fraction_range_min (minuend);
2686   const GValue *max2 = gst_value_get_fraction_range_max (minuend);
2687   const GValue *max1 = gst_value_get_fraction_range_min (subtrahend);
2688   const GValue *min2 = gst_value_get_fraction_range_max (subtrahend);
2689   int cmp1, cmp2;
2690   GValue v1 = { 0, };
2691   GValue v2 = { 0, };
2692   GValue *pv1, *pv2;            /* yeah, hungarian! */
2693   GstValueCompareFunc compare;
2694
2695   g_return_val_if_fail (min1 != NULL && max1 != NULL, FALSE);
2696   g_return_val_if_fail (min2 != NULL && max2 != NULL, FALSE);
2697
2698   compare = gst_value_get_compare_func (min1);
2699   g_return_val_if_fail (compare, FALSE);
2700
2701   cmp1 = gst_value_compare_with_func (max2, max1, compare);
2702   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
2703   if (cmp1 == GST_VALUE_LESS_THAN)
2704     max1 = max2;
2705   cmp1 = gst_value_compare_with_func (min1, min2, compare);
2706   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
2707   if (cmp1 == GST_VALUE_GREATER_THAN)
2708     min2 = min1;
2709
2710   cmp1 = gst_value_compare_with_func (min1, max1, compare);
2711   cmp2 = gst_value_compare_with_func (min2, max2, compare);
2712
2713   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
2714     pv1 = &v1;
2715     pv2 = &v2;
2716   } else if (cmp1 == GST_VALUE_LESS_THAN) {
2717     pv1 = dest;
2718     pv2 = NULL;
2719   } else if (cmp2 == GST_VALUE_LESS_THAN) {
2720     pv1 = NULL;
2721     pv2 = dest;
2722   } else {
2723     return FALSE;
2724   }
2725
2726   if (cmp1 == GST_VALUE_LESS_THAN) {
2727     g_value_init (pv1, GST_TYPE_FRACTION_RANGE);
2728     gst_value_set_fraction_range (pv1, min1, max1);
2729   }
2730   if (cmp2 == GST_VALUE_LESS_THAN) {
2731     g_value_init (pv2, GST_TYPE_FRACTION_RANGE);
2732     gst_value_set_fraction_range (pv2, min2, max2);
2733   }
2734
2735   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
2736     gst_value_list_concat (dest, pv1, pv2);
2737     g_value_unset (pv1);
2738     g_value_unset (pv2);
2739   }
2740   return TRUE;
2741 }
2742
2743
2744 /**************
2745  * comparison *
2746  **************/
2747
2748 /**
2749  * gst_value_can_compare:
2750  * @value1: a value to compare
2751  * @value2: another value to compare
2752  *
2753  * Determines if @value1 and @value2 can be compared.
2754  *
2755  * Returns: TRUE if the values can be compared
2756  */
2757 gboolean
2758 gst_value_can_compare (const GValue * value1, const GValue * value2)
2759 {
2760   GstValueTable *table;
2761   guint i;
2762
2763   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
2764     return FALSE;
2765
2766   for (i = 0; i < gst_value_table->len; i++) {
2767     table = &g_array_index (gst_value_table, GstValueTable, i);
2768     if (g_type_is_a (G_VALUE_TYPE (value1), table->type) && table->compare)
2769       return TRUE;
2770   }
2771
2772   return FALSE;
2773 }
2774
2775 /*
2776  * gst_value_get_compare_func:
2777  * @value1: a value to get the compare function for
2778  *
2779  * Determines the compare function to be used with values of the same type as
2780  * @value1. The function can be given to gst_value_compare_with_func().
2781  *
2782  * Returns: A #GstValueCompareFunc value
2783  */
2784 static GstValueCompareFunc
2785 gst_value_get_compare_func (const GValue * value1)
2786 {
2787   GstValueTable *table, *best = NULL;
2788   guint i;
2789
2790   for (i = 0; i < gst_value_table->len; i++) {
2791     table = &g_array_index (gst_value_table, GstValueTable, i);
2792     if (table->type == G_VALUE_TYPE (value1) && table->compare != NULL) {
2793       best = table;
2794       break;
2795     }
2796     if (g_type_is_a (G_VALUE_TYPE (value1), table->type)) {
2797       if (!best || g_type_is_a (table->type, best->type))
2798         best = table;
2799     }
2800   }
2801   if (best) {
2802     return best->compare;
2803   }
2804   return NULL;
2805 }
2806
2807 /**
2808  * gst_value_compare:
2809  * @value1: a value to compare
2810  * @value2: another value to compare
2811  *
2812  * Compares @value1 and @value2.  If @value1 and @value2 cannot be
2813  * compared, the function returns GST_VALUE_UNORDERED.  Otherwise,
2814  * if @value1 is greater than @value2, GST_VALUE_GREATER_THAN is returned.
2815  * If @value1 is less than @value2, GST_VALUE_LESS_THAN is returned.
2816  * If the values are equal, GST_VALUE_EQUAL is returned.
2817  *
2818  * Returns: A #GstValueCompareType value
2819  */
2820 gint
2821 gst_value_compare (const GValue * value1, const GValue * value2)
2822 {
2823   GstValueCompareFunc compare;
2824
2825   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
2826     return GST_VALUE_UNORDERED;
2827
2828   compare = gst_value_get_compare_func (value1);
2829   if (compare) {
2830     return compare (value1, value2);
2831   }
2832
2833   g_critical ("unable to compare values of type %s\n",
2834       g_type_name (G_VALUE_TYPE (value1)));
2835   return GST_VALUE_UNORDERED;
2836 }
2837
2838 /*
2839  * gst_value_compare_with_func:
2840  * @value1: a value to compare
2841  * @value2: another value to compare
2842  * @compare: compare function
2843  *
2844  * Compares @value1 and @value2 using the @compare function. Works like
2845  * gst_value_compare() but allows to save time determining the compare function
2846  * a multiple times. 
2847  *
2848  * Returns: A #GstValueCompareType value
2849  */
2850 static gint
2851 gst_value_compare_with_func (const GValue * value1, const GValue * value2,
2852     GstValueCompareFunc compare)
2853 {
2854   g_assert (compare);
2855
2856   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
2857     return GST_VALUE_UNORDERED;
2858
2859   return compare (value1, value2);
2860 }
2861
2862 /* union */
2863
2864 /**
2865  * gst_value_can_union:
2866  * @value1: a value to union
2867  * @value2: another value to union
2868  *
2869  * Determines if @value1 and @value2 can be non-trivially unioned.
2870  * Any two values can be trivially unioned by adding both of them
2871  * to a GstValueList.  However, certain types have the possibility
2872  * to be unioned in a simpler way.  For example, an integer range
2873  * and an integer can be unioned if the integer is a subset of the
2874  * integer range.  If there is the possibility that two values can
2875  * be unioned, this function returns TRUE.
2876  *
2877  * Returns: TRUE if there is a function allowing the two values to
2878  * be unioned.
2879  */
2880 gboolean
2881 gst_value_can_union (const GValue * value1, const GValue * value2)
2882 {
2883   GstValueUnionInfo *union_info;
2884   guint i;
2885
2886   for (i = 0; i < gst_value_union_funcs->len; i++) {
2887     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
2888     if (union_info->type1 == G_VALUE_TYPE (value1) &&
2889         union_info->type2 == G_VALUE_TYPE (value2))
2890       return TRUE;
2891     if (union_info->type1 == G_VALUE_TYPE (value2) &&
2892         union_info->type2 == G_VALUE_TYPE (value1))
2893       return TRUE;
2894   }
2895
2896   return FALSE;
2897 }
2898
2899 /**
2900  * gst_value_union:
2901  * @dest: the destination value
2902  * @value1: a value to union
2903  * @value2: another value to union
2904  *
2905  * Creates a GValue cooresponding to the union of @value1 and @value2.
2906  *
2907  * Returns: always returns %TRUE
2908  */
2909 /* FIXME: change return type to 'void'? */
2910 gboolean
2911 gst_value_union (GValue * dest, const GValue * value1, const GValue * value2)
2912 {
2913   GstValueUnionInfo *union_info;
2914   guint i;
2915
2916   for (i = 0; i < gst_value_union_funcs->len; i++) {
2917     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
2918     if (union_info->type1 == G_VALUE_TYPE (value1) &&
2919         union_info->type2 == G_VALUE_TYPE (value2)) {
2920       if (union_info->func (dest, value1, value2)) {
2921         return TRUE;
2922       }
2923     }
2924     if (union_info->type1 == G_VALUE_TYPE (value2) &&
2925         union_info->type2 == G_VALUE_TYPE (value1)) {
2926       if (union_info->func (dest, value2, value1)) {
2927         return TRUE;
2928       }
2929     }
2930   }
2931
2932   gst_value_list_concat (dest, value1, value2);
2933   return TRUE;
2934 }
2935
2936 /**
2937  * gst_value_register_union_func:
2938  * @type1: a type to union
2939  * @type2: another type to union
2940  * @func: a function that implments creating a union between the two types
2941  *
2942  * Registers a union function that can create a union between GValues
2943  * of the type @type1 and @type2.
2944  *
2945  * Union functions should be registered at startup before any pipelines are
2946  * started, as gst_value_register_union_func() is not thread-safe and cannot
2947  * be used at the same time as gst_value_union() or gst_value_can_union().
2948  */
2949 void
2950 gst_value_register_union_func (GType type1, GType type2, GstValueUnionFunc func)
2951 {
2952   GstValueUnionInfo union_info;
2953
2954   union_info.type1 = type1;
2955   union_info.type2 = type2;
2956   union_info.func = func;
2957
2958   g_array_append_val (gst_value_union_funcs, union_info);
2959 }
2960
2961 /* intersection */
2962
2963 /**
2964  * gst_value_can_intersect:
2965  * @value1: a value to intersect
2966  * @value2: another value to intersect
2967  *
2968  * Determines if intersecting two values will produce a valid result.
2969  * Two values will produce a valid intersection if they have the same
2970  * type, or if there is a method (registered by
2971  * gst_value_register_intersection_func()) to calculate the intersection.
2972  *
2973  * Returns: TRUE if the values can intersect
2974  */
2975 gboolean
2976 gst_value_can_intersect (const GValue * value1, const GValue * value2)
2977 {
2978   GstValueIntersectInfo *intersect_info;
2979   guint i;
2980
2981   /* special cases */
2982   if (GST_VALUE_HOLDS_LIST (value1) || GST_VALUE_HOLDS_LIST (value2))
2983     return TRUE;
2984
2985   for (i = 0; i < gst_value_intersect_funcs->len; i++) {
2986     intersect_info = &g_array_index (gst_value_intersect_funcs,
2987         GstValueIntersectInfo, i);
2988     if (intersect_info->type1 == G_VALUE_TYPE (value1) &&
2989         intersect_info->type2 == G_VALUE_TYPE (value2))
2990       if (intersect_info->type2 == G_VALUE_TYPE (value1) &&
2991           intersect_info->type1 == G_VALUE_TYPE (value2))
2992         return TRUE;
2993   }
2994
2995   return gst_value_can_compare (value1, value2);
2996 }
2997
2998 /**
2999  * gst_value_intersect:
3000  * @dest: a uninitialized #GValue that will hold the calculated
3001  * intersection value
3002  * @value1: a value to intersect
3003  * @value2: another value to intersect
3004  *
3005  * Calculates the intersection of two values.  If the values have
3006  * a non-empty intersection, the value representing the intersection
3007  * is placed in @dest.  If the intersection is non-empty, @dest is
3008  * not modified.
3009  *
3010  * Returns: TRUE if the intersection is non-empty
3011  */
3012 gboolean
3013 gst_value_intersect (GValue * dest, const GValue * value1,
3014     const GValue * value2)
3015 {
3016   GstValueIntersectInfo *intersect_info;
3017   guint i;
3018   gboolean ret = FALSE;
3019
3020   /* special cases first */
3021   if (GST_VALUE_HOLDS_LIST (value1))
3022     return gst_value_intersect_list (dest, value1, value2);
3023   if (GST_VALUE_HOLDS_LIST (value2))
3024     return gst_value_intersect_list (dest, value2, value1);
3025
3026   for (i = 0; i < gst_value_intersect_funcs->len; i++) {
3027     intersect_info = &g_array_index (gst_value_intersect_funcs,
3028         GstValueIntersectInfo, i);
3029     if (intersect_info->type1 == G_VALUE_TYPE (value1) &&
3030         intersect_info->type2 == G_VALUE_TYPE (value2)) {
3031       ret = intersect_info->func (dest, value1, value2);
3032       return ret;
3033     }
3034     if (intersect_info->type1 == G_VALUE_TYPE (value2) &&
3035         intersect_info->type2 == G_VALUE_TYPE (value1)) {
3036       ret = intersect_info->func (dest, value2, value1);
3037       return ret;
3038     }
3039   }
3040
3041   if (gst_value_compare (value1, value2) == GST_VALUE_EQUAL) {
3042     gst_value_init_and_copy (dest, value1);
3043     ret = TRUE;
3044   }
3045
3046   return ret;
3047 }
3048
3049 /**
3050  * gst_value_register_intersect_func:
3051  * @type1: the first type to intersect
3052  * @type2: the second type to intersect
3053  * @func: the intersection function
3054  *
3055  * Registers a function that is called to calculate the intersection
3056  * of the values having the types @type1 and @type2.
3057  *
3058  * Intersect functions should be registered at startup before any pipelines are
3059  * started, as gst_value_register_intersect_func() is not thread-safe and
3060  * cannot be used at the same time as gst_value_intersect() or
3061  * gst_value_can_intersect().
3062  */
3063 void
3064 gst_value_register_intersect_func (GType type1, GType type2,
3065     GstValueIntersectFunc func)
3066 {
3067   GstValueIntersectInfo intersect_info;
3068
3069   intersect_info.type1 = type1;
3070   intersect_info.type2 = type2;
3071   intersect_info.func = func;
3072
3073   g_array_append_val (gst_value_intersect_funcs, intersect_info);
3074 }
3075
3076
3077 /* subtraction */
3078
3079 /**
3080  * gst_value_subtract:
3081  * @dest: the destination value for the result if the subtraction is not empty
3082  * @minuend: the value to subtract from
3083  * @subtrahend: the value to subtract
3084  *
3085  * Subtracts @subtrahend from @minuend and stores the result in @dest.
3086  * Note that this means subtraction as in sets, not as in mathematics.
3087  *
3088  * Returns: %TRUE if the subtraction is not empty
3089  */
3090 gboolean
3091 gst_value_subtract (GValue * dest, const GValue * minuend,
3092     const GValue * subtrahend)
3093 {
3094   GstValueSubtractInfo *info;
3095   guint i;
3096
3097   /* special cases first */
3098   if (GST_VALUE_HOLDS_LIST (minuend))
3099     return gst_value_subtract_from_list (dest, minuend, subtrahend);
3100   if (GST_VALUE_HOLDS_LIST (subtrahend))
3101     return gst_value_subtract_list (dest, minuend, subtrahend);
3102
3103   for (i = 0; i < gst_value_subtract_funcs->len; i++) {
3104     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
3105     if (info->minuend == G_VALUE_TYPE (minuend) &&
3106         info->subtrahend == G_VALUE_TYPE (subtrahend)) {
3107       return info->func (dest, minuend, subtrahend);
3108     }
3109   }
3110
3111   if (gst_value_compare (minuend, subtrahend) != GST_VALUE_EQUAL) {
3112     gst_value_init_and_copy (dest, minuend);
3113     return TRUE;
3114   }
3115
3116   return FALSE;
3117 }
3118
3119 #if 0
3120 gboolean
3121 gst_value_subtract (GValue * dest, const GValue * minuend,
3122     const GValue * subtrahend)
3123 {
3124   gboolean ret = gst_value_subtract2 (dest, minuend, subtrahend);
3125
3126   g_printerr ("\"%s\"  -  \"%s\"  =  \"%s\"\n", gst_value_serialize (minuend),
3127       gst_value_serialize (subtrahend),
3128       ret ? gst_value_serialize (dest) : "---");
3129   return ret;
3130 }
3131 #endif
3132
3133 /**
3134  * gst_value_can_subtract:
3135  * @minuend: the value to subtract from
3136  * @subtrahend: the value to subtract
3137  *
3138  * Checks if it's possible to subtract @subtrahend from @minuend.
3139  *
3140  * Returns: TRUE if a subtraction is possible
3141  */
3142 gboolean
3143 gst_value_can_subtract (const GValue * minuend, const GValue * subtrahend)
3144 {
3145   GstValueSubtractInfo *info;
3146   guint i;
3147
3148   /* special cases */
3149   if (GST_VALUE_HOLDS_LIST (minuend) || GST_VALUE_HOLDS_LIST (subtrahend))
3150     return TRUE;
3151
3152   for (i = 0; i < gst_value_subtract_funcs->len; i++) {
3153     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
3154     if (info->minuend == G_VALUE_TYPE (minuend) &&
3155         info->subtrahend == G_VALUE_TYPE (subtrahend))
3156       return TRUE;
3157   }
3158
3159   return gst_value_can_compare (minuend, subtrahend);
3160 }
3161
3162 /**
3163  * gst_value_register_subtract_func:
3164  * @minuend_type: type of the minuend
3165  * @subtrahend_type: type of the subtrahend
3166  * @func: function to use
3167  *
3168  * Registers @func as a function capable of subtracting the values of
3169  * @subtrahend_type from values of @minuend_type.
3170  *
3171  * Subtract functions should be registered at startup before any pipelines are
3172  * started, as gst_value_register_subtract_func() is not thread-safe and
3173  * cannot be used at the same time as gst_value_subtract().
3174  */
3175 void
3176 gst_value_register_subtract_func (GType minuend_type, GType subtrahend_type,
3177     GstValueSubtractFunc func)
3178 {
3179   GstValueSubtractInfo info;
3180
3181   /* one type must be unfixed, other subtractions can be done as comparisons */
3182   g_return_if_fail (!gst_type_is_fixed (minuend_type)
3183       || !gst_type_is_fixed (subtrahend_type));
3184
3185   info.minuend = minuend_type;
3186   info.subtrahend = subtrahend_type;
3187   info.func = func;
3188
3189   g_array_append_val (gst_value_subtract_funcs, info);
3190 }
3191
3192 /**
3193  * gst_value_register:
3194  * @table: structure containing functions to register
3195  *
3196  * Registers functions to perform calculations on #GValues of a given
3197  * type.
3198  */
3199 void
3200 gst_value_register (const GstValueTable * table)
3201 {
3202   g_array_append_val (gst_value_table, *table);
3203 }
3204
3205 /**
3206  * gst_value_init_and_copy:
3207  * @dest: the target value
3208  * @src: the source value
3209  *
3210  * Initialises the target value to be of the same type as source and then copies
3211  * the contents from source to target.
3212  */
3213 void
3214 gst_value_init_and_copy (GValue * dest, const GValue * src)
3215 {
3216   g_value_init (dest, G_VALUE_TYPE (src));
3217   g_value_copy (src, dest);
3218 }
3219
3220 /**
3221  * gst_value_serialize:
3222  * @value: a #GValue to serialize
3223  *
3224  * tries to transform the given @value into a string representation that allows
3225  * getting back this string later on using gst_value_deserialize().
3226  *
3227  * Returns: the serialization for @value or NULL if none exists
3228  */
3229 gchar *
3230 gst_value_serialize (const GValue * value)
3231 {
3232   guint i;
3233   GValue s_val = { 0 };
3234   GstValueTable *table, *best = NULL;
3235   char *s;
3236
3237   g_return_val_if_fail (G_IS_VALUE (value), NULL);
3238
3239   for (i = 0; i < gst_value_table->len; i++) {
3240     table = &g_array_index (gst_value_table, GstValueTable, i);
3241     if (table->serialize == NULL)
3242       continue;
3243     if (table->type == G_VALUE_TYPE (value)) {
3244       best = table;
3245       break;
3246     }
3247     if (g_type_is_a (G_VALUE_TYPE (value), table->type)) {
3248       if (!best || g_type_is_a (table->type, best->type))
3249         best = table;
3250     }
3251   }
3252   if (best)
3253     return best->serialize (value);
3254
3255   g_value_init (&s_val, G_TYPE_STRING);
3256   if (g_value_transform (value, &s_val)) {
3257     s = gst_string_wrap (g_value_get_string (&s_val));
3258   } else {
3259     s = NULL;
3260   }
3261   g_value_unset (&s_val);
3262
3263   return s;
3264 }
3265
3266 /**
3267  * gst_value_deserialize:
3268  * @dest: #GValue to fill with contents of deserialization
3269  * @src: string to deserialize
3270  *
3271  * Tries to deserialize a string into the type specified by the given GValue.
3272  * If the operation succeeds, TRUE is returned, FALSE otherwise.
3273  *
3274  * Returns: TRUE on success
3275  */
3276 gboolean
3277 gst_value_deserialize (GValue * dest, const gchar * src)
3278 {
3279   GstValueTable *table, *best = NULL;
3280   guint i;
3281
3282   g_return_val_if_fail (src != NULL, FALSE);
3283   g_return_val_if_fail (G_IS_VALUE (dest), FALSE);
3284
3285   for (i = 0; i < gst_value_table->len; i++) {
3286     table = &g_array_index (gst_value_table, GstValueTable, i);
3287     if (table->serialize == NULL)
3288       continue;
3289
3290     if (table->type == G_VALUE_TYPE (dest)) {
3291       best = table;
3292       break;
3293     }
3294
3295     if (g_type_is_a (G_VALUE_TYPE (dest), table->type)) {
3296       if (!best || g_type_is_a (table->type, best->type))
3297         best = table;
3298     }
3299   }
3300   if (best) {
3301     return best->deserialize (dest, src);
3302   }
3303
3304   return FALSE;
3305 }
3306
3307 /**
3308  * gst_value_is_fixed:
3309  * @value: the #GValue to check
3310  *
3311  * Tests if the given GValue, if available in a GstStructure (or any other
3312  * container) contains a "fixed" (which means: one value) or an "unfixed"
3313  * (which means: multiple possible values, such as data lists or data
3314  * ranges) value.
3315  *
3316  * Returns: true if the value is "fixed".
3317  */
3318
3319 gboolean
3320 gst_value_is_fixed (const GValue * value)
3321 {
3322   GType type = G_VALUE_TYPE (value);
3323
3324   if (type == GST_TYPE_ARRAY) {
3325     gboolean fixed = TRUE;
3326     gint size, n;
3327     const GValue *kid;
3328
3329     /* check recursively */
3330     size = gst_value_array_get_size (value);
3331     for (n = 0; n < size; n++) {
3332       kid = gst_value_array_get_value (value, n);
3333       fixed &= gst_value_is_fixed (kid);
3334     }
3335
3336     return fixed;
3337   }
3338
3339   return gst_type_is_fixed (type);
3340 }
3341
3342 /************
3343  * fraction *
3344  ************/
3345
3346 /* helper functions */
3347
3348 /* Finds the greatest common divisor.
3349  * Returns 1 if none other found.
3350  * This is Euclid's algorithm. */
3351 static gint
3352 gst_greatest_common_divisor (gint a, gint b)
3353 {
3354   while (b != 0) {
3355     int temp = a;
3356
3357     a = b;
3358     b = temp % b;
3359   }
3360
3361   return ABS (a);
3362 }
3363
3364 static void
3365 gst_value_init_fraction (GValue * value)
3366 {
3367   value->data[0].v_int = 0;
3368   value->data[1].v_int = 1;
3369 }
3370
3371 static void
3372 gst_value_copy_fraction (const GValue * src_value, GValue * dest_value)
3373 {
3374   dest_value->data[0].v_int = src_value->data[0].v_int;
3375   dest_value->data[1].v_int = src_value->data[1].v_int;
3376 }
3377
3378 static gchar *
3379 gst_value_collect_fraction (GValue * value, guint n_collect_values,
3380     GTypeCValue * collect_values, guint collect_flags)
3381 {
3382   gst_value_set_fraction (value,
3383       collect_values[0].v_int, collect_values[1].v_int);
3384
3385   return NULL;
3386 }
3387
3388 static gchar *
3389 gst_value_lcopy_fraction (const GValue * value, guint n_collect_values,
3390     GTypeCValue * collect_values, guint collect_flags)
3391 {
3392   gint *numerator = collect_values[0].v_pointer;
3393   gint *denominator = collect_values[1].v_pointer;
3394
3395   if (!numerator)
3396     return g_strdup_printf ("numerator for `%s' passed as NULL",
3397         G_VALUE_TYPE_NAME (value));
3398   if (!denominator)
3399     return g_strdup_printf ("denominator for `%s' passed as NULL",
3400         G_VALUE_TYPE_NAME (value));
3401
3402   *numerator = value->data[0].v_int;
3403   *denominator = value->data[1].v_int;
3404
3405   return NULL;
3406 }
3407
3408 /**
3409  * gst_value_set_fraction:
3410  * @value: a GValue initialized to #GST_TYPE_FRACTION
3411  * @numerator: the numerator of the fraction
3412  * @denominator: the denominator of the fraction
3413  *
3414  * Sets @value to the fraction specified by @numerator over @denominator.
3415  * The fraction gets reduced to the smallest numerator and denominator,
3416  * and if necessary the sign is moved to the numerator.
3417  */
3418 void
3419 gst_value_set_fraction (GValue * value, gint numerator, gint denominator)
3420 {
3421   gint gcd = 0;
3422
3423   g_return_if_fail (GST_VALUE_HOLDS_FRACTION (value));
3424   g_return_if_fail (denominator != 0);
3425   g_return_if_fail (denominator >= -G_MAXINT);
3426   g_return_if_fail (numerator >= -G_MAXINT);
3427
3428   /* normalize sign */
3429   if (denominator < 0) {
3430     numerator = -numerator;
3431     denominator = -denominator;
3432   }
3433
3434   /* check for reduction */
3435   gcd = gst_greatest_common_divisor (numerator, denominator);
3436   if (gcd) {
3437     numerator /= gcd;
3438     denominator /= gcd;
3439   }
3440
3441   g_assert (denominator > 0);
3442
3443   value->data[0].v_int = numerator;
3444   value->data[1].v_int = denominator;
3445 }
3446
3447 /**
3448  * gst_value_get_fraction_numerator:
3449  * @value: a GValue initialized to #GST_TYPE_FRACTION
3450  *
3451  * Gets the numerator of the fraction specified by @value.
3452  *
3453  * Returns: the numerator of the fraction.
3454  */
3455 gint
3456 gst_value_get_fraction_numerator (const GValue * value)
3457 {
3458   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 0);
3459
3460   return value->data[0].v_int;
3461 }
3462
3463 /**
3464  * gst_value_get_fraction_denominator:
3465  * @value: a GValue initialized to #GST_TYPE_FRACTION
3466  *
3467  * Gets the denominator of the fraction specified by @value.
3468  *
3469  * Returns: the denominator of the fraction.
3470  */
3471 gint
3472 gst_value_get_fraction_denominator (const GValue * value)
3473 {
3474   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 1);
3475
3476   return value->data[1].v_int;
3477 }
3478
3479 /**
3480  * gst_value_fraction_multiply:
3481  * @product: a GValue initialized to #GST_TYPE_FRACTION
3482  * @factor1: a GValue initialized to #GST_TYPE_FRACTION
3483  * @factor2: a GValue initialized to #GST_TYPE_FRACTION
3484  *
3485  * Multiplies the two GValues containing a GstFraction and sets @product
3486  * to the product of the two fractions.
3487  *
3488  * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise.
3489  */
3490 gboolean
3491 gst_value_fraction_multiply (GValue * product, const GValue * factor1,
3492     const GValue * factor2)
3493 {
3494   gint gcd, n1, n2, d1, d2;
3495
3496   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor1), FALSE);
3497   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor2), FALSE);
3498
3499   n1 = factor1->data[0].v_int;
3500   n2 = factor2->data[0].v_int;
3501   d1 = factor1->data[1].v_int;
3502   d2 = factor2->data[1].v_int;
3503
3504   gcd = gst_greatest_common_divisor (n1, d2);
3505   n1 /= gcd;
3506   d2 /= gcd;
3507   gcd = gst_greatest_common_divisor (n2, d1);
3508   n2 /= gcd;
3509   d1 /= gcd;
3510
3511   g_return_val_if_fail (n1 == 0 || G_MAXINT / ABS (n1) >= ABS (n2), FALSE);
3512   g_return_val_if_fail (G_MAXINT / ABS (d1) >= ABS (d2), FALSE);
3513
3514   gst_value_set_fraction (product, n1 * n2, d1 * d2);
3515
3516   return TRUE;
3517 }
3518
3519 /**
3520  * gst_value_fraction_subtract:
3521  * @dest: a GValue initialized to #GST_TYPE_FRACTION
3522  * @minuend: a GValue initialized to #GST_TYPE_FRACTION
3523  * @subtrahend: a GValue initialized to #GST_TYPE_FRACTION
3524  *
3525  * Subtracts the @subtrahend from the @minuend and sets @dest to the result.
3526  *
3527  * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise.
3528  */
3529 gboolean
3530 gst_value_fraction_subtract (GValue * dest,
3531     const GValue * minuend, const GValue * subtrahend)
3532 {
3533   gint n1, n2, d1, d2;
3534
3535   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (minuend), FALSE);
3536   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (subtrahend), FALSE);
3537
3538   n1 = minuend->data[0].v_int;
3539   n2 = subtrahend->data[0].v_int;
3540   d1 = minuend->data[1].v_int;
3541   d2 = subtrahend->data[1].v_int;
3542
3543   if (n1 == 0) {
3544     gst_value_set_fraction (dest, -n2, d2);
3545     return TRUE;
3546   }
3547   if (n2 == 0) {
3548     gst_value_set_fraction (dest, n1, d1);
3549     return TRUE;
3550   }
3551
3552   g_return_val_if_fail (n1 == 0 || G_MAXINT / ABS (n1) >= ABS (d2), FALSE);
3553   g_return_val_if_fail (G_MAXINT / ABS (d1) >= ABS (n2), FALSE);
3554   g_return_val_if_fail (G_MAXINT / ABS (d1) >= ABS (d2), FALSE);
3555
3556   gst_value_set_fraction (dest, (n1 * d2) - (n2 * d1), d1 * d2);
3557
3558   return TRUE;
3559 }
3560
3561 static gchar *
3562 gst_value_serialize_fraction (const GValue * value)
3563 {
3564   gint32 numerator = value->data[0].v_int;
3565   gint32 denominator = value->data[1].v_int;
3566   gboolean positive = TRUE;
3567
3568   /* get the sign and make components absolute */
3569   if (numerator < 0) {
3570     numerator = -numerator;
3571     positive = !positive;
3572   }
3573   if (denominator < 0) {
3574     denominator = -denominator;
3575     positive = !positive;
3576   }
3577
3578   return g_strdup_printf ("%s%d/%d",
3579       positive ? "" : "-", numerator, denominator);
3580 }
3581
3582 static gboolean
3583 gst_value_deserialize_fraction (GValue * dest, const gchar * s)
3584 {
3585   gint num, den;
3586
3587   if (G_UNLIKELY (s == NULL))
3588     return FALSE;
3589
3590   if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_FRACTION (dest)))
3591     return FALSE;
3592
3593   if (sscanf (s, "%d/%d", &num, &den) == 2) {
3594     gst_value_set_fraction (dest, num, den);
3595     return TRUE;
3596   }
3597   if (sscanf (s, "%d", &num) == 1) {
3598     gst_value_set_fraction (dest, num, 1);
3599     return TRUE;
3600   }
3601   if (g_ascii_strcasecmp (s, "min") == 0) {
3602     gst_value_set_fraction (dest, -G_MAXINT, 1);
3603     return TRUE;
3604   } else if (g_ascii_strcasecmp (s, "max") == 0) {
3605     gst_value_set_fraction (dest, G_MAXINT, 1);
3606     return TRUE;
3607   }
3608
3609   return FALSE;
3610 }
3611
3612 static void
3613 gst_value_transform_fraction_string (const GValue * src_value,
3614     GValue * dest_value)
3615 {
3616   dest_value->data[0].v_pointer = gst_value_serialize_fraction (src_value);
3617 }
3618
3619 static void
3620 gst_value_transform_string_fraction (const GValue * src_value,
3621     GValue * dest_value)
3622 {
3623   if (!gst_value_deserialize_fraction (dest_value,
3624           src_value->data[0].v_pointer))
3625     /* If the deserialize fails, ensure we leave the fraction in a
3626      * valid, if incorrect, state */
3627     gst_value_set_fraction (dest_value, 0, 1);
3628 }
3629
3630 #define MAX_TERMS       30
3631 #define MIN_DIVISOR     1.0e-10
3632 #define MAX_ERROR       1.0e-20
3633
3634 /* use continued fractions to transform a double into a fraction,
3635  * see http://mathforum.org/dr.math/faq/faq.fractions.html#decfrac.
3636  * This algorithm takes care of overflows.
3637  */
3638 static void
3639 gst_value_transform_double_fraction (const GValue * src_value,
3640     GValue * dest_value)
3641 {
3642   gdouble V, F;                 /* double being converted */
3643   gint N, D;                    /* will contain the result */
3644   gint A;                       /* current term in continued fraction */
3645   gint64 N1, D1;                /* numerator, denominator of last approx */
3646   gint64 N2, D2;                /* numerator, denominator of previous approx */
3647   gint i;
3648   gboolean negative = FALSE;
3649
3650   /* initialize fraction being converted */
3651   F = src_value->data[0].v_double;
3652   if (F < 0.0) {
3653     F = -F;
3654     negative = TRUE;
3655   }
3656
3657   V = F;
3658   /* initialize fractions with 1/0, 0/1 */
3659   N1 = 1;
3660   D1 = 0;
3661   N2 = 0;
3662   D2 = 1;
3663   N = 1;
3664   D = 1;
3665
3666   for (i = 0; i < MAX_TERMS; i++) {
3667     /* get next term */
3668     A = (gint) F;               /* no floor() needed, F is always >= 0 */
3669     /* get new divisor */
3670     F = F - A;
3671
3672     /* calculate new fraction in temp */
3673     N2 = N1 * A + N2;
3674     D2 = D1 * A + D2;
3675
3676     /* guard against overflow */
3677     if (N2 > G_MAXINT || D2 > G_MAXINT) {
3678       break;
3679     }
3680
3681     N = N2;
3682     D = D2;
3683
3684     /* save last two fractions */
3685     N2 = N1;
3686     D2 = D1;
3687     N1 = N;
3688     D1 = D;
3689
3690     /* quit if dividing by zero or close enough to target */
3691     if (F < MIN_DIVISOR || fabs (V - ((gdouble) N) / D) < MAX_ERROR) {
3692       break;
3693     }
3694
3695     /* Take reciprocal */
3696     F = 1 / F;
3697   }
3698   /* fix for overflow */
3699   if (D == 0) {
3700     N = G_MAXINT;
3701     D = 1;
3702   }
3703   /* fix for negative */
3704   if (negative)
3705     N = -N;
3706
3707   /* will also simplify */
3708   gst_value_set_fraction (dest_value, N, D);
3709 }
3710
3711 static void
3712 gst_value_transform_fraction_double (const GValue * src_value,
3713     GValue * dest_value)
3714 {
3715   dest_value->data[0].v_double = ((double) src_value->data[0].v_int) /
3716       ((double) src_value->data[1].v_int);
3717 }
3718
3719 static gint
3720 gst_value_compare_fraction (const GValue * value1, const GValue * value2)
3721 {
3722   gint n1, n2;
3723   gint d1, d2;
3724
3725   gint64 new_num_1;
3726   gint64 new_num_2;
3727
3728   n1 = value1->data[0].v_int;
3729   n2 = value2->data[0].v_int;
3730   d1 = value1->data[1].v_int;
3731   d2 = value2->data[1].v_int;
3732
3733   /* fractions are reduced when set, so we can quickly see if they're equal */
3734   if (n1 == n2 && d1 == d2)
3735     return GST_VALUE_EQUAL;
3736
3737   /* extend to 64 bits */
3738   new_num_1 = ((gint64) n1) * d2;
3739   new_num_2 = ((gint64) n2) * d1;
3740   if (new_num_1 < new_num_2)
3741     return GST_VALUE_LESS_THAN;
3742   if (new_num_1 > new_num_2)
3743     return GST_VALUE_GREATER_THAN;
3744
3745   /* new_num_1 == new_num_2 implies that both denominators must have 
3746    * been 0, beause otherwise simplification would have caught the
3747    * equivalence */
3748   return GST_VALUE_UNORDERED;
3749 }
3750
3751 /*********
3752  * GDate *
3753  *********/
3754
3755 /**
3756  * gst_value_set_date:
3757  * @value: a GValue initialized to GST_TYPE_DATE
3758  * @date: the date to set the value to
3759  *
3760  * Sets the contents of @value to coorespond to @date.  The actual
3761  * #GDate structure is copied before it is used.
3762  */
3763 void
3764 gst_value_set_date (GValue * value, const GDate * date)
3765 {
3766   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_DATE);
3767   g_return_if_fail (g_date_valid (date));
3768
3769   g_value_set_boxed (value, date);
3770 }
3771
3772 /**
3773  * gst_value_get_date:
3774  * @value: a GValue initialized to GST_TYPE_DATE
3775  *
3776  * Gets the contents of @value.
3777  *
3778  * Returns: the contents of @value
3779  */
3780 const GDate *
3781 gst_value_get_date (const GValue * value)
3782 {
3783   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_DATE, NULL);
3784
3785   return (const GDate *) g_value_get_boxed (value);
3786 }
3787
3788 static gpointer
3789 gst_date_copy (gpointer boxed)
3790 {
3791   const GDate *date = (const GDate *) boxed;
3792
3793   if (!g_date_valid (date)) {
3794     GST_WARNING ("invalid GDate");
3795     return NULL;
3796   }
3797
3798   return g_date_new_julian (g_date_get_julian (date));
3799 }
3800
3801 static gint
3802 gst_value_compare_date (const GValue * value1, const GValue * value2)
3803 {
3804   const GDate *date1 = (const GDate *) g_value_get_boxed (value1);
3805   const GDate *date2 = (const GDate *) g_value_get_boxed (value2);
3806   guint32 j1, j2;
3807
3808   if (date1 == date2)
3809     return GST_VALUE_EQUAL;
3810
3811   if ((date1 == NULL || !g_date_valid (date1))
3812       && (date2 != NULL && g_date_valid (date2))) {
3813     return GST_VALUE_LESS_THAN;
3814   }
3815
3816   if ((date2 == NULL || !g_date_valid (date2))
3817       && (date1 != NULL && g_date_valid (date1))) {
3818     return GST_VALUE_GREATER_THAN;
3819   }
3820
3821   if (date1 == NULL || date2 == NULL || !g_date_valid (date1)
3822       || !g_date_valid (date2)) {
3823     return GST_VALUE_UNORDERED;
3824   }
3825
3826   j1 = g_date_get_julian (date1);
3827   j2 = g_date_get_julian (date2);
3828
3829   if (j1 == j2)
3830     return GST_VALUE_EQUAL;
3831   else if (j1 < j2)
3832     return GST_VALUE_LESS_THAN;
3833   else
3834     return GST_VALUE_GREATER_THAN;
3835 }
3836
3837 static gchar *
3838 gst_value_serialize_date (const GValue * val)
3839 {
3840   const GDate *date = (const GDate *) g_value_get_boxed (val);
3841
3842   if (date == NULL || !g_date_valid (date))
3843     return g_strdup ("9999-99-99");
3844
3845   return g_strdup_printf ("%04u-%02u-%02u", g_date_get_year (date),
3846       g_date_get_month (date), g_date_get_day (date));
3847 }
3848
3849 static gboolean
3850 gst_value_deserialize_date (GValue * dest, const char *s)
3851 {
3852   guint year, month, day;
3853
3854   if (!s || sscanf (s, "%04u-%02u-%02u", &year, &month, &day) != 3)
3855     return FALSE;
3856
3857   if (!g_date_valid_dmy (day, month, year))
3858     return FALSE;
3859
3860   g_value_take_boxed (dest, g_date_new_dmy (day, month, year));
3861   return TRUE;
3862 }
3863
3864 static void
3865 gst_value_transform_date_string (const GValue * src_value, GValue * dest_value)
3866 {
3867   dest_value->data[0].v_pointer = gst_value_serialize_date (src_value);
3868 }
3869
3870 static void
3871 gst_value_transform_string_date (const GValue * src_value, GValue * dest_value)
3872 {
3873   gst_value_deserialize_date (dest_value, src_value->data[0].v_pointer);
3874 }
3875
3876 static void
3877 gst_value_transform_object_string (const GValue * src_value,
3878     GValue * dest_value)
3879 {
3880   GstObject *obj;
3881   gchar *str;
3882
3883   obj = g_value_get_object (src_value);
3884   str = obj ? GST_OBJECT_NAME (obj) : "NULL";
3885
3886   dest_value->data[0].v_pointer = g_strdup (str);
3887 }
3888
3889 static GTypeInfo _info = {
3890   0,
3891   NULL,
3892   NULL,
3893   NULL,
3894   NULL,
3895   NULL,
3896   0,
3897   0,
3898   NULL,
3899   NULL,
3900 };
3901
3902 static GTypeFundamentalInfo _finfo = {
3903   0
3904 };
3905
3906 #define FUNC_VALUE_GET_TYPE(type, name)                         \
3907 GType gst_ ## type ## _get_type (void)                          \
3908 {                                                               \
3909   static GType gst_ ## type ## _type = 0;                       \
3910                                                                 \
3911   if (G_UNLIKELY (gst_ ## type ## _type == 0)) {                \
3912     _info.value_table = & _gst_ ## type ## _value_table;        \
3913     gst_ ## type ## _type = g_type_register_fundamental (       \
3914         g_type_fundamental_next (),                             \
3915         name, &_info, &_finfo, 0);                              \
3916   }                                                             \
3917                                                                 \
3918   return gst_ ## type ## _type;                                 \
3919 }
3920
3921 static const GTypeValueTable _gst_fourcc_value_table = {
3922   gst_value_init_fourcc,
3923   NULL,
3924   gst_value_copy_fourcc,
3925   NULL,
3926   "i",
3927   gst_value_collect_fourcc,
3928   "p",
3929   gst_value_lcopy_fourcc
3930 };
3931
3932 FUNC_VALUE_GET_TYPE (fourcc, "GstFourcc");
3933
3934 static const GTypeValueTable _gst_int_range_value_table = {
3935   gst_value_init_int_range,
3936   NULL,
3937   gst_value_copy_int_range,
3938   NULL,
3939   "ii",
3940   gst_value_collect_int_range,
3941   "pp",
3942   gst_value_lcopy_int_range
3943 };
3944
3945 FUNC_VALUE_GET_TYPE (int_range, "GstIntRange");
3946
3947 static const GTypeValueTable _gst_double_range_value_table = {
3948   gst_value_init_double_range,
3949   NULL,
3950   gst_value_copy_double_range,
3951   NULL,
3952   "dd",
3953   gst_value_collect_double_range,
3954   "pp",
3955   gst_value_lcopy_double_range
3956 };
3957
3958 FUNC_VALUE_GET_TYPE (double_range, "GstDoubleRange");
3959
3960 static const GTypeValueTable _gst_fraction_range_value_table = {
3961   gst_value_init_fraction_range,
3962   gst_value_free_fraction_range,
3963   gst_value_copy_fraction_range,
3964   NULL,
3965   "iiii",
3966   gst_value_collect_fraction_range,
3967   "pppp",
3968   gst_value_lcopy_fraction_range
3969 };
3970
3971 FUNC_VALUE_GET_TYPE (fraction_range, "GstFractionRange");
3972
3973 static const GTypeValueTable _gst_value_list_value_table = {
3974   gst_value_init_list_or_array,
3975   gst_value_free_list_or_array,
3976   gst_value_copy_list_or_array,
3977   gst_value_list_or_array_peek_pointer,
3978   "p",
3979   gst_value_collect_list_or_array,
3980   "p",
3981   gst_value_lcopy_list_or_array
3982 };
3983
3984 FUNC_VALUE_GET_TYPE (value_list, "GstValueList");
3985
3986 static const GTypeValueTable _gst_value_array_value_table = {
3987   gst_value_init_list_or_array,
3988   gst_value_free_list_or_array,
3989   gst_value_copy_list_or_array,
3990   gst_value_list_or_array_peek_pointer,
3991   "p",
3992   gst_value_collect_list_or_array,
3993   "p",
3994   gst_value_lcopy_list_or_array
3995 };
3996
3997 FUNC_VALUE_GET_TYPE (value_array, "GstValueArray");
3998
3999 static const GTypeValueTable _gst_fraction_value_table = {
4000   gst_value_init_fraction,
4001   NULL,
4002   gst_value_copy_fraction,
4003   NULL,
4004   "ii",
4005   gst_value_collect_fraction,
4006   "pp",
4007   gst_value_lcopy_fraction
4008 };
4009
4010 FUNC_VALUE_GET_TYPE (fraction, "GstFraction");
4011
4012
4013 GType
4014 gst_date_get_type (void)
4015 {
4016   static GType gst_date_type = 0;
4017
4018   if (G_UNLIKELY (gst_date_type == 0)) {
4019     /* FIXME 0.11: we require GLib 2.8 already
4020      * Not using G_TYPE_DATE here on purpose, even if we could
4021      * if GLIB_CHECK_VERSION(2,8,0) was true: we don't want the
4022      * serialised strings to have different type strings depending
4023      * on what version is used, so FIXME when we require GLib-2.8 */
4024     gst_date_type = g_boxed_type_register_static ("GstDate",
4025         (GBoxedCopyFunc) gst_date_copy, (GBoxedFreeFunc) g_date_free);
4026   }
4027
4028   return gst_date_type;
4029 }
4030
4031 void
4032 _gst_value_initialize (void)
4033 {
4034   gst_value_table = g_array_new (FALSE, FALSE, sizeof (GstValueTable));
4035   gst_value_union_funcs = g_array_new (FALSE, FALSE,
4036       sizeof (GstValueUnionInfo));
4037   gst_value_intersect_funcs = g_array_new (FALSE, FALSE,
4038       sizeof (GstValueIntersectInfo));
4039   gst_value_subtract_funcs = g_array_new (FALSE, FALSE,
4040       sizeof (GstValueSubtractInfo));
4041
4042   {
4043     static GstValueTable gst_value = {
4044       0,
4045       gst_value_compare_fourcc,
4046       gst_value_serialize_fourcc,
4047       gst_value_deserialize_fourcc,
4048     };
4049
4050     gst_value.type = gst_fourcc_get_type ();
4051     gst_value_register (&gst_value);
4052   }
4053
4054   {
4055     static GstValueTable gst_value = {
4056       0,
4057       gst_value_compare_int_range,
4058       gst_value_serialize_int_range,
4059       gst_value_deserialize_int_range,
4060     };
4061
4062     gst_value.type = gst_int_range_get_type ();
4063     gst_value_register (&gst_value);
4064   }
4065
4066   {
4067     static GstValueTable gst_value = {
4068       0,
4069       gst_value_compare_double_range,
4070       gst_value_serialize_double_range,
4071       gst_value_deserialize_double_range,
4072     };
4073
4074     gst_value.type = gst_double_range_get_type ();
4075     gst_value_register (&gst_value);
4076   }
4077
4078   {
4079     static GstValueTable gst_value = {
4080       0,
4081       gst_value_compare_fraction_range,
4082       gst_value_serialize_fraction_range,
4083       gst_value_deserialize_fraction_range,
4084     };
4085
4086     gst_value.type = gst_fraction_range_get_type ();
4087     gst_value_register (&gst_value);
4088   }
4089
4090   {
4091     static GstValueTable gst_value = {
4092       0,
4093       gst_value_compare_list,
4094       gst_value_serialize_list,
4095       gst_value_deserialize_list,
4096     };
4097
4098     gst_value.type = gst_value_list_get_type ();
4099     gst_value_register (&gst_value);
4100   }
4101
4102   {
4103     static GstValueTable gst_value = {
4104       0,
4105       gst_value_compare_array,
4106       gst_value_serialize_array,
4107       gst_value_deserialize_array,
4108     };
4109
4110     gst_value.type = gst_value_array_get_type ();;
4111     gst_value_register (&gst_value);
4112   }
4113
4114   {
4115 #if 0
4116     static const GTypeValueTable value_table = {
4117       gst_value_init_buffer,
4118       NULL,
4119       gst_value_copy_buffer,
4120       NULL,
4121       "i",
4122       NULL,                     /*gst_value_collect_buffer, */
4123       "p",
4124       NULL                      /*gst_value_lcopy_buffer */
4125     };
4126 #endif
4127     static GstValueTable gst_value = {
4128       0,
4129       gst_value_compare_buffer,
4130       gst_value_serialize_buffer,
4131       gst_value_deserialize_buffer,
4132     };
4133
4134     gst_value.type = GST_TYPE_BUFFER;
4135     gst_value_register (&gst_value);
4136   }
4137   {
4138     static GstValueTable gst_value = {
4139       0,
4140       gst_value_compare_fraction,
4141       gst_value_serialize_fraction,
4142       gst_value_deserialize_fraction,
4143     };
4144
4145     gst_value.type = gst_fraction_get_type ();
4146     gst_value_register (&gst_value);
4147   }
4148   {
4149     static GstValueTable gst_value = {
4150       0,
4151       NULL,
4152       gst_value_serialize_caps,
4153       gst_value_deserialize_caps,
4154     };
4155
4156     gst_value.type = GST_TYPE_CAPS;
4157     gst_value_register (&gst_value);
4158   }
4159   {
4160     static GstValueTable gst_value = {
4161       0,
4162       NULL,
4163       gst_value_serialize_structure,
4164       gst_value_deserialize_structure,
4165     };
4166
4167     gst_value.type = GST_TYPE_STRUCTURE;
4168     gst_value_register (&gst_value);
4169   }
4170   {
4171     static GstValueTable gst_value = {
4172       0,
4173       gst_value_compare_date,
4174       gst_value_serialize_date,
4175       gst_value_deserialize_date,
4176     };
4177
4178     gst_value.type = gst_date_get_type ();
4179     gst_value_register (&gst_value);
4180   }
4181
4182   REGISTER_SERIALIZATION (G_TYPE_DOUBLE, double);
4183   REGISTER_SERIALIZATION (G_TYPE_FLOAT, float);
4184
4185   REGISTER_SERIALIZATION (G_TYPE_STRING, string);
4186   REGISTER_SERIALIZATION (G_TYPE_BOOLEAN, boolean);
4187   REGISTER_SERIALIZATION (G_TYPE_ENUM, enum);
4188
4189   REGISTER_SERIALIZATION (G_TYPE_FLAGS, flags);
4190
4191   REGISTER_SERIALIZATION (G_TYPE_INT, int);
4192
4193   REGISTER_SERIALIZATION (G_TYPE_INT64, int64);
4194   REGISTER_SERIALIZATION (G_TYPE_LONG, long);
4195
4196   REGISTER_SERIALIZATION (G_TYPE_UINT, uint);
4197   REGISTER_SERIALIZATION (G_TYPE_UINT64, uint64);
4198   REGISTER_SERIALIZATION (G_TYPE_ULONG, ulong);
4199
4200   g_value_register_transform_func (GST_TYPE_FOURCC, G_TYPE_STRING,
4201       gst_value_transform_fourcc_string);
4202   g_value_register_transform_func (GST_TYPE_INT_RANGE, G_TYPE_STRING,
4203       gst_value_transform_int_range_string);
4204   g_value_register_transform_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_STRING,
4205       gst_value_transform_double_range_string);
4206   g_value_register_transform_func (GST_TYPE_FRACTION_RANGE, G_TYPE_STRING,
4207       gst_value_transform_fraction_range_string);
4208   g_value_register_transform_func (GST_TYPE_LIST, G_TYPE_STRING,
4209       gst_value_transform_list_string);
4210   g_value_register_transform_func (GST_TYPE_ARRAY, G_TYPE_STRING,
4211       gst_value_transform_array_string);
4212   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_STRING,
4213       gst_value_transform_fraction_string);
4214   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_FRACTION,
4215       gst_value_transform_string_fraction);
4216   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_DOUBLE,
4217       gst_value_transform_fraction_double);
4218   g_value_register_transform_func (G_TYPE_DOUBLE, GST_TYPE_FRACTION,
4219       gst_value_transform_double_fraction);
4220   g_value_register_transform_func (GST_TYPE_DATE, G_TYPE_STRING,
4221       gst_value_transform_date_string);
4222   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_DATE,
4223       gst_value_transform_string_date);
4224   g_value_register_transform_func (GST_TYPE_OBJECT, G_TYPE_STRING,
4225       gst_value_transform_object_string);
4226
4227   gst_value_register_intersect_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
4228       gst_value_intersect_int_int_range);
4229   gst_value_register_intersect_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
4230       gst_value_intersect_int_range_int_range);
4231   gst_value_register_intersect_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
4232       gst_value_intersect_double_double_range);
4233   gst_value_register_intersect_func (GST_TYPE_DOUBLE_RANGE,
4234       GST_TYPE_DOUBLE_RANGE, gst_value_intersect_double_range_double_range);
4235   gst_value_register_intersect_func (GST_TYPE_ARRAY,
4236       GST_TYPE_ARRAY, gst_value_intersect_array);
4237   gst_value_register_intersect_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
4238       gst_value_intersect_fraction_fraction_range);
4239   gst_value_register_intersect_func (GST_TYPE_FRACTION_RANGE,
4240       GST_TYPE_FRACTION_RANGE,
4241       gst_value_intersect_fraction_range_fraction_range);
4242
4243   gst_value_register_subtract_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
4244       gst_value_subtract_int_int_range);
4245   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, G_TYPE_INT,
4246       gst_value_subtract_int_range_int);
4247   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
4248       gst_value_subtract_int_range_int_range);
4249   gst_value_register_subtract_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
4250       gst_value_subtract_double_double_range);
4251   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_DOUBLE,
4252       gst_value_subtract_double_range_double);
4253   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE,
4254       GST_TYPE_DOUBLE_RANGE, gst_value_subtract_double_range_double_range);
4255
4256   gst_value_register_subtract_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
4257       gst_value_subtract_fraction_fraction_range);
4258   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE, GST_TYPE_FRACTION,
4259       gst_value_subtract_fraction_range_fraction);
4260   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE,
4261       GST_TYPE_FRACTION_RANGE,
4262       gst_value_subtract_fraction_range_fraction_range);
4263
4264   /* see bug #317246, #64994, #65041 */
4265   {
4266     volatile GType date_type = G_TYPE_DATE;
4267
4268     g_type_name (date_type);
4269   }
4270
4271   gst_value_register_union_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
4272       gst_value_union_int_int_range);
4273   gst_value_register_union_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
4274       gst_value_union_int_range_int_range);
4275
4276 #if 0
4277   /* Implement these if needed */
4278   gst_value_register_union_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
4279       gst_value_union_fraction_fraction_range);
4280   gst_value_register_union_func (GST_TYPE_FRACTION_RANGE,
4281       GST_TYPE_FRACTION_RANGE, gst_value_union_fraction_range_fraction_range);
4282 #endif
4283 }