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