gst/: Remove pre glib2.8 compatibility, fixes #340508
[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   result = g_strdup ("");
1923   flags = g_value_get_flags (value);
1924   while (flags) {
1925     fl = gst_flags_get_first_value (klass, flags);
1926     if (fl != NULL) {
1927       tmp = g_strconcat (result, (first ? "" : "+"), fl->value_name, NULL);
1928       g_free (result);
1929       result = tmp;
1930       first = FALSE;
1931
1932       /* clear flag */
1933       flags &= ~fl->value;
1934     }
1935   }
1936   g_type_class_unref (klass);
1937
1938   return result;
1939 }
1940
1941 static gboolean
1942 gst_value_deserialize_flags (GValue * dest, const gchar * s)
1943 {
1944   GFlagsValue *fl;
1945   gchar *endptr = NULL;
1946   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (dest));
1947   gchar **split;
1948   guint flags;
1949   gint i;
1950
1951   g_return_val_if_fail (klass, FALSE);
1952
1953   /* split into parts delimited with + */
1954   split = g_strsplit (s, "+", 0);
1955
1956   flags = 0;
1957   i = 0;
1958   /* loop over each part */
1959   while (split[i]) {
1960     if (!(fl = g_flags_get_value_by_name (klass, split[i]))) {
1961       if (!(fl = g_flags_get_value_by_nick (klass, split[i]))) {
1962         gint val = strtol (split[i], &endptr, 0);
1963
1964         /* just or numeric value */
1965         if (endptr && *endptr == '\0') {
1966           flags |= val;
1967         }
1968       }
1969     }
1970     if (fl) {
1971       flags |= fl->value;
1972     }
1973     i++;
1974   }
1975   g_strfreev (split);
1976   g_type_class_unref (klass);
1977   g_value_set_flags (dest, flags);
1978
1979   return TRUE;
1980 }
1981
1982 /*********
1983  * union *
1984  *********/
1985
1986 static gboolean
1987 gst_value_union_int_int_range (GValue * dest, const GValue * src1,
1988     const GValue * src2)
1989 {
1990   if (src2->data[0].v_int <= src1->data[0].v_int &&
1991       src2->data[1].v_int >= src1->data[0].v_int) {
1992     gst_value_init_and_copy (dest, src2);
1993     return TRUE;
1994   }
1995   return FALSE;
1996 }
1997
1998 static gboolean
1999 gst_value_union_int_range_int_range (GValue * dest, const GValue * src1,
2000     const GValue * src2)
2001 {
2002   gint min;
2003   gint max;
2004
2005   min = MAX (src1->data[0].v_int, src2->data[0].v_int);
2006   max = MIN (src1->data[1].v_int, src2->data[1].v_int);
2007
2008   if (min <= max) {
2009     g_value_init (dest, GST_TYPE_INT_RANGE);
2010     gst_value_set_int_range (dest,
2011         MIN (src1->data[0].v_int, src2->data[0].v_int),
2012         MAX (src1->data[1].v_int, src2->data[1].v_int));
2013     return TRUE;
2014   }
2015
2016   return FALSE;
2017 }
2018
2019 /****************
2020  * intersection *
2021  ****************/
2022
2023 static gboolean
2024 gst_value_intersect_int_int_range (GValue * dest, const GValue * src1,
2025     const GValue * src2)
2026 {
2027   if (src2->data[0].v_int <= src1->data[0].v_int &&
2028       src2->data[1].v_int >= src1->data[0].v_int) {
2029     gst_value_init_and_copy (dest, src1);
2030     return TRUE;
2031   }
2032
2033   return FALSE;
2034 }
2035
2036 static gboolean
2037 gst_value_intersect_int_range_int_range (GValue * dest, const GValue * src1,
2038     const GValue * src2)
2039 {
2040   gint min;
2041   gint max;
2042
2043   min = MAX (src1->data[0].v_int, src2->data[0].v_int);
2044   max = MIN (src1->data[1].v_int, src2->data[1].v_int);
2045
2046   if (min < max) {
2047     g_value_init (dest, GST_TYPE_INT_RANGE);
2048     gst_value_set_int_range (dest, min, max);
2049     return TRUE;
2050   }
2051   if (min == max) {
2052     g_value_init (dest, G_TYPE_INT);
2053     g_value_set_int (dest, min);
2054     return TRUE;
2055   }
2056
2057   return FALSE;
2058 }
2059
2060 static gboolean
2061 gst_value_intersect_double_double_range (GValue * dest, const GValue * src1,
2062     const GValue * src2)
2063 {
2064   if (src2->data[0].v_double <= src1->data[0].v_double &&
2065       src2->data[1].v_double >= src1->data[0].v_double) {
2066     gst_value_init_and_copy (dest, src1);
2067     return TRUE;
2068   }
2069
2070   return FALSE;
2071 }
2072
2073 static gboolean
2074 gst_value_intersect_double_range_double_range (GValue * dest,
2075     const GValue * src1, const GValue * src2)
2076 {
2077   gdouble min;
2078   gdouble max;
2079
2080   min = MAX (src1->data[0].v_double, src2->data[0].v_double);
2081   max = MIN (src1->data[1].v_double, src2->data[1].v_double);
2082
2083   if (min < max) {
2084     g_value_init (dest, GST_TYPE_DOUBLE_RANGE);
2085     gst_value_set_double_range (dest, min, max);
2086     return TRUE;
2087   }
2088   if (min == max) {
2089     g_value_init (dest, G_TYPE_DOUBLE);
2090     g_value_set_int (dest, (int) min);
2091     return TRUE;
2092   }
2093
2094   return FALSE;
2095 }
2096
2097 static gboolean
2098 gst_value_intersect_list (GValue * dest, const GValue * value1,
2099     const GValue * value2)
2100 {
2101   guint i, size;
2102   GValue intersection = { 0, };
2103   gboolean ret = FALSE;
2104
2105   size = gst_value_list_get_size (value1);
2106   for (i = 0; i < size; i++) {
2107     const GValue *cur = gst_value_list_get_value (value1, i);
2108
2109     if (gst_value_intersect (&intersection, cur, value2)) {
2110       /* append value */
2111       if (!ret) {
2112         gst_value_init_and_copy (dest, &intersection);
2113         ret = TRUE;
2114       } else if (GST_VALUE_HOLDS_LIST (dest)) {
2115         gst_value_list_append_value (dest, &intersection);
2116       } else {
2117         GValue temp = { 0, };
2118
2119         gst_value_init_and_copy (&temp, dest);
2120         g_value_unset (dest);
2121         gst_value_list_concat (dest, &temp, &intersection);
2122         g_value_unset (&temp);
2123       }
2124       g_value_unset (&intersection);
2125     }
2126   }
2127
2128   return ret;
2129 }
2130
2131 static gboolean
2132 gst_value_intersect_array (GValue * dest, const GValue * src1,
2133     const GValue * src2)
2134 {
2135   guint size;
2136   guint n;
2137   GValue val = { 0 };
2138
2139   /* only works on similar-sized arrays */
2140   size = gst_value_array_get_size (src1);
2141   if (size != gst_value_array_get_size (src2))
2142     return FALSE;
2143   g_value_init (dest, GST_TYPE_ARRAY);
2144
2145   for (n = 0; n < size; n++) {
2146     if (!gst_value_intersect (&val, gst_value_array_get_value (src1, n),
2147             gst_value_array_get_value (src2, n))) {
2148       g_value_unset (dest);
2149       return FALSE;
2150     }
2151     gst_value_array_append_value (dest, &val);
2152     g_value_unset (&val);
2153   }
2154
2155   return TRUE;
2156 }
2157
2158 static gboolean
2159 gst_value_intersect_fraction_fraction_range (GValue * dest, const GValue * src1,
2160     const GValue * src2)
2161 {
2162   int res1, res2;
2163   GValue *vals;
2164
2165   vals = src2->data[0].v_pointer;
2166
2167   if (vals == NULL)
2168     return FALSE;
2169
2170   res1 = gst_value_compare (&vals[0], src1);
2171   res2 = gst_value_compare (&vals[1], src1);
2172
2173   if ((res1 == GST_VALUE_EQUAL || res1 == GST_VALUE_LESS_THAN) &&
2174       (res2 == GST_VALUE_EQUAL || res2 == GST_VALUE_GREATER_THAN)) {
2175     gst_value_init_and_copy (dest, src1);
2176     return TRUE;
2177   }
2178
2179   return FALSE;
2180 }
2181
2182 static gboolean
2183     gst_value_intersect_fraction_range_fraction_range
2184     (GValue * dest, const GValue * src1, const GValue * src2)
2185 {
2186   GValue *min;
2187   GValue *max;
2188   int res;
2189   GValue *vals1, *vals2;
2190
2191   vals1 = src1->data[0].v_pointer;
2192   vals2 = src2->data[0].v_pointer;
2193   g_return_val_if_fail (vals1 != NULL && vals2 != NULL, FALSE);
2194
2195   /* min = MAX (src1.start, src2.start) */
2196   res = gst_value_compare (&vals1[0], &vals2[0]);
2197   g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
2198   if (res == GST_VALUE_LESS_THAN)
2199     min = &vals2[0];            /* Take the max of the 2 */
2200   else
2201     min = &vals1[0];
2202
2203   /* max = MIN (src1.end, src2.end) */
2204   res = gst_value_compare (&vals1[1], &vals2[1]);
2205   g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
2206   if (res == GST_VALUE_GREATER_THAN)
2207     max = &vals2[1];            /* Take the min of the 2 */
2208   else
2209     max = &vals1[1];
2210
2211   res = gst_value_compare (min, max);
2212   g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
2213   if (res == GST_VALUE_LESS_THAN) {
2214     g_value_init (dest, GST_TYPE_FRACTION_RANGE);
2215     vals1 = dest->data[0].v_pointer;
2216     g_value_copy (min, &vals1[0]);
2217     g_value_copy (max, &vals1[1]);
2218     return TRUE;
2219   }
2220   if (res == GST_VALUE_EQUAL) {
2221     gst_value_init_and_copy (dest, min);
2222     return TRUE;
2223   }
2224
2225   return FALSE;
2226 }
2227
2228 /***************
2229  * subtraction *
2230  ***************/
2231
2232 static gboolean
2233 gst_value_subtract_int_int_range (GValue * dest, const GValue * minuend,
2234     const GValue * subtrahend)
2235 {
2236   int min = gst_value_get_int_range_min (subtrahend);
2237   int max = gst_value_get_int_range_max (subtrahend);
2238   int val = g_value_get_int (minuend);
2239
2240   /* subtracting a range from an int only works if the int is not in the
2241    * range */
2242   if (val < min || val > max) {
2243     /* and the result is the int */
2244     gst_value_init_and_copy (dest, minuend);
2245     return TRUE;
2246   }
2247   return FALSE;
2248 }
2249
2250 /* creates a new int range based on input values.
2251  */
2252 static gboolean
2253 gst_value_create_new_range (GValue * dest, gint min1, gint max1, gint min2,
2254     gint max2)
2255 {
2256   GValue v1 = { 0, };
2257   GValue v2 = { 0, };
2258   GValue *pv1, *pv2;            /* yeah, hungarian! */
2259
2260   if (min1 <= max1 && min2 <= max2) {
2261     pv1 = &v1;
2262     pv2 = &v2;
2263   } else if (min1 <= max1) {
2264     pv1 = dest;
2265     pv2 = NULL;
2266   } else if (min2 <= max2) {
2267     pv1 = NULL;
2268     pv2 = dest;
2269   } else {
2270     return FALSE;
2271   }
2272
2273   if (min1 < max1) {
2274     g_value_init (pv1, GST_TYPE_INT_RANGE);
2275     gst_value_set_int_range (pv1, min1, max1);
2276   } else if (min1 == max1) {
2277     g_value_init (pv1, G_TYPE_INT);
2278     g_value_set_int (pv1, min1);
2279   }
2280   if (min2 < max2) {
2281     g_value_init (pv2, GST_TYPE_INT_RANGE);
2282     gst_value_set_int_range (pv2, min2, max2);
2283   } else if (min2 == max2) {
2284     g_value_init (pv2, G_TYPE_INT);
2285     g_value_set_int (pv2, min2);
2286   }
2287
2288   if (min1 <= max1 && min2 <= max2) {
2289     gst_value_list_concat (dest, pv1, pv2);
2290     g_value_unset (pv1);
2291     g_value_unset (pv2);
2292   }
2293   return TRUE;
2294 }
2295
2296 static gboolean
2297 gst_value_subtract_int_range_int (GValue * dest, const GValue * minuend,
2298     const GValue * subtrahend)
2299 {
2300   gint min = gst_value_get_int_range_min (minuend);
2301   gint max = gst_value_get_int_range_max (minuend);
2302   gint val = g_value_get_int (subtrahend);
2303
2304   g_return_val_if_fail (min < max, FALSE);
2305
2306   /* value is outside of the range, return range unchanged */
2307   if (val < min || val > max) {
2308     gst_value_init_and_copy (dest, minuend);
2309     return TRUE;
2310   } else {
2311     /* max must be MAXINT too as val <= max */
2312     if (val == G_MAXINT) {
2313       max--;
2314       val--;
2315     }
2316     /* min must be MININT too as val >= max */
2317     if (val == G_MININT) {
2318       min++;
2319       val++;
2320     }
2321     gst_value_create_new_range (dest, min, val - 1, val + 1, max);
2322   }
2323   return TRUE;
2324 }
2325
2326 static gboolean
2327 gst_value_subtract_int_range_int_range (GValue * dest, const GValue * minuend,
2328     const GValue * subtrahend)
2329 {
2330   gint min1 = gst_value_get_int_range_min (minuend);
2331   gint max1 = gst_value_get_int_range_max (minuend);
2332   gint min2 = gst_value_get_int_range_min (subtrahend);
2333   gint max2 = gst_value_get_int_range_max (subtrahend);
2334
2335   if (max2 == G_MAXINT && min2 == G_MININT) {
2336     return FALSE;
2337   } else if (max2 == G_MAXINT) {
2338     return gst_value_create_new_range (dest, min1, MIN (min2 - 1, max1), 1, 0);
2339   } else if (min2 == G_MININT) {
2340     return gst_value_create_new_range (dest, MAX (max2 + 1, min1), max1, 1, 0);
2341   } else {
2342     return gst_value_create_new_range (dest, min1, MIN (min2 - 1, max1),
2343         MAX (max2 + 1, min1), max1);
2344   }
2345 }
2346
2347 static gboolean
2348 gst_value_subtract_double_double_range (GValue * dest, const GValue * minuend,
2349     const GValue * subtrahend)
2350 {
2351   gdouble min = gst_value_get_double_range_min (subtrahend);
2352   gdouble max = gst_value_get_double_range_max (subtrahend);
2353   gdouble val = g_value_get_double (minuend);
2354
2355   if (val < min || val > max) {
2356     gst_value_init_and_copy (dest, minuend);
2357     return TRUE;
2358   }
2359   return FALSE;
2360 }
2361
2362 static gboolean
2363 gst_value_subtract_double_range_double (GValue * dest, const GValue * minuend,
2364     const GValue * subtrahend)
2365 {
2366   /* since we don't have open ranges, we cannot create a hole in
2367    * a double range. We return the original range */
2368   gst_value_init_and_copy (dest, minuend);
2369   return TRUE;
2370 }
2371
2372 static gboolean
2373 gst_value_subtract_double_range_double_range (GValue * dest,
2374     const GValue * minuend, const GValue * subtrahend)
2375 {
2376   /* since we don't have open ranges, we have to approximate */
2377   /* done like with ints */
2378   gdouble min1 = gst_value_get_double_range_min (minuend);
2379   gdouble max2 = gst_value_get_double_range_max (minuend);
2380   gdouble max1 = MIN (gst_value_get_double_range_min (subtrahend), max2);
2381   gdouble min2 = MAX (gst_value_get_double_range_max (subtrahend), min1);
2382   GValue v1 = { 0, };
2383   GValue v2 = { 0, };
2384   GValue *pv1, *pv2;            /* yeah, hungarian! */
2385
2386   if (min1 < max1 && min2 < max2) {
2387     pv1 = &v1;
2388     pv2 = &v2;
2389   } else if (min1 < max1) {
2390     pv1 = dest;
2391     pv2 = NULL;
2392   } else if (min2 < max2) {
2393     pv1 = NULL;
2394     pv2 = dest;
2395   } else {
2396     return FALSE;
2397   }
2398
2399   if (min1 < max1) {
2400     g_value_init (pv1, GST_TYPE_DOUBLE_RANGE);
2401     gst_value_set_double_range (pv1, min1, max1);
2402   }
2403   if (min2 < max2) {
2404     g_value_init (pv2, GST_TYPE_DOUBLE_RANGE);
2405     gst_value_set_double_range (pv2, min2, max2);
2406   }
2407
2408   if (min1 < max1 && min2 < max2) {
2409     gst_value_list_concat (dest, pv1, pv2);
2410     g_value_unset (pv1);
2411     g_value_unset (pv2);
2412   }
2413   return TRUE;
2414 }
2415
2416 static gboolean
2417 gst_value_subtract_from_list (GValue * dest, const GValue * minuend,
2418     const GValue * subtrahend)
2419 {
2420   guint i, size;
2421   GValue subtraction = { 0, };
2422   gboolean ret = FALSE;
2423
2424   size = gst_value_list_get_size (minuend);
2425   for (i = 0; i < size; i++) {
2426     const GValue *cur = gst_value_list_get_value (minuend, i);
2427
2428     if (gst_value_subtract (&subtraction, cur, subtrahend)) {
2429       if (!ret) {
2430         gst_value_init_and_copy (dest, &subtraction);
2431         ret = TRUE;
2432       } else if (GST_VALUE_HOLDS_LIST (dest)
2433           && GST_VALUE_HOLDS_LIST (&subtraction)) {
2434         /* unroll */
2435         GValue unroll = { 0, };
2436
2437         gst_value_init_and_copy (&unroll, dest);
2438         g_value_unset (dest);
2439         gst_value_list_concat (dest, &unroll, &subtraction);
2440       } else if (GST_VALUE_HOLDS_LIST (dest)) {
2441         gst_value_list_append_value (dest, &subtraction);
2442       } else {
2443         GValue temp = { 0, };
2444
2445         gst_value_init_and_copy (&temp, dest);
2446         g_value_unset (dest);
2447         gst_value_list_concat (dest, &temp, &subtraction);
2448         g_value_unset (&temp);
2449       }
2450       g_value_unset (&subtraction);
2451     }
2452   }
2453   return ret;
2454 }
2455
2456 static gboolean
2457 gst_value_subtract_list (GValue * dest, const GValue * minuend,
2458     const GValue * subtrahend)
2459 {
2460   guint i, size;
2461   GValue data[2] = { {0,}, {0,} };
2462   GValue *subtraction = &data[0], *result = &data[1];
2463
2464   gst_value_init_and_copy (result, minuend);
2465   size = gst_value_list_get_size (subtrahend);
2466   for (i = 0; i < size; i++) {
2467     const GValue *cur = gst_value_list_get_value (subtrahend, i);
2468
2469     if (gst_value_subtract (subtraction, result, cur)) {
2470       GValue *temp = result;
2471
2472       result = subtraction;
2473       subtraction = temp;
2474       g_value_unset (subtraction);
2475     } else {
2476       g_value_unset (result);
2477       return FALSE;
2478     }
2479   }
2480   gst_value_init_and_copy (dest, result);
2481   g_value_unset (result);
2482   return TRUE;
2483 }
2484
2485 static gboolean
2486 gst_value_subtract_fraction_fraction_range (GValue * dest,
2487     const GValue * minuend, const GValue * subtrahend)
2488 {
2489   const GValue *min = gst_value_get_fraction_range_min (subtrahend);
2490   const GValue *max = gst_value_get_fraction_range_max (subtrahend);
2491
2492   /* subtracting a range from an fraction only works if the fraction
2493    * is not in the range */
2494   if (gst_value_compare (minuend, min) == GST_VALUE_LESS_THAN ||
2495       gst_value_compare (minuend, max) == GST_VALUE_GREATER_THAN) {
2496     /* and the result is the value */
2497     gst_value_init_and_copy (dest, minuend);
2498     return TRUE;
2499   }
2500   return FALSE;
2501 }
2502
2503 static gboolean
2504 gst_value_subtract_fraction_range_fraction (GValue * dest,
2505     const GValue * minuend, const GValue * subtrahend)
2506 {
2507   /* since we don't have open ranges, we cannot create a hole in
2508    * a range. We return the original range */
2509   gst_value_init_and_copy (dest, minuend);
2510   return TRUE;
2511 }
2512
2513 static gboolean
2514 gst_value_subtract_fraction_range_fraction_range (GValue * dest,
2515     const GValue * minuend, const GValue * subtrahend)
2516 {
2517   /* since we don't have open ranges, we have to approximate */
2518   /* done like with ints and doubles. Creates a list of 2 fraction ranges */
2519   const GValue *min1 = gst_value_get_fraction_range_min (minuend);
2520   const GValue *max2 = gst_value_get_fraction_range_max (minuend);
2521   const GValue *max1 = gst_value_get_fraction_range_min (subtrahend);
2522   const GValue *min2 = gst_value_get_fraction_range_max (subtrahend);
2523   int cmp1, cmp2;
2524   GValue v1 = { 0, };
2525   GValue v2 = { 0, };
2526   GValue *pv1, *pv2;            /* yeah, hungarian! */
2527
2528   g_return_val_if_fail (min1 != NULL && max1 != NULL, FALSE);
2529   g_return_val_if_fail (min2 != NULL && max2 != NULL, FALSE);
2530
2531   cmp1 = gst_value_compare (max2, max1);
2532   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
2533   if (cmp1 == GST_VALUE_LESS_THAN)
2534     max1 = max2;
2535   cmp1 = gst_value_compare (min1, min2);
2536   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
2537   if (cmp1 == GST_VALUE_GREATER_THAN)
2538     min2 = min1;
2539
2540   cmp1 = gst_value_compare (min1, max1);
2541   cmp2 = gst_value_compare (min2, max2);
2542
2543   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
2544     pv1 = &v1;
2545     pv2 = &v2;
2546   } else if (cmp1 == GST_VALUE_LESS_THAN) {
2547     pv1 = dest;
2548     pv2 = NULL;
2549   } else if (cmp2 == GST_VALUE_LESS_THAN) {
2550     pv1 = NULL;
2551     pv2 = dest;
2552   } else {
2553     return FALSE;
2554   }
2555
2556   if (cmp1 == GST_VALUE_LESS_THAN) {
2557     g_value_init (pv1, GST_TYPE_FRACTION_RANGE);
2558     gst_value_set_fraction_range (pv1, min1, max1);
2559   }
2560   if (cmp2 == GST_VALUE_LESS_THAN) {
2561     g_value_init (pv2, GST_TYPE_FRACTION_RANGE);
2562     gst_value_set_fraction_range (pv2, min2, max2);
2563   }
2564
2565   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
2566     gst_value_list_concat (dest, pv1, pv2);
2567     g_value_unset (pv1);
2568     g_value_unset (pv2);
2569   }
2570   return TRUE;
2571 }
2572
2573
2574 /**************
2575  * comparison *
2576  **************/
2577
2578 /**
2579  * gst_value_can_compare:
2580  * @value1: a value to compare
2581  * @value2: another value to compare
2582  *
2583  * Determines if @value1 and @value2 can be compared.
2584  *
2585  * Returns: TRUE if the values can be compared
2586  */
2587 gboolean
2588 gst_value_can_compare (const GValue * value1, const GValue * value2)
2589 {
2590   GstValueTable *table;
2591   guint i;
2592
2593   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
2594     return FALSE;
2595
2596   for (i = 0; i < gst_value_table->len; i++) {
2597     table = &g_array_index (gst_value_table, GstValueTable, i);
2598     if (g_type_is_a (G_VALUE_TYPE (value1), table->type) && table->compare)
2599       return TRUE;
2600   }
2601
2602   return FALSE;
2603 }
2604
2605 /**
2606  * gst_value_compare:
2607  * @value1: a value to compare
2608  * @value2: another value to compare
2609  *
2610  * Compares @value1 and @value2.  If @value1 and @value2 cannot be
2611  * compared, the function returns GST_VALUE_UNORDERED.  Otherwise,
2612  * if @value1 is greater than @value2, GST_VALUE_GREATER is returned.
2613  * If @value1 is less than @value2, GST_VALUE_LESSER is returned.
2614  * If the values are equal, GST_VALUE_EQUAL is returned.
2615  *
2616  * Returns: A GstValueCompareType value
2617  */
2618 int
2619 gst_value_compare (const GValue * value1, const GValue * value2)
2620 {
2621   GstValueTable *table, *best = NULL;
2622   guint i;
2623
2624   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
2625     return GST_VALUE_UNORDERED;
2626
2627   for (i = 0; i < gst_value_table->len; i++) {
2628     table = &g_array_index (gst_value_table, GstValueTable, i);
2629     if (table->type == G_VALUE_TYPE (value1) && table->compare != NULL) {
2630       best = table;
2631       break;
2632     }
2633     if (g_type_is_a (G_VALUE_TYPE (value1), table->type)) {
2634       if (!best || g_type_is_a (table->type, best->type))
2635         best = table;
2636     }
2637   }
2638   if (best) {
2639     return best->compare (value1, value2);
2640   }
2641
2642   g_critical ("unable to compare values of type %s\n",
2643       g_type_name (G_VALUE_TYPE (value1)));
2644   return GST_VALUE_UNORDERED;
2645 }
2646
2647 /* union */
2648
2649 /**
2650  * gst_value_can_union:
2651  * @value1: a value to union
2652  * @value2: another value to union
2653  *
2654  * Determines if @value1 and @value2 can be non-trivially unioned.
2655  * Any two values can be trivially unioned by adding both of them
2656  * to a GstValueList.  However, certain types have the possibility
2657  * to be unioned in a simpler way.  For example, an integer range
2658  * and an integer can be unioned if the integer is a subset of the
2659  * integer range.  If there is the possibility that two values can
2660  * be unioned, this function returns TRUE.
2661  *
2662  * Returns: TRUE if there is a function allowing the two values to
2663  * be unioned.
2664  */
2665 gboolean
2666 gst_value_can_union (const GValue * value1, const GValue * value2)
2667 {
2668   GstValueUnionInfo *union_info;
2669   guint i;
2670
2671   for (i = 0; i < gst_value_union_funcs->len; i++) {
2672     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
2673     if (union_info->type1 == G_VALUE_TYPE (value1) &&
2674         union_info->type2 == G_VALUE_TYPE (value2))
2675       return TRUE;
2676     if (union_info->type1 == G_VALUE_TYPE (value2) &&
2677         union_info->type2 == G_VALUE_TYPE (value1))
2678       return TRUE;
2679   }
2680
2681   return FALSE;
2682 }
2683
2684 /**
2685  * gst_value_union:
2686  * @dest: the destination value
2687  * @value1: a value to union
2688  * @value2: another value to union
2689  *
2690  * Creates a GValue cooresponding to the union of @value1 and @value2.
2691  *
2692  * Returns: always returns %TRUE
2693  */
2694 /* FIXME: change return type to 'void'? */
2695 gboolean
2696 gst_value_union (GValue * dest, const GValue * value1, const GValue * value2)
2697 {
2698   GstValueUnionInfo *union_info;
2699   guint i;
2700
2701   for (i = 0; i < gst_value_union_funcs->len; i++) {
2702     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
2703     if (union_info->type1 == G_VALUE_TYPE (value1) &&
2704         union_info->type2 == G_VALUE_TYPE (value2)) {
2705       if (union_info->func (dest, value1, value2)) {
2706         return TRUE;
2707       }
2708     }
2709     if (union_info->type1 == G_VALUE_TYPE (value2) &&
2710         union_info->type2 == G_VALUE_TYPE (value1)) {
2711       if (union_info->func (dest, value2, value1)) {
2712         return TRUE;
2713       }
2714     }
2715   }
2716
2717   gst_value_list_concat (dest, value1, value2);
2718   return TRUE;
2719 }
2720
2721 /**
2722  * gst_value_register_union_func:
2723  * @type1: a type to union
2724  * @type2: another type to union
2725  * @func: a function that implments creating a union between the two types
2726  *
2727  * Registers a union function that can create a union between GValues
2728  * of the type @type1 and @type2.
2729  *
2730  * Union functions should be registered at startup before any pipelines are
2731  * started, as gst_value_register_union_func() is not thread-safe and cannot
2732  * be used at the same time as gst_value_union() or gst_value_can_union().
2733  */
2734 void
2735 gst_value_register_union_func (GType type1, GType type2, GstValueUnionFunc func)
2736 {
2737   GstValueUnionInfo union_info;
2738
2739   union_info.type1 = type1;
2740   union_info.type2 = type2;
2741   union_info.func = func;
2742
2743   g_array_append_val (gst_value_union_funcs, union_info);
2744 }
2745
2746 /* intersection */
2747
2748 /**
2749  * gst_value_can_intersect:
2750  * @value1: a value to intersect
2751  * @value2: another value to intersect
2752  *
2753  * Determines if intersecting two values will produce a valid result.
2754  * Two values will produce a valid intersection if they have the same
2755  * type, or if there is a method (registered by
2756  * gst_value_register_intersection_func()) to calculate the intersection.
2757  *
2758  * Returns: TRUE if the values can intersect
2759  */
2760 gboolean
2761 gst_value_can_intersect (const GValue * value1, const GValue * value2)
2762 {
2763   GstValueIntersectInfo *intersect_info;
2764   guint i;
2765
2766   /* special cases */
2767   if (GST_VALUE_HOLDS_LIST (value1) || GST_VALUE_HOLDS_LIST (value2))
2768     return TRUE;
2769
2770   for (i = 0; i < gst_value_intersect_funcs->len; i++) {
2771     intersect_info = &g_array_index (gst_value_intersect_funcs,
2772         GstValueIntersectInfo, i);
2773     if (intersect_info->type1 == G_VALUE_TYPE (value1) &&
2774         intersect_info->type2 == G_VALUE_TYPE (value2))
2775       if (intersect_info->type2 == G_VALUE_TYPE (value1) &&
2776           intersect_info->type1 == G_VALUE_TYPE (value2))
2777         return TRUE;
2778   }
2779
2780   return gst_value_can_compare (value1, value2);
2781 }
2782
2783 /**
2784  * gst_value_intersect:
2785  * @dest: a uninitialized #GValue that will hold the calculated
2786  * intersection value
2787  * @value1: a value to intersect
2788  * @value2: another value to intersect
2789  *
2790  * Calculates the intersection of two values.  If the values have
2791  * a non-empty intersection, the value representing the intersection
2792  * is placed in @dest.  If the intersection is non-empty, @dest is
2793  * not modified.
2794  *
2795  * Returns: TRUE if the intersection is non-empty
2796  */
2797 gboolean
2798 gst_value_intersect (GValue * dest, const GValue * value1,
2799     const GValue * value2)
2800 {
2801   GstValueIntersectInfo *intersect_info;
2802   guint i;
2803   gboolean ret = FALSE;
2804
2805   /* special cases first */
2806   if (GST_VALUE_HOLDS_LIST (value1))
2807     return gst_value_intersect_list (dest, value1, value2);
2808   if (GST_VALUE_HOLDS_LIST (value2))
2809     return gst_value_intersect_list (dest, value2, value1);
2810
2811   for (i = 0; i < gst_value_intersect_funcs->len; i++) {
2812     intersect_info = &g_array_index (gst_value_intersect_funcs,
2813         GstValueIntersectInfo, i);
2814     if (intersect_info->type1 == G_VALUE_TYPE (value1) &&
2815         intersect_info->type2 == G_VALUE_TYPE (value2)) {
2816       ret = intersect_info->func (dest, value1, value2);
2817       return ret;
2818     }
2819     if (intersect_info->type1 == G_VALUE_TYPE (value2) &&
2820         intersect_info->type2 == G_VALUE_TYPE (value1)) {
2821       ret = intersect_info->func (dest, value2, value1);
2822       return ret;
2823     }
2824   }
2825
2826   if (gst_value_compare (value1, value2) == GST_VALUE_EQUAL) {
2827     gst_value_init_and_copy (dest, value1);
2828     ret = TRUE;
2829   }
2830
2831   return ret;
2832 }
2833
2834 /**
2835  * gst_value_register_intersect_func:
2836  * @type1: the first type to intersect
2837  * @type2: the second type to intersect
2838  * @func: the intersection function
2839  *
2840  * Registers a function that is called to calculate the intersection
2841  * of the values having the types @type1 and @type2.
2842  *
2843  * Intersect functions should be registered at startup before any pipelines are
2844  * started, as gst_value_register_intersect_func() is not thread-safe and
2845  * cannot be used at the same time as gst_value_intersect() or
2846  * gst_value_can_intersect().
2847  */
2848 void
2849 gst_value_register_intersect_func (GType type1, GType type2,
2850     GstValueIntersectFunc func)
2851 {
2852   GstValueIntersectInfo intersect_info;
2853
2854   intersect_info.type1 = type1;
2855   intersect_info.type2 = type2;
2856   intersect_info.func = func;
2857
2858   g_array_append_val (gst_value_intersect_funcs, intersect_info);
2859 }
2860
2861
2862 /* subtraction */
2863
2864 /**
2865  * gst_value_subtract:
2866  * @dest: the destination value for the result if the subtraction is not empty
2867  * @minuend: the value to subtract from
2868  * @subtrahend: the value to subtract
2869  *
2870  * Subtracts @subtrahend from @minuend and stores the result in @dest.
2871  * Note that this means subtraction as in sets, not as in mathematics.
2872  *
2873  * Returns: %TRUE if the subtraction is not empty
2874  */
2875 gboolean
2876 gst_value_subtract (GValue * dest, const GValue * minuend,
2877     const GValue * subtrahend)
2878 {
2879   GstValueSubtractInfo *info;
2880   guint i;
2881
2882   /* special cases first */
2883   if (GST_VALUE_HOLDS_LIST (minuend))
2884     return gst_value_subtract_from_list (dest, minuend, subtrahend);
2885   if (GST_VALUE_HOLDS_LIST (subtrahend))
2886     return gst_value_subtract_list (dest, minuend, subtrahend);
2887
2888   for (i = 0; i < gst_value_subtract_funcs->len; i++) {
2889     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
2890     if (info->minuend == G_VALUE_TYPE (minuend) &&
2891         info->subtrahend == G_VALUE_TYPE (subtrahend)) {
2892       return info->func (dest, minuend, subtrahend);
2893     }
2894   }
2895
2896   if (gst_value_compare (minuend, subtrahend) != GST_VALUE_EQUAL) {
2897     gst_value_init_and_copy (dest, minuend);
2898     return TRUE;
2899   }
2900
2901   return FALSE;
2902 }
2903
2904 #if 0
2905 gboolean
2906 gst_value_subtract (GValue * dest, const GValue * minuend,
2907     const GValue * subtrahend)
2908 {
2909   gboolean ret = gst_value_subtract2 (dest, minuend, subtrahend);
2910
2911   g_printerr ("\"%s\"  -  \"%s\"  =  \"%s\"\n", gst_value_serialize (minuend),
2912       gst_value_serialize (subtrahend),
2913       ret ? gst_value_serialize (dest) : "---");
2914   return ret;
2915 }
2916 #endif
2917
2918 /**
2919  * gst_value_can_subtract:
2920  * @minuend: the value to subtract from
2921  * @subtrahend: the value to subtract
2922  *
2923  * Checks if it's possible to subtract @subtrahend from @minuend.
2924  *
2925  * Returns: TRUE if a subtraction is possible
2926  */
2927 gboolean
2928 gst_value_can_subtract (const GValue * minuend, const GValue * subtrahend)
2929 {
2930   GstValueSubtractInfo *info;
2931   guint i;
2932
2933   /* special cases */
2934   if (GST_VALUE_HOLDS_LIST (minuend) || GST_VALUE_HOLDS_LIST (subtrahend))
2935     return TRUE;
2936
2937   for (i = 0; i < gst_value_subtract_funcs->len; i++) {
2938     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
2939     if (info->minuend == G_VALUE_TYPE (minuend) &&
2940         info->subtrahend == G_VALUE_TYPE (subtrahend))
2941       return TRUE;
2942   }
2943
2944   return gst_value_can_compare (minuend, subtrahend);
2945 }
2946
2947 /**
2948  * gst_value_register_subtract_func:
2949  * @minuend_type: type of the minuend
2950  * @subtrahend_type: type of the subtrahend
2951  * @func: function to use
2952  *
2953  * Registers @func as a function capable of subtracting the values of
2954  * @subtrahend_type from values of @minuend_type.
2955  *
2956  * Subtract functions should be registered at startup before any pipelines are
2957  * started, as gst_value_register_subtract_func() is not thread-safe and
2958  * cannot be used at the same time as gst_value_subtract().
2959  */
2960 void
2961 gst_value_register_subtract_func (GType minuend_type, GType subtrahend_type,
2962     GstValueSubtractFunc func)
2963 {
2964   GstValueSubtractInfo info;
2965
2966   /* one type must be unfixed, other subtractions can be done as comparisons */
2967   g_return_if_fail (!gst_type_is_fixed (minuend_type)
2968       || !gst_type_is_fixed (subtrahend_type));
2969
2970   info.minuend = minuend_type;
2971   info.subtrahend = subtrahend_type;
2972   info.func = func;
2973
2974   g_array_append_val (gst_value_subtract_funcs, info);
2975 }
2976
2977 /**
2978  * gst_value_register:
2979  * @table: structure containing functions to register
2980  *
2981  * Registers functions to perform calculations on #GValues of a given
2982  * type.
2983  */
2984 /**
2985  * GstValueTable:
2986  * @type: GType that the functions operate on.
2987  * @compare: A function that compares two values of this type.
2988  * @serialize: A function that transforms a value of this type to a
2989  * string.  Strings created by this function must be unique and should
2990  * be human readable.
2991  * @deserialize: A function that transforms a string to a value of
2992  * this type.  This function must transform strings created by the
2993  * serialize function back to the original value.  This function may
2994  * optionally transform other strings into values.
2995  */
2996 void
2997 gst_value_register (const GstValueTable * table)
2998 {
2999   g_array_append_val (gst_value_table, *table);
3000 }
3001
3002 /**
3003  * gst_value_init_and_copy:
3004  * @dest: the target value
3005  * @src: the source value
3006  *
3007  * Initialises the target value to be of the same type as source and then copies
3008  * the contents from source to target.
3009  */
3010 void
3011 gst_value_init_and_copy (GValue * dest, const GValue * src)
3012 {
3013   g_value_init (dest, G_VALUE_TYPE (src));
3014   g_value_copy (src, dest);
3015 }
3016
3017 /**
3018  * gst_value_serialize:
3019  * @value: a #GValue to serialize
3020  *
3021  * tries to transform the given @value into a string representation that allows
3022  * getting back this string later on using gst_value_deserialize().
3023  *
3024  * Returns: the serialization for @value or NULL if none exists
3025  */
3026 gchar *
3027 gst_value_serialize (const GValue * value)
3028 {
3029   guint i;
3030   GValue s_val = { 0 };
3031   GstValueTable *table, *best = NULL;
3032   char *s;
3033
3034   g_return_val_if_fail (G_IS_VALUE (value), NULL);
3035
3036   for (i = 0; i < gst_value_table->len; i++) {
3037     table = &g_array_index (gst_value_table, GstValueTable, i);
3038     if (table->serialize == NULL)
3039       continue;
3040     if (table->type == G_VALUE_TYPE (value)) {
3041       best = table;
3042       break;
3043     }
3044     if (g_type_is_a (G_VALUE_TYPE (value), table->type)) {
3045       if (!best || g_type_is_a (table->type, best->type))
3046         best = table;
3047     }
3048   }
3049   if (best)
3050     return best->serialize (value);
3051
3052   g_value_init (&s_val, G_TYPE_STRING);
3053   if (g_value_transform (value, &s_val)) {
3054     s = gst_string_wrap (g_value_get_string (&s_val));
3055   } else {
3056     s = NULL;
3057   }
3058   g_value_unset (&s_val);
3059
3060   return s;
3061 }
3062
3063 /**
3064  * gst_value_deserialize:
3065  * @dest: #GValue to fill with contents of deserialization
3066  * @src: string to deserialize
3067  *
3068  * Tries to deserialize a string into the type specified by the given GValue.
3069  * If the operation succeeds, TRUE is returned, FALSE otherwise.
3070  *
3071  * Returns: TRUE on success
3072  */
3073 gboolean
3074 gst_value_deserialize (GValue * dest, const gchar * src)
3075 {
3076   GstValueTable *table, *best = NULL;
3077   guint i;
3078
3079   g_return_val_if_fail (src != NULL, FALSE);
3080   g_return_val_if_fail (G_IS_VALUE (dest), FALSE);
3081
3082   for (i = 0; i < gst_value_table->len; i++) {
3083     table = &g_array_index (gst_value_table, GstValueTable, i);
3084     if (table->serialize == NULL)
3085       continue;
3086
3087     if (table->type == G_VALUE_TYPE (dest)) {
3088       best = table;
3089       break;
3090     }
3091
3092     if (g_type_is_a (G_VALUE_TYPE (dest), table->type)) {
3093       if (!best || g_type_is_a (table->type, best->type))
3094         best = table;
3095     }
3096   }
3097   if (best) {
3098     return best->deserialize (dest, src);
3099   }
3100
3101   return FALSE;
3102 }
3103
3104 /**
3105  * gst_value_is_fixed:
3106  * @value: the #GValue to check
3107  *
3108  * Tests if the given GValue, if available in a GstStructure (or any other
3109  * container) contains a "fixed" (which means: one value) or an "unfixed"
3110  * (which means: multiple possible values, such as data lists or data
3111  * ranges) value.
3112  *
3113  * Returns: true if the value is "fixed".
3114  */
3115
3116 gboolean
3117 gst_value_is_fixed (const GValue * value)
3118 {
3119   GType type = G_VALUE_TYPE (value);
3120
3121   if (type == GST_TYPE_ARRAY) {
3122     gboolean fixed = TRUE;
3123     gint size, n;
3124     const GValue *kid;
3125
3126     /* check recursively */
3127     size = gst_value_array_get_size (value);
3128     for (n = 0; n < size; n++) {
3129       kid = gst_value_array_get_value (value, n);
3130       fixed &= gst_value_is_fixed (kid);
3131     }
3132
3133     return fixed;
3134   }
3135
3136   return gst_type_is_fixed (type);
3137 }
3138
3139 /************
3140  * fraction *
3141  ************/
3142
3143 /* helper functions */
3144
3145 /* Finds the greatest common divisor.
3146  * Returns 1 if none other found.
3147  * This is Euclid's algorithm. */
3148 static gint
3149 gst_greatest_common_divisor (gint a, gint b)
3150 {
3151   while (b != 0) {
3152     int temp = a;
3153
3154     a = b;
3155     b = temp % b;
3156   }
3157
3158   return ABS (a);
3159 }
3160
3161 static void
3162 gst_value_init_fraction (GValue * value)
3163 {
3164   value->data[0].v_int = 0;
3165   value->data[1].v_int = 1;
3166 }
3167
3168 static void
3169 gst_value_copy_fraction (const GValue * src_value, GValue * dest_value)
3170 {
3171   dest_value->data[0].v_int = src_value->data[0].v_int;
3172   dest_value->data[1].v_int = src_value->data[1].v_int;
3173 }
3174
3175 static gchar *
3176 gst_value_collect_fraction (GValue * value, guint n_collect_values,
3177     GTypeCValue * collect_values, guint collect_flags)
3178 {
3179   gst_value_set_fraction (value,
3180       collect_values[0].v_int, collect_values[1].v_int);
3181
3182   return NULL;
3183 }
3184
3185 static gchar *
3186 gst_value_lcopy_fraction (const GValue * value, guint n_collect_values,
3187     GTypeCValue * collect_values, guint collect_flags)
3188 {
3189   gint *numerator = collect_values[0].v_pointer;
3190   gint *denominator = collect_values[1].v_pointer;
3191
3192   if (!numerator)
3193     return g_strdup_printf ("numerator for `%s' passed as NULL",
3194         G_VALUE_TYPE_NAME (value));
3195   if (!denominator)
3196     return g_strdup_printf ("denominator for `%s' passed as NULL",
3197         G_VALUE_TYPE_NAME (value));
3198
3199   *numerator = value->data[0].v_int;
3200   *denominator = value->data[1].v_int;
3201
3202   return NULL;
3203 }
3204
3205 /**
3206  * gst_value_set_fraction:
3207  * @value: a GValue initialized to #GST_TYPE_FRACTION
3208  * @numerator: the numerator of the fraction
3209  * @denominator: the denominator of the fraction
3210  *
3211  * Sets @value to the fraction specified by @numerator over @denominator.
3212  * The fraction gets reduced to the smallest numerator and denominator,
3213  * and if necessary the sign is moved to the numerator.
3214  */
3215 void
3216 gst_value_set_fraction (GValue * value, gint numerator, gint denominator)
3217 {
3218   gint gcd = 0;
3219
3220   g_return_if_fail (GST_VALUE_HOLDS_FRACTION (value));
3221   g_return_if_fail (denominator != 0);
3222   g_return_if_fail (denominator >= -G_MAXINT);
3223   g_return_if_fail (numerator >= -G_MAXINT);
3224
3225   /* normalize sign */
3226   if (denominator < 0) {
3227     numerator = -numerator;
3228     denominator = -denominator;
3229   }
3230
3231   /* check for reduction */
3232   gcd = gst_greatest_common_divisor (numerator, denominator);
3233   if (gcd) {
3234     numerator /= gcd;
3235     denominator /= gcd;
3236   }
3237
3238   g_assert (denominator > 0);
3239
3240   value->data[0].v_int = numerator;
3241   value->data[1].v_int = denominator;
3242 }
3243
3244 /**
3245  * gst_value_get_fraction_numerator:
3246  * @value: a GValue initialized to #GST_TYPE_FRACTION
3247  *
3248  * Gets the numerator of the fraction specified by @value.
3249  *
3250  * Returns: the numerator of the fraction.
3251  */
3252 gint
3253 gst_value_get_fraction_numerator (const GValue * value)
3254 {
3255   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 0);
3256
3257   return value->data[0].v_int;
3258 }
3259
3260 /**
3261  * gst_value_get_fraction_denominator:
3262  * @value: a GValue initialized to #GST_TYPE_FRACTION
3263  *
3264  * Gets the denominator of the fraction specified by @value.
3265  *
3266  * Returns: the denominator of the fraction.
3267  */
3268 gint
3269 gst_value_get_fraction_denominator (const GValue * value)
3270 {
3271   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 1);
3272
3273   return value->data[1].v_int;
3274 }
3275
3276 /**
3277  * gst_value_fraction_multiply:
3278  * @product: a GValue initialized to #GST_TYPE_FRACTION
3279  * @factor1: a GValue initialized to #GST_TYPE_FRACTION
3280  * @factor2: a GValue initialized to #GST_TYPE_FRACTION
3281  *
3282  * Multiplies the two GValues containing a GstFraction and sets @product
3283  * to the product of the two fractions.
3284  *
3285  * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise.
3286  */
3287 gboolean
3288 gst_value_fraction_multiply (GValue * product, const GValue * factor1,
3289     const GValue * factor2)
3290 {
3291   gint gcd, n1, n2, d1, d2;
3292
3293   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor1), FALSE);
3294   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor2), FALSE);
3295
3296   n1 = factor1->data[0].v_int;
3297   n2 = factor2->data[0].v_int;
3298   d1 = factor1->data[1].v_int;
3299   d2 = factor2->data[1].v_int;
3300
3301   gcd = gst_greatest_common_divisor (n1, d2);
3302   n1 /= gcd;
3303   d2 /= gcd;
3304   gcd = gst_greatest_common_divisor (n2, d1);
3305   n2 /= gcd;
3306   d1 /= gcd;
3307
3308   g_return_val_if_fail (n1 == 0 || G_MAXINT / ABS (n1) >= ABS (n2), FALSE);
3309   g_return_val_if_fail (G_MAXINT / ABS (d1) >= ABS (d2), FALSE);
3310
3311   gst_value_set_fraction (product, n1 * n2, d1 * d2);
3312
3313   return TRUE;
3314 }
3315
3316 /**
3317  * gst_value_fraction_subtract:
3318  * @dest: a GValue initialized to #GST_TYPE_FRACTION
3319  * @minuend: a GValue initialized to #GST_TYPE_FRACTION
3320  * @subtrahend: a GValue initialized to #GST_TYPE_FRACTION
3321  *
3322  * Subtracts the @subtrahend from the @minuend and sets @dest to the result.
3323  *
3324  * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise.
3325  */
3326 gboolean
3327 gst_value_fraction_subtract (GValue * dest,
3328     const GValue * minuend, const GValue * subtrahend)
3329 {
3330   gint n1, n2, d1, d2;
3331
3332   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (minuend), FALSE);
3333   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (subtrahend), FALSE);
3334
3335   n1 = minuend->data[0].v_int;
3336   n2 = subtrahend->data[0].v_int;
3337   d1 = minuend->data[1].v_int;
3338   d2 = subtrahend->data[1].v_int;
3339
3340   if (n1 == 0) {
3341     gst_value_set_fraction (dest, -n2, d2);
3342     return TRUE;
3343   }
3344   if (n2 == 0) {
3345     gst_value_set_fraction (dest, n1, d1);
3346     return TRUE;
3347   }
3348
3349   g_return_val_if_fail (n1 == 0 || G_MAXINT / ABS (n1) >= ABS (d2), FALSE);
3350   g_return_val_if_fail (G_MAXINT / ABS (d1) >= ABS (n2), FALSE);
3351   g_return_val_if_fail (G_MAXINT / ABS (d1) >= ABS (d2), FALSE);
3352
3353   gst_value_set_fraction (dest, (n1 * d2) - (n2 * d1), d1 * d2);
3354
3355   return TRUE;
3356 }
3357
3358 static gchar *
3359 gst_value_serialize_fraction (const GValue * value)
3360 {
3361   gint32 numerator = value->data[0].v_int;
3362   gint32 denominator = value->data[1].v_int;
3363   gboolean positive = TRUE;
3364
3365   /* get the sign and make components absolute */
3366   if (numerator < 0) {
3367     numerator = -numerator;
3368     positive = !positive;
3369   }
3370   if (denominator < 0) {
3371     denominator = -denominator;
3372     positive = !positive;
3373   }
3374
3375   return g_strdup_printf ("%s%d/%d",
3376       positive ? "" : "-", numerator, denominator);
3377 }
3378
3379 static gboolean
3380 gst_value_deserialize_fraction (GValue * dest, const gchar * s)
3381 {
3382   gint num, den;
3383
3384   if (s && sscanf (s, "%d/%d", &num, &den) == 2) {
3385     gst_value_set_fraction (dest, num, den);
3386     return TRUE;
3387   }
3388   if (s && sscanf (s, "%d", &num) == 1) {
3389     gst_value_set_fraction (dest, num, 1);
3390     return TRUE;
3391   }
3392   if (g_ascii_strcasecmp (s, "min") == 0) {
3393     gst_value_set_fraction (dest, -G_MAXINT, 1);
3394     return TRUE;
3395   } else if (g_ascii_strcasecmp (s, "max") == 0) {
3396     gst_value_set_fraction (dest, G_MAXINT, 1);
3397     return TRUE;
3398   }
3399
3400   return FALSE;
3401 }
3402
3403 static void
3404 gst_value_transform_fraction_string (const GValue * src_value,
3405     GValue * dest_value)
3406 {
3407   dest_value->data[0].v_pointer = gst_value_serialize_fraction (src_value);
3408 }
3409
3410 static void
3411 gst_value_transform_string_fraction (const GValue * src_value,
3412     GValue * dest_value)
3413 {
3414   if (!gst_value_deserialize_fraction (dest_value,
3415           src_value->data[0].v_pointer))
3416     /* If the deserialize fails, ensure we leave the fraction in a
3417      * valid, if incorrect, state */
3418     gst_value_set_fraction (dest_value, 0, 1);
3419 }
3420
3421 #define MAX_TERMS       30
3422 #define MIN_DIVISOR     1.0e-10
3423 #define MAX_ERROR       1.0e-20
3424
3425 /* use continued fractions to transform a double into a fraction,
3426  * see http://mathforum.org/dr.math/faq/faq.fractions.html#decfrac.
3427  * This algorithm takes care of overflows.
3428  */
3429 static void
3430 gst_value_transform_double_fraction (const GValue * src_value,
3431     GValue * dest_value)
3432 {
3433   gdouble V, F;                 /* double being converted */
3434   gint N, D;                    /* will contain the result */
3435   gint A;                       /* current term in continued fraction */
3436   gint64 N1, D1;                /* numerator, denominator of last approx */
3437   gint64 N2, D2;                /* numerator, denominator of previous approx */
3438   gint i;
3439   gboolean negative = FALSE;
3440
3441   /* initialize fraction being converted */
3442   F = src_value->data[0].v_double;
3443   if (F < 0.0) {
3444     F = -F;
3445     negative = TRUE;
3446   }
3447
3448   V = F;
3449   /* initialize fractions with 1/0, 0/1 */
3450   N1 = 1;
3451   D1 = 0;
3452   N2 = 0;
3453   D2 = 1;
3454   N = 1;
3455   D = 1;
3456
3457   for (i = 0; i < MAX_TERMS; i++) {
3458     /* get next term */
3459     A = (gint) F;               /* no floor() needed, F is always >= 0 */
3460     /* get new divisor */
3461     F = F - A;
3462
3463     /* calculate new fraction in temp */
3464     N2 = N1 * A + N2;
3465     D2 = D1 * A + D2;
3466
3467     /* guard against overflow */
3468     if (N2 > G_MAXINT || D2 > G_MAXINT) {
3469       break;
3470     }
3471
3472     N = N2;
3473     D = D2;
3474
3475     /* save last two fractions */
3476     N2 = N1;
3477     D2 = D1;
3478     N1 = N;
3479     D1 = D;
3480
3481     /* quit if dividing by zero or close enough to target */
3482     if (F < MIN_DIVISOR || fabs (V - ((gdouble) N) / D) < MAX_ERROR) {
3483       break;
3484     }
3485
3486     /* Take reciprocal */
3487     F = 1 / F;
3488   }
3489   /* fix for overflow */
3490   if (D == 0) {
3491     N = G_MAXINT;
3492     D = 1;
3493   }
3494   /* fix for negative */
3495   if (negative)
3496     N = -N;
3497
3498   /* will also simplify */
3499   gst_value_set_fraction (dest_value, N, D);
3500 }
3501
3502 static void
3503 gst_value_transform_fraction_double (const GValue * src_value,
3504     GValue * dest_value)
3505 {
3506   dest_value->data[0].v_double = ((double) src_value->data[0].v_int) /
3507       ((double) src_value->data[1].v_int);
3508 }
3509
3510 static gint
3511 gst_value_compare_fraction (const GValue * value1, const GValue * value2)
3512 {
3513   gint n1, n2;
3514   gint d1, d2;
3515
3516   gint64 new_num_1;
3517   gint64 new_num_2;
3518
3519   n1 = value1->data[0].v_int;
3520   n2 = value2->data[0].v_int;
3521   d1 = value1->data[1].v_int;
3522   d2 = value2->data[1].v_int;
3523
3524   /* fractions are reduced when set, so we can quickly see if they're equal */
3525   if (n1 == n2 && d1 == d2)
3526     return GST_VALUE_EQUAL;
3527
3528   /* extend to 64 bits */
3529   new_num_1 = ((gint64) n1) * d2;
3530   new_num_2 = ((gint64) n2) * d1;
3531   if (new_num_1 < new_num_2)
3532     return GST_VALUE_LESS_THAN;
3533   if (new_num_1 > new_num_2)
3534     return GST_VALUE_GREATER_THAN;
3535
3536   /* new_num_1 == new_num_2 implies that both denominators must have 
3537    * been 0, beause otherwise simplification would have caught the
3538    * equivalence */
3539   g_assert_not_reached ();
3540   return GST_VALUE_UNORDERED;
3541 }
3542
3543 /*********
3544  * GDate *
3545  *********/
3546
3547 /**
3548  * gst_value_set_date:
3549  * @value: a GValue initialized to GST_TYPE_DATE
3550  * @date: the date to set the value to
3551  *
3552  * Sets the contents of @value to coorespond to @date.  The actual
3553  * #GDate structure is copied before it is used.
3554  */
3555 void
3556 gst_value_set_date (GValue * value, const GDate * date)
3557 {
3558   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_DATE);
3559
3560   g_value_set_boxed (value, date);
3561 }
3562
3563 /**
3564  * gst_value_get_date:
3565  * @value: a GValue initialized to GST_TYPE_DATE
3566  *
3567  * Gets the contents of @value.
3568  *
3569  * Returns: the contents of @value
3570  */
3571 const GDate *
3572 gst_value_get_date (const GValue * value)
3573 {
3574   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_DATE, NULL);
3575
3576   return (const GDate *) g_value_get_boxed (value);
3577 }
3578
3579 static gpointer
3580 gst_date_copy (gpointer boxed)
3581 {
3582   const GDate *date = (const GDate *) boxed;
3583
3584   return g_date_new_julian (g_date_get_julian (date));
3585 }
3586
3587 static gint
3588 gst_value_compare_date (const GValue * value1, const GValue * value2)
3589 {
3590   const GDate *date1 = (const GDate *) g_value_get_boxed (value1);
3591   const GDate *date2 = (const GDate *) g_value_get_boxed (value2);
3592   guint32 j1, j2;
3593
3594   if (date1 == date2)
3595     return GST_VALUE_EQUAL;
3596
3597   if ((date1 == NULL || !g_date_valid (date1))
3598       && (date2 != NULL && g_date_valid (date2))) {
3599     return GST_VALUE_LESS_THAN;
3600   }
3601
3602   if ((date2 == NULL || !g_date_valid (date2))
3603       && (date1 != NULL && g_date_valid (date1))) {
3604     return GST_VALUE_GREATER_THAN;
3605   }
3606
3607   if (date1 == NULL || date2 == NULL || !g_date_valid (date1)
3608       || !g_date_valid (date2)) {
3609     return GST_VALUE_UNORDERED;
3610   }
3611
3612   j1 = g_date_get_julian (date1);
3613   j2 = g_date_get_julian (date2);
3614
3615   if (j1 == j2)
3616     return GST_VALUE_EQUAL;
3617   else if (j1 < j2)
3618     return GST_VALUE_LESS_THAN;
3619   else
3620     return GST_VALUE_GREATER_THAN;
3621 }
3622
3623 static gchar *
3624 gst_value_serialize_date (const GValue * val)
3625 {
3626   const GDate *date = (const GDate *) g_value_get_boxed (val);
3627
3628   if (date == NULL || !g_date_valid (date))
3629     return g_strdup ("9999-99-99");
3630
3631   return g_strdup_printf ("%04u-%02u-%02u", g_date_get_year (date),
3632       g_date_get_month (date), g_date_get_day (date));
3633 }
3634
3635 static gboolean
3636 gst_value_deserialize_date (GValue * dest, const char *s)
3637 {
3638   guint year, month, day;
3639
3640   if (!s || sscanf (s, "%04u-%02u-%02u", &year, &month, &day) != 3)
3641     return FALSE;
3642
3643   if (!g_date_valid_dmy (day, month, year))
3644     return FALSE;
3645
3646   g_value_take_boxed (dest, g_date_new_dmy (day, month, year));
3647   return TRUE;
3648 }
3649
3650 static void
3651 gst_value_transform_date_string (const GValue * src_value, GValue * dest_value)
3652 {
3653   dest_value->data[0].v_pointer = gst_value_serialize_date (src_value);
3654 }
3655
3656 static void
3657 gst_value_transform_string_date (const GValue * src_value, GValue * dest_value)
3658 {
3659   gst_value_deserialize_date (dest_value, src_value->data[0].v_pointer);
3660 }
3661
3662 static GTypeInfo _info = {
3663   0,
3664   NULL,
3665   NULL,
3666   NULL,
3667   NULL,
3668   NULL,
3669   0,
3670   0,
3671   NULL,
3672   NULL,
3673 };
3674
3675 static GTypeFundamentalInfo _finfo = {
3676   0
3677 };
3678
3679 #define FUNC_VALUE_GET_TYPE(type, name)                         \
3680 GType gst_ ## type ## _get_type (void)                          \
3681 {                                                               \
3682   static GType gst_ ## type ## _type = 0;                       \
3683                                                                 \
3684   if (G_UNLIKELY (gst_ ## type ## _type == 0)) {                \
3685     _info.value_table = & _gst_ ## type ## _value_table;        \
3686     gst_ ## type ## _type = g_type_register_fundamental (       \
3687         g_type_fundamental_next (),                             \
3688         name, &_info, &_finfo, 0);                              \
3689   }                                                             \
3690                                                                 \
3691   return gst_ ## type ## _type;                                 \
3692 }
3693
3694 static const GTypeValueTable _gst_fourcc_value_table = {
3695   gst_value_init_fourcc,
3696   NULL,
3697   gst_value_copy_fourcc,
3698   NULL,
3699   "i",
3700   gst_value_collect_fourcc,
3701   "p",
3702   gst_value_lcopy_fourcc
3703 };
3704
3705 FUNC_VALUE_GET_TYPE (fourcc, "GstFourcc");
3706
3707 static const GTypeValueTable _gst_int_range_value_table = {
3708   gst_value_init_int_range,
3709   NULL,
3710   gst_value_copy_int_range,
3711   NULL,
3712   "ii",
3713   gst_value_collect_int_range,
3714   "pp",
3715   gst_value_lcopy_int_range
3716 };
3717
3718 FUNC_VALUE_GET_TYPE (int_range, "GstIntRange");
3719
3720 static const GTypeValueTable _gst_double_range_value_table = {
3721   gst_value_init_double_range,
3722   NULL,
3723   gst_value_copy_double_range,
3724   NULL,
3725   "dd",
3726   gst_value_collect_double_range,
3727   "pp",
3728   gst_value_lcopy_double_range
3729 };
3730
3731 FUNC_VALUE_GET_TYPE (double_range, "GstDoubleRange");
3732
3733 static const GTypeValueTable _gst_fraction_range_value_table = {
3734   gst_value_init_fraction_range,
3735   gst_value_free_fraction_range,
3736   gst_value_copy_fraction_range,
3737   NULL,
3738   "iiii",
3739   gst_value_collect_fraction_range,
3740   "pppp",
3741   gst_value_lcopy_fraction_range
3742 };
3743
3744 FUNC_VALUE_GET_TYPE (fraction_range, "GstFractionRange");
3745
3746 static const GTypeValueTable _gst_value_list_value_table = {
3747   gst_value_init_list_or_array,
3748   gst_value_free_list_or_array,
3749   gst_value_copy_list_or_array,
3750   gst_value_list_or_array_peek_pointer,
3751   "p",
3752   gst_value_collect_list_or_array,
3753   "p",
3754   gst_value_lcopy_list_or_array
3755 };
3756
3757 FUNC_VALUE_GET_TYPE (value_list, "GstValueList");
3758
3759 static const GTypeValueTable _gst_value_array_value_table = {
3760   gst_value_init_list_or_array,
3761   gst_value_free_list_or_array,
3762   gst_value_copy_list_or_array,
3763   gst_value_list_or_array_peek_pointer,
3764   "p",
3765   gst_value_collect_list_or_array,
3766   "p",
3767   gst_value_lcopy_list_or_array
3768 };
3769
3770 FUNC_VALUE_GET_TYPE (value_array, "GstValueArray");
3771
3772 static const GTypeValueTable _gst_fraction_value_table = {
3773   gst_value_init_fraction,
3774   NULL,
3775   gst_value_copy_fraction,
3776   NULL,
3777   "ii",
3778   gst_value_collect_fraction,
3779   "pp",
3780   gst_value_lcopy_fraction
3781 };
3782
3783 FUNC_VALUE_GET_TYPE (fraction, "GstFraction");
3784
3785
3786 GType
3787 gst_date_get_type (void)
3788 {
3789   static GType gst_date_type = 0;
3790
3791   if (!gst_date_type) {
3792     /* Not using G_TYPE_DATE here on purpose, even if we could
3793      * if GLIB_CHECK_VERSION(2,8,0) was true: we don't want the
3794      * serialised strings to have different type strings depending
3795      * on what version is used, so FIXME when we
3796      * require GLib-2.8 */
3797     gst_date_type = g_boxed_type_register_static ("GstDate",
3798         (GBoxedCopyFunc) gst_date_copy, (GBoxedFreeFunc) g_date_free);
3799   }
3800
3801   return gst_date_type;
3802 }
3803
3804 void
3805 _gst_value_initialize (void)
3806 {
3807   //const GTypeFundamentalInfo finfo = { G_TYPE_FLAG_DERIVABLE, };
3808
3809   gst_value_table = g_array_new (FALSE, FALSE, sizeof (GstValueTable));
3810   gst_value_union_funcs = g_array_new (FALSE, FALSE,
3811       sizeof (GstValueUnionInfo));
3812   gst_value_intersect_funcs = g_array_new (FALSE, FALSE,
3813       sizeof (GstValueIntersectInfo));
3814   gst_value_subtract_funcs = g_array_new (FALSE, FALSE,
3815       sizeof (GstValueSubtractInfo));
3816
3817   {
3818     static GstValueTable gst_value = {
3819       0,
3820       gst_value_compare_fourcc,
3821       gst_value_serialize_fourcc,
3822       gst_value_deserialize_fourcc,
3823     };
3824
3825     gst_value.type = gst_fourcc_get_type ();
3826     gst_value_register (&gst_value);
3827   }
3828
3829   {
3830     static GstValueTable gst_value = {
3831       0,
3832       gst_value_compare_int_range,
3833       gst_value_serialize_int_range,
3834       gst_value_deserialize_int_range,
3835     };
3836
3837     gst_value.type = gst_int_range_get_type ();
3838     gst_value_register (&gst_value);
3839   }
3840
3841   {
3842     static GstValueTable gst_value = {
3843       0,
3844       gst_value_compare_double_range,
3845       gst_value_serialize_double_range,
3846       gst_value_deserialize_double_range,
3847     };
3848
3849     gst_value.type = gst_double_range_get_type ();
3850     gst_value_register (&gst_value);
3851   }
3852
3853   {
3854     static GstValueTable gst_value = {
3855       0,
3856       gst_value_compare_fraction_range,
3857       gst_value_serialize_fraction_range,
3858       gst_value_deserialize_fraction_range,
3859     };
3860
3861     gst_value.type = gst_fraction_range_get_type ();
3862     gst_value_register (&gst_value);
3863   }
3864
3865   {
3866     static GstValueTable gst_value = {
3867       0,
3868       gst_value_compare_list_or_array,
3869       gst_value_serialize_list,
3870       gst_value_deserialize_list,
3871     };
3872
3873     gst_value.type = gst_value_list_get_type ();
3874     gst_value_register (&gst_value);
3875   }
3876
3877   {
3878     static GstValueTable gst_value = {
3879       0,
3880       gst_value_compare_list_or_array,
3881       gst_value_serialize_array,
3882       gst_value_deserialize_array,
3883     };
3884
3885     gst_value.type = gst_value_array_get_type ();;
3886     gst_value_register (&gst_value);
3887   }
3888
3889   {
3890 #if 0
3891     static const GTypeValueTable value_table = {
3892       gst_value_init_buffer,
3893       NULL,
3894       gst_value_copy_buffer,
3895       NULL,
3896       "i",
3897       NULL,                     /*gst_value_collect_buffer, */
3898       "p",
3899       NULL                      /*gst_value_lcopy_buffer */
3900     };
3901 #endif
3902     static GstValueTable gst_value = {
3903       0,
3904       gst_value_compare_buffer,
3905       gst_value_serialize_buffer,
3906       gst_value_deserialize_buffer,
3907     };
3908
3909     gst_value.type = GST_TYPE_BUFFER;
3910     gst_value_register (&gst_value);
3911   }
3912   {
3913     static GstValueTable gst_value = {
3914       0,
3915       gst_value_compare_fraction,
3916       gst_value_serialize_fraction,
3917       gst_value_deserialize_fraction,
3918     };
3919
3920     gst_value.type = gst_fraction_get_type ();
3921     gst_value_register (&gst_value);
3922   }
3923   {
3924     static GstValueTable gst_value = {
3925       0,
3926       NULL,
3927       gst_value_serialize_caps,
3928       gst_value_deserialize_caps,
3929     };
3930
3931     gst_value.type = GST_TYPE_CAPS;
3932     gst_value_register (&gst_value);
3933   }
3934   {
3935     static GstValueTable gst_value = {
3936       0,
3937       gst_value_compare_date,
3938       gst_value_serialize_date,
3939       gst_value_deserialize_date,
3940     };
3941
3942     gst_value.type = gst_date_get_type ();
3943     gst_value_register (&gst_value);
3944   }
3945
3946   REGISTER_SERIALIZATION (G_TYPE_DOUBLE, double);
3947   REGISTER_SERIALIZATION (G_TYPE_FLOAT, float);
3948
3949   REGISTER_SERIALIZATION (G_TYPE_STRING, string);
3950   REGISTER_SERIALIZATION (G_TYPE_BOOLEAN, boolean);
3951   REGISTER_SERIALIZATION (G_TYPE_ENUM, enum);
3952
3953   REGISTER_SERIALIZATION (G_TYPE_FLAGS, flags);
3954
3955   REGISTER_SERIALIZATION (G_TYPE_INT, int);
3956
3957   REGISTER_SERIALIZATION (G_TYPE_INT64, int64);
3958   REGISTER_SERIALIZATION (G_TYPE_LONG, long);
3959
3960   REGISTER_SERIALIZATION (G_TYPE_UINT, uint);
3961   REGISTER_SERIALIZATION (G_TYPE_UINT64, uint64);
3962   REGISTER_SERIALIZATION (G_TYPE_ULONG, ulong);
3963
3964   g_value_register_transform_func (GST_TYPE_FOURCC, G_TYPE_STRING,
3965       gst_value_transform_fourcc_string);
3966   g_value_register_transform_func (GST_TYPE_INT_RANGE, G_TYPE_STRING,
3967       gst_value_transform_int_range_string);
3968   g_value_register_transform_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_STRING,
3969       gst_value_transform_double_range_string);
3970   g_value_register_transform_func (GST_TYPE_FRACTION_RANGE, G_TYPE_STRING,
3971       gst_value_transform_fraction_range_string);
3972   g_value_register_transform_func (GST_TYPE_LIST, G_TYPE_STRING,
3973       gst_value_transform_list_string);
3974   g_value_register_transform_func (GST_TYPE_ARRAY, G_TYPE_STRING,
3975       gst_value_transform_array_string);
3976   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_STRING,
3977       gst_value_transform_fraction_string);
3978   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_FRACTION,
3979       gst_value_transform_string_fraction);
3980   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_DOUBLE,
3981       gst_value_transform_fraction_double);
3982   g_value_register_transform_func (G_TYPE_DOUBLE, GST_TYPE_FRACTION,
3983       gst_value_transform_double_fraction);
3984   g_value_register_transform_func (GST_TYPE_DATE, G_TYPE_STRING,
3985       gst_value_transform_date_string);
3986   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_DATE,
3987       gst_value_transform_string_date);
3988
3989   gst_value_register_intersect_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
3990       gst_value_intersect_int_int_range);
3991   gst_value_register_intersect_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
3992       gst_value_intersect_int_range_int_range);
3993   gst_value_register_intersect_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
3994       gst_value_intersect_double_double_range);
3995   gst_value_register_intersect_func (GST_TYPE_DOUBLE_RANGE,
3996       GST_TYPE_DOUBLE_RANGE, gst_value_intersect_double_range_double_range);
3997   gst_value_register_intersect_func (GST_TYPE_ARRAY,
3998       GST_TYPE_ARRAY, gst_value_intersect_array);
3999   gst_value_register_intersect_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
4000       gst_value_intersect_fraction_fraction_range);
4001   gst_value_register_intersect_func (GST_TYPE_FRACTION_RANGE,
4002       GST_TYPE_FRACTION_RANGE,
4003       gst_value_intersect_fraction_range_fraction_range);
4004
4005   gst_value_register_subtract_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
4006       gst_value_subtract_int_int_range);
4007   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, G_TYPE_INT,
4008       gst_value_subtract_int_range_int);
4009   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
4010       gst_value_subtract_int_range_int_range);
4011   gst_value_register_subtract_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
4012       gst_value_subtract_double_double_range);
4013   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_DOUBLE,
4014       gst_value_subtract_double_range_double);
4015   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE,
4016       GST_TYPE_DOUBLE_RANGE, gst_value_subtract_double_range_double_range);
4017
4018   gst_value_register_subtract_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
4019       gst_value_subtract_fraction_fraction_range);
4020   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE, GST_TYPE_FRACTION,
4021       gst_value_subtract_fraction_range_fraction);
4022   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE,
4023       GST_TYPE_FRACTION_RANGE,
4024       gst_value_subtract_fraction_range_fraction_range);
4025
4026   /* see bug #317246, #64994, #65041 */
4027   {
4028     volatile GType date_type = G_TYPE_DATE;
4029
4030     g_type_name (date_type);
4031   }
4032
4033   gst_value_register_union_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
4034       gst_value_union_int_int_range);
4035   gst_value_register_union_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
4036       gst_value_union_int_range_int_range);
4037
4038 #if 0
4039   /* Implement these if needed */
4040   gst_value_register_union_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
4041       gst_value_union_fraction_fraction_range);
4042   gst_value_register_union_func (GST_TYPE_FRACTION_RANGE,
4043       GST_TYPE_FRACTION_RANGE, gst_value_union_fraction_range_fraction_range);
4044 #endif
4045 }