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