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