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