gstvalue: Prevent division or modulo by zero
[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., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, 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 /* GstValueUnionFunc:
49  * @dest: a #GValue for the result
50  * @value1: a #GValue operand
51  * @value2: a #GValue operand
52  *
53  * Used by gst_value_union() to perform unification for a specific #GValue
54  * type. Register a new implementation with gst_value_register_union_func().
55  *
56  * Returns: %TRUE if a union was successful
57  */
58 typedef gboolean (*GstValueUnionFunc) (GValue * dest,
59     const GValue * value1, const GValue * value2);
60
61 /* GstValueIntersectFunc:
62  * @dest: (out caller-allocates): a #GValue for the result
63  * @value1: a #GValue operand
64  * @value2: a #GValue operand
65  *
66  * Used by gst_value_intersect() to perform intersection for a specific #GValue
67  * type. If the intersection is non-empty, the result is
68  * placed in @dest and TRUE is returned.  If the intersection is
69  * empty, @dest is unmodified and FALSE is returned.
70  * Register a new implementation with gst_value_register_intersect_func().
71  *
72  * Returns: %TRUE if the values can intersect
73  */
74 typedef gboolean (*GstValueIntersectFunc) (GValue * dest,
75     const GValue * value1, const GValue * value2);
76
77 /* GstValueSubtractFunc:
78  * @dest: (out caller-allocates): a #GValue for the result
79  * @minuend: a #GValue operand
80  * @subtrahend: a #GValue operand
81  *
82  * Used by gst_value_subtract() to perform subtraction for a specific #GValue
83  * type. Register a new implementation with gst_value_register_subtract_func().
84  *
85  * Returns: %TRUE if the subtraction is not empty
86  */
87 typedef gboolean (*GstValueSubtractFunc) (GValue * dest,
88     const GValue * minuend, const GValue * subtrahend);
89
90 static void gst_value_register_union_func (GType type1,
91     GType type2, GstValueUnionFunc func);
92 static void gst_value_register_intersect_func (GType type1,
93     GType type2, GstValueIntersectFunc func);
94 static void gst_value_register_subtract_func (GType minuend_type,
95     GType subtrahend_type, GstValueSubtractFunc func);
96
97 typedef struct _GstValueUnionInfo GstValueUnionInfo;
98 struct _GstValueUnionInfo
99 {
100   GType type1;
101   GType type2;
102   GstValueUnionFunc func;
103 };
104
105 typedef struct _GstValueIntersectInfo GstValueIntersectInfo;
106 struct _GstValueIntersectInfo
107 {
108   GType type1;
109   GType type2;
110   GstValueIntersectFunc func;
111 };
112
113 typedef struct _GstValueSubtractInfo GstValueSubtractInfo;
114 struct _GstValueSubtractInfo
115 {
116   GType minuend;
117   GType subtrahend;
118   GstValueSubtractFunc func;
119 };
120
121 #define FUNDAMENTAL_TYPE_ID_MAX \
122     (G_TYPE_FUNDAMENTAL_MAX >> G_TYPE_FUNDAMENTAL_SHIFT)
123 #define FUNDAMENTAL_TYPE_ID(type) \
124     ((type) >> G_TYPE_FUNDAMENTAL_SHIFT)
125
126 #define VALUE_LIST_SIZE(v) (((GArray *) (v)->data[0].v_pointer)->len)
127 #define VALUE_LIST_GET_VALUE(v, index) ((const GValue *) &g_array_index ((GArray *) (v)->data[0].v_pointer, GValue, (index)))
128
129 static GArray *gst_value_table;
130 static GHashTable *gst_value_hash;
131 static GstValueTable *gst_value_tables_fundamental[FUNDAMENTAL_TYPE_ID_MAX + 1];
132 static GArray *gst_value_union_funcs;
133 static GArray *gst_value_intersect_funcs;
134 static GArray *gst_value_subtract_funcs;
135
136 /* Forward declarations */
137 static gchar *gst_value_serialize_fraction (const GValue * value);
138
139 static GstValueCompareFunc gst_value_get_compare_func (const GValue * value1);
140 static gint gst_value_compare_with_func (const GValue * value1,
141     const GValue * value2, GstValueCompareFunc compare);
142
143 static gchar *gst_string_wrap (const gchar * s);
144 static gchar *gst_string_take_and_wrap (gchar * s);
145 static gchar *gst_string_unwrap (const gchar * s);
146
147 static void gst_value_move (GValue * dest, GValue * src);
148 static void _gst_value_list_append_and_take_value (GValue * value,
149     GValue * append_value);
150 static void _gst_value_array_append_and_take_value (GValue * value,
151     GValue * append_value);
152
153 static inline GstValueTable *
154 gst_value_hash_lookup_type (GType type)
155 {
156   if (G_LIKELY (G_TYPE_IS_FUNDAMENTAL (type)))
157     return gst_value_tables_fundamental[FUNDAMENTAL_TYPE_ID (type)];
158   else
159     return g_hash_table_lookup (gst_value_hash, (gpointer) type);
160 }
161
162 static void
163 gst_value_hash_add_type (GType type, const GstValueTable * table)
164 {
165   if (G_TYPE_IS_FUNDAMENTAL (type))
166     gst_value_tables_fundamental[FUNDAMENTAL_TYPE_ID (type)] = (gpointer) table;
167
168   g_hash_table_insert (gst_value_hash, (gpointer) type, (gpointer) table);
169 }
170
171 /********
172  * list *
173  ********/
174
175 /* two helper functions to serialize/stringify any type of list
176  * regular lists are done with { }, arrays with < >
177  */
178 static gchar *
179 gst_value_serialize_any_list (const GValue * value, const gchar * begin,
180     const gchar * end)
181 {
182   guint i;
183   GArray *array = value->data[0].v_pointer;
184   GString *s;
185   GValue *v;
186   gchar *s_val;
187   guint alen = array->len;
188
189   /* estimate minimum string length to minimise re-allocs in GString */
190   s = g_string_sized_new (2 + (6 * alen) + 2);
191   g_string_append (s, begin);
192   for (i = 0; i < alen; i++) {
193     v = &g_array_index (array, GValue, i);
194     s_val = gst_value_serialize (v);
195     if (s_val != NULL) {
196       g_string_append (s, s_val);
197       g_free (s_val);
198       if (i < alen - 1) {
199         g_string_append_len (s, ", ", 2);
200       }
201     } else {
202       GST_WARNING ("Could not serialize list/array value of type '%s'",
203           G_VALUE_TYPE_NAME (v));
204     }
205   }
206   g_string_append (s, end);
207   return g_string_free (s, FALSE);
208 }
209
210 static void
211 gst_value_transform_any_list_string (const GValue * src_value,
212     GValue * dest_value, const gchar * begin, const gchar * end)
213 {
214   GValue *list_value;
215   GArray *array;
216   GString *s;
217   guint i;
218   gchar *list_s;
219   guint alen;
220
221   array = src_value->data[0].v_pointer;
222   alen = array->len;
223
224   /* estimate minimum string length to minimise re-allocs in GString */
225   s = g_string_sized_new (2 + (10 * alen) + 2);
226   g_string_append (s, begin);
227   for (i = 0; i < alen; i++) {
228     list_value = &g_array_index (array, GValue, i);
229
230     if (i != 0) {
231       g_string_append_len (s, ", ", 2);
232     }
233     list_s = g_strdup_value_contents (list_value);
234     g_string_append (s, list_s);
235     g_free (list_s);
236   }
237   g_string_append (s, end);
238
239   dest_value->data[0].v_pointer = g_string_free (s, FALSE);
240 }
241
242 /*
243  * helper function to see if a type is fixed. Is used internally here and
244  * there. Do not export, since it doesn't work for types where the content
245  * decides the fixedness (e.g. GST_TYPE_ARRAY).
246  */
247 static gboolean
248 gst_type_is_fixed (GType type)
249 {
250   /* the basic int, string, double types */
251   if (type <= G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
252     return TRUE;
253   }
254   /* our fundamental types that are certainly not fixed */
255   if (type == GST_TYPE_INT_RANGE || type == GST_TYPE_DOUBLE_RANGE ||
256       type == GST_TYPE_INT64_RANGE ||
257       type == GST_TYPE_LIST || type == GST_TYPE_FRACTION_RANGE) {
258     return FALSE;
259   }
260   /* other (boxed) types that are fixed */
261   if (type == GST_TYPE_BUFFER) {
262     return TRUE;
263   }
264   /* heavy checks */
265   if (G_TYPE_IS_FUNDAMENTAL (type) || G_TYPE_FUNDAMENTAL (type) <=
266       G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
267     return TRUE;
268   }
269
270   return FALSE;
271 }
272
273 /* GValue functions usable for both regular lists and arrays */
274 static void
275 gst_value_init_list_or_array (GValue * value)
276 {
277   value->data[0].v_pointer = g_array_new (FALSE, TRUE, sizeof (GValue));
278 }
279
280 static GArray *
281 copy_garray_of_gstvalue (const GArray * src)
282 {
283   GArray *dest;
284   guint i, len;
285
286   len = src->len;
287   dest = g_array_sized_new (FALSE, TRUE, sizeof (GValue), len);
288   g_array_set_size (dest, len);
289   for (i = 0; i < len; i++) {
290     gst_value_init_and_copy (&g_array_index (dest, GValue, i),
291         &g_array_index (src, GValue, i));
292   }
293
294   return dest;
295 }
296
297 static void
298 gst_value_copy_list_or_array (const GValue * src_value, GValue * dest_value)
299 {
300   dest_value->data[0].v_pointer =
301       copy_garray_of_gstvalue ((GArray *) src_value->data[0].v_pointer);
302 }
303
304 static void
305 gst_value_free_list_or_array (GValue * value)
306 {
307   guint i, len;
308   GArray *src = (GArray *) value->data[0].v_pointer;
309   len = src->len;
310
311   if ((value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS) == 0) {
312     for (i = 0; i < len; i++) {
313       g_value_unset (&g_array_index (src, GValue, i));
314     }
315     g_array_free (src, TRUE);
316   }
317 }
318
319 static gpointer
320 gst_value_list_or_array_peek_pointer (const GValue * value)
321 {
322   return value->data[0].v_pointer;
323 }
324
325 static gchar *
326 gst_value_collect_list_or_array (GValue * value, guint n_collect_values,
327     GTypeCValue * collect_values, guint collect_flags)
328 {
329   if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
330     value->data[0].v_pointer = collect_values[0].v_pointer;
331     value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
332   } else {
333     value->data[0].v_pointer =
334         copy_garray_of_gstvalue ((GArray *) collect_values[0].v_pointer);
335   }
336   return NULL;
337 }
338
339 static gchar *
340 gst_value_lcopy_list_or_array (const GValue * value, guint n_collect_values,
341     GTypeCValue * collect_values, guint collect_flags)
342 {
343   GArray **dest = collect_values[0].v_pointer;
344
345   if (!dest)
346     return g_strdup_printf ("value location for `%s' passed as NULL",
347         G_VALUE_TYPE_NAME (value));
348   if (!value->data[0].v_pointer)
349     return g_strdup_printf ("invalid value given for `%s'",
350         G_VALUE_TYPE_NAME (value));
351   if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
352     *dest = (GArray *) value->data[0].v_pointer;
353   } else {
354     *dest = copy_garray_of_gstvalue ((GArray *) value->data[0].v_pointer);
355   }
356   return NULL;
357 }
358
359 static gboolean
360 gst_value_list_or_array_get_basic_type (const GValue * value, GType * type)
361 {
362   if (G_UNLIKELY (value == NULL))
363     return FALSE;
364
365   if (GST_VALUE_HOLDS_LIST (value)) {
366     if (VALUE_LIST_SIZE (value) == 0)
367       return FALSE;
368     return gst_value_list_or_array_get_basic_type (VALUE_LIST_GET_VALUE (value,
369             0), type);
370   }
371   if (GST_VALUE_HOLDS_ARRAY (value)) {
372     const GArray *array = (const GArray *) value->data[0].v_pointer;
373     if (array->len == 0)
374       return FALSE;
375     return gst_value_list_or_array_get_basic_type (&g_array_index (array,
376             GValue, 0), type);
377   }
378
379   *type = G_VALUE_TYPE (value);
380
381   return TRUE;
382 }
383
384 #define IS_RANGE_COMPAT(type1,type2,t1,t2) \
385   (((t1) == (type1) && (t2) == (type2)) || ((t2) == (type1) && (t1) == (type2)))
386
387 static gboolean
388 gst_value_list_or_array_are_compatible (const GValue * value1,
389     const GValue * value2)
390 {
391   GType basic_type1, basic_type2;
392
393   /* empty or same type is OK */
394   if (!gst_value_list_or_array_get_basic_type (value1, &basic_type1) ||
395       !gst_value_list_or_array_get_basic_type (value2, &basic_type2) ||
396       basic_type1 == basic_type2)
397     return TRUE;
398
399   /* ranges are distinct types for each bound type... */
400   if (IS_RANGE_COMPAT (G_TYPE_INT, GST_TYPE_INT_RANGE, basic_type1,
401           basic_type2))
402     return TRUE;
403   if (IS_RANGE_COMPAT (G_TYPE_INT64, GST_TYPE_INT64_RANGE, basic_type1,
404           basic_type2))
405     return TRUE;
406   if (IS_RANGE_COMPAT (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE, basic_type1,
407           basic_type2))
408     return TRUE;
409   if (IS_RANGE_COMPAT (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE, basic_type1,
410           basic_type2))
411     return TRUE;
412
413   return FALSE;
414 }
415
416 static inline void
417 _gst_value_list_append_and_take_value (GValue * value, GValue * append_value)
418 {
419   g_array_append_vals ((GArray *) value->data[0].v_pointer, append_value, 1);
420   memset (append_value, 0, sizeof (GValue));
421 }
422
423 /**
424  * gst_value_list_append_and_take_value:
425  * @value: a #GValue of type #GST_TYPE_LIST
426  * @append_value: (transfer full): the value to append
427  *
428  * Appends @append_value to the GstValueList in @value.
429  *
430  * Since: 1.2
431  */
432 void
433 gst_value_list_append_and_take_value (GValue * value, GValue * append_value)
434 {
435   g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
436   g_return_if_fail (G_IS_VALUE (append_value));
437   g_return_if_fail (gst_value_list_or_array_are_compatible (value,
438           append_value));
439
440   _gst_value_list_append_and_take_value (value, append_value);
441 }
442
443 /**
444  * gst_value_list_append_value:
445  * @value: a #GValue of type #GST_TYPE_LIST
446  * @append_value: (transfer none): the value to append
447  *
448  * Appends @append_value to the GstValueList in @value.
449  */
450 void
451 gst_value_list_append_value (GValue * value, const GValue * append_value)
452 {
453   GValue val = { 0, };
454
455   g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
456   g_return_if_fail (G_IS_VALUE (append_value));
457   g_return_if_fail (gst_value_list_or_array_are_compatible (value,
458           append_value));
459
460   gst_value_init_and_copy (&val, append_value);
461   g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1);
462 }
463
464 /**
465  * gst_value_list_prepend_value:
466  * @value: a #GValue of type #GST_TYPE_LIST
467  * @prepend_value: the value to prepend
468  *
469  * Prepends @prepend_value to the GstValueList in @value.
470  */
471 void
472 gst_value_list_prepend_value (GValue * value, const GValue * prepend_value)
473 {
474   GValue val = { 0, };
475
476   g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
477   g_return_if_fail (G_IS_VALUE (prepend_value));
478   g_return_if_fail (gst_value_list_or_array_are_compatible (value,
479           prepend_value));
480
481   gst_value_init_and_copy (&val, prepend_value);
482   g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1);
483 }
484
485 /**
486  * gst_value_list_concat:
487  * @dest: (out caller-allocates): an uninitialized #GValue to take the result
488  * @value1: a #GValue
489  * @value2: a #GValue
490  *
491  * Concatenates copies of @value1 and @value2 into a list.  Values that are not
492  * of type #GST_TYPE_LIST are treated as if they were lists of length 1.
493  * @dest will be initialized to the type #GST_TYPE_LIST.
494  */
495 void
496 gst_value_list_concat (GValue * dest, const GValue * value1,
497     const GValue * value2)
498 {
499   guint i, value1_length, value2_length;
500   GArray *array;
501
502   g_return_if_fail (dest != NULL);
503   g_return_if_fail (G_VALUE_TYPE (dest) == 0);
504   g_return_if_fail (G_IS_VALUE (value1));
505   g_return_if_fail (G_IS_VALUE (value2));
506   g_return_if_fail (gst_value_list_or_array_are_compatible (value1, value2));
507
508   value1_length =
509       (GST_VALUE_HOLDS_LIST (value1) ? VALUE_LIST_SIZE (value1) : 1);
510   value2_length =
511       (GST_VALUE_HOLDS_LIST (value2) ? VALUE_LIST_SIZE (value2) : 1);
512   g_value_init (dest, GST_TYPE_LIST);
513   array = (GArray *) dest->data[0].v_pointer;
514   g_array_set_size (array, value1_length + value2_length);
515
516   if (GST_VALUE_HOLDS_LIST (value1)) {
517     for (i = 0; i < value1_length; i++) {
518       gst_value_init_and_copy (&g_array_index (array, GValue, i),
519           VALUE_LIST_GET_VALUE (value1, i));
520     }
521   } else {
522     gst_value_init_and_copy (&g_array_index (array, GValue, 0), value1);
523   }
524
525   if (GST_VALUE_HOLDS_LIST (value2)) {
526     for (i = 0; i < value2_length; i++) {
527       gst_value_init_and_copy (&g_array_index (array, GValue,
528               i + value1_length), VALUE_LIST_GET_VALUE (value2, i));
529     }
530   } else {
531     gst_value_init_and_copy (&g_array_index (array, GValue, value1_length),
532         value2);
533   }
534 }
535
536 /**
537  * gst_value_list_merge:
538  * @dest: (out caller-allocates): an uninitialized #GValue to take the result
539  * @value1: a #GValue
540  * @value2: a #GValue
541  *
542  * Merges copies of @value1 and @value2.  Values that are not
543  * of type #GST_TYPE_LIST are treated as if they were lists of length 1.
544  *
545  * The result will be put into @dest and will either be a list that will not
546  * contain any duplicates, or a non-list type (if @value1 and @value2
547  * were equal).
548  */
549 void
550 gst_value_list_merge (GValue * dest, const GValue * value1,
551     const GValue * value2)
552 {
553   guint i, j, k, value1_length, value2_length, skipped;
554   const GValue *src;
555   gboolean skip;
556   GArray *array;
557
558   g_return_if_fail (dest != NULL);
559   g_return_if_fail (G_VALUE_TYPE (dest) == 0);
560   g_return_if_fail (G_IS_VALUE (value1));
561   g_return_if_fail (G_IS_VALUE (value2));
562   g_return_if_fail (gst_value_list_or_array_are_compatible (value1, value2));
563
564   value1_length =
565       (GST_VALUE_HOLDS_LIST (value1) ? VALUE_LIST_SIZE (value1) : 1);
566   value2_length =
567       (GST_VALUE_HOLDS_LIST (value2) ? VALUE_LIST_SIZE (value2) : 1);
568   g_value_init (dest, GST_TYPE_LIST);
569   array = (GArray *) dest->data[0].v_pointer;
570   g_array_set_size (array, value1_length + value2_length);
571
572   if (GST_VALUE_HOLDS_LIST (value1)) {
573     for (i = 0; i < value1_length; i++) {
574       gst_value_init_and_copy (&g_array_index (array, GValue, i),
575           VALUE_LIST_GET_VALUE (value1, i));
576     }
577   } else {
578     gst_value_init_and_copy (&g_array_index (array, GValue, 0), value1);
579   }
580
581   j = value1_length;
582   skipped = 0;
583   if (GST_VALUE_HOLDS_LIST (value2)) {
584     for (i = 0; i < value2_length; i++) {
585       skip = FALSE;
586       src = VALUE_LIST_GET_VALUE (value2, i);
587       for (k = 0; k < value1_length; k++) {
588         if (gst_value_compare (&g_array_index (array, GValue, k),
589                 src) == GST_VALUE_EQUAL) {
590           skip = TRUE;
591           skipped++;
592           break;
593         }
594       }
595       if (!skip) {
596         gst_value_init_and_copy (&g_array_index (array, GValue, j), src);
597         j++;
598       }
599     }
600   } else {
601     skip = FALSE;
602     for (k = 0; k < value1_length; k++) {
603       if (gst_value_compare (&g_array_index (array, GValue, k),
604               value2) == GST_VALUE_EQUAL) {
605         skip = TRUE;
606         skipped++;
607         break;
608       }
609     }
610     if (!skip) {
611       gst_value_init_and_copy (&g_array_index (array, GValue, j), value2);
612     }
613   }
614   if (skipped) {
615     guint new_size = value1_length + (value2_length - skipped);
616
617     if (new_size > 1) {
618       /* shrink list */
619       g_array_set_size (array, new_size);
620     } else {
621       GValue single_dest;
622
623       /* size is 1, take single value in list and make it new dest */
624       single_dest = g_array_index (array, GValue, 0);
625
626       /* clean up old value allocations: must set array size to 0, because
627        * allocated values are not inited meaning g_value_unset() will not
628        * work on them */
629       g_array_set_size (array, 0);
630       g_value_unset (dest);
631
632       /* the single value is our new result */
633       *dest = single_dest;
634     }
635   }
636 }
637
638 /**
639  * gst_value_list_get_size:
640  * @value: a #GValue of type #GST_TYPE_LIST
641  *
642  * Gets the number of values contained in @value.
643  *
644  * Returns: the number of values
645  */
646 guint
647 gst_value_list_get_size (const GValue * value)
648 {
649   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), 0);
650
651   return ((GArray *) value->data[0].v_pointer)->len;
652 }
653
654 /**
655  * gst_value_list_get_value:
656  * @value: a #GValue of type #GST_TYPE_LIST
657  * @index: index of value to get from the list
658  *
659  * Gets the value that is a member of the list contained in @value and
660  * has the index @index.
661  *
662  * Returns: (transfer none): the value at the given index
663  */
664 const GValue *
665 gst_value_list_get_value (const GValue * value, guint index)
666 {
667   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), NULL);
668   g_return_val_if_fail (index < VALUE_LIST_SIZE (value), NULL);
669
670   return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer,
671       GValue, index);
672 }
673
674 /**
675  * gst_value_array_append_value:
676  * @value: a #GValue of type #GST_TYPE_ARRAY
677  * @append_value: the value to append
678  *
679  * Appends @append_value to the GstValueArray in @value.
680  */
681 void
682 gst_value_array_append_value (GValue * value, const GValue * append_value)
683 {
684   GValue val = { 0, };
685
686   g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value));
687   g_return_if_fail (G_IS_VALUE (append_value));
688   g_return_if_fail (gst_value_list_or_array_are_compatible (value,
689           append_value));
690
691   gst_value_init_and_copy (&val, append_value);
692   g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1);
693 }
694
695 static inline void
696 _gst_value_array_append_and_take_value (GValue * value, GValue * append_value)
697 {
698   g_array_append_vals ((GArray *) value->data[0].v_pointer, append_value, 1);
699   memset (append_value, 0, sizeof (GValue));
700 }
701
702 /**
703  * gst_value_array_append_and_take_value:
704  * @value: a #GValue of type #GST_TYPE_ARRAY
705  * @append_value: (transfer full): the value to append
706  *
707  * Appends @append_value to the GstValueArray in @value.
708  *
709  * Since: 1.2
710  */
711 void
712 gst_value_array_append_and_take_value (GValue * value, GValue * append_value)
713 {
714   g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value));
715   g_return_if_fail (G_IS_VALUE (append_value));
716   g_return_if_fail (gst_value_list_or_array_are_compatible (value,
717           append_value));
718
719   _gst_value_array_append_and_take_value (value, append_value);
720 }
721
722 /**
723  * gst_value_array_prepend_value:
724  * @value: a #GValue of type #GST_TYPE_ARRAY
725  * @prepend_value: the value to prepend
726  *
727  * Prepends @prepend_value to the GstValueArray in @value.
728  */
729 void
730 gst_value_array_prepend_value (GValue * value, const GValue * prepend_value)
731 {
732   GValue val = { 0, };
733
734   g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value));
735   g_return_if_fail (G_IS_VALUE (prepend_value));
736   g_return_if_fail (gst_value_list_or_array_are_compatible (value,
737           prepend_value));
738
739   gst_value_init_and_copy (&val, prepend_value);
740   g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1);
741 }
742
743 /**
744  * gst_value_array_get_size:
745  * @value: a #GValue of type #GST_TYPE_ARRAY
746  *
747  * Gets the number of values contained in @value.
748  *
749  * Returns: the number of values
750  */
751 guint
752 gst_value_array_get_size (const GValue * value)
753 {
754   g_return_val_if_fail (GST_VALUE_HOLDS_ARRAY (value), 0);
755
756   return ((GArray *) value->data[0].v_pointer)->len;
757 }
758
759 /**
760  * gst_value_array_get_value:
761  * @value: a #GValue of type #GST_TYPE_ARRAY
762  * @index: index of value to get from the array
763  *
764  * Gets the value that is a member of the array contained in @value and
765  * has the index @index.
766  *
767  * Returns: (transfer none): the value at the given index
768  */
769 const GValue *
770 gst_value_array_get_value (const GValue * value, guint index)
771 {
772   g_return_val_if_fail (GST_VALUE_HOLDS_ARRAY (value), NULL);
773   g_return_val_if_fail (index < gst_value_array_get_size (value), NULL);
774
775   return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer,
776       GValue, index);
777 }
778
779 static void
780 gst_value_transform_list_string (const GValue * src_value, GValue * dest_value)
781 {
782   gst_value_transform_any_list_string (src_value, dest_value, "{ ", " }");
783 }
784
785 static void
786 gst_value_transform_array_string (const GValue * src_value, GValue * dest_value)
787 {
788   gst_value_transform_any_list_string (src_value, dest_value, "< ", " >");
789 }
790
791 /* Do an unordered compare of the contents of a list */
792 static gint
793 gst_value_compare_list (const GValue * value1, const GValue * value2)
794 {
795   guint i, j;
796   GArray *array1 = value1->data[0].v_pointer;
797   GArray *array2 = value2->data[0].v_pointer;
798   GValue *v1;
799   GValue *v2;
800   gint len, to_remove;
801   guint8 *removed;
802   GstValueCompareFunc compare;
803
804   /* get length and do initial length check. */
805   len = array1->len;
806   if (len != array2->len)
807     return GST_VALUE_UNORDERED;
808
809   /* place to mark removed value indices of array2 */
810   removed = g_newa (guint8, len);
811   memset (removed, 0, len);
812   to_remove = len;
813
814   /* loop over array1, all items should be in array2. When we find an
815    * item in array2, remove it from array2 by marking it as removed */
816   for (i = 0; i < len; i++) {
817     v1 = &g_array_index (array1, GValue, i);
818     if ((compare = gst_value_get_compare_func (v1))) {
819       for (j = 0; j < len; j++) {
820         /* item is removed, we can skip it */
821         if (removed[j])
822           continue;
823         v2 = &g_array_index (array2, GValue, j);
824         if (gst_value_compare_with_func (v1, v2, compare) == GST_VALUE_EQUAL) {
825           /* mark item as removed now that we found it in array2 and 
826            * decrement the number of remaining items in array2. */
827           removed[j] = 1;
828           to_remove--;
829           break;
830         }
831       }
832       /* item in array1 and not in array2, UNORDERED */
833       if (j == len)
834         return GST_VALUE_UNORDERED;
835     } else
836       return GST_VALUE_UNORDERED;
837   }
838   /* if not all items were removed, array2 contained something not in array1 */
839   if (to_remove != 0)
840     return GST_VALUE_UNORDERED;
841
842   /* arrays are equal */
843   return GST_VALUE_EQUAL;
844 }
845
846 /* Perform an ordered comparison of the contents of an array */
847 static gint
848 gst_value_compare_array (const GValue * value1, const GValue * value2)
849 {
850   guint i;
851   GArray *array1 = value1->data[0].v_pointer;
852   GArray *array2 = value2->data[0].v_pointer;
853   guint len = array1->len;
854   GValue *v1;
855   GValue *v2;
856
857   if (len != array2->len)
858     return GST_VALUE_UNORDERED;
859
860   for (i = 0; i < len; i++) {
861     v1 = &g_array_index (array1, GValue, i);
862     v2 = &g_array_index (array2, GValue, i);
863     if (gst_value_compare (v1, v2) != GST_VALUE_EQUAL)
864       return GST_VALUE_UNORDERED;
865   }
866
867   return GST_VALUE_EQUAL;
868 }
869
870 static gchar *
871 gst_value_serialize_list (const GValue * value)
872 {
873   return gst_value_serialize_any_list (value, "{ ", " }");
874 }
875
876 static gboolean
877 gst_value_deserialize_list (GValue * dest, const gchar * s)
878 {
879   g_warning ("gst_value_deserialize_list: unimplemented");
880   return FALSE;
881 }
882
883 static gchar *
884 gst_value_serialize_array (const GValue * value)
885 {
886   return gst_value_serialize_any_list (value, "< ", " >");
887 }
888
889 static gboolean
890 gst_value_deserialize_array (GValue * dest, const gchar * s)
891 {
892   g_warning ("gst_value_deserialize_array: unimplemented");
893   return FALSE;
894 }
895
896 /*************
897  * int range *
898  *
899  * Values in the range are defined as any value greater or equal
900  * to min*step, AND lesser or equal to max*step.
901  * For step == 1, this falls back to the traditional range semantics.
902  *************/
903
904 #define INT_RANGE_MIN(v) (((gint *)((v)->data[0].v_pointer))[0])
905 #define INT_RANGE_MAX(v) (((gint *)((v)->data[0].v_pointer))[1])
906 #define INT_RANGE_STEP(v) (((gint *)((v)->data[0].v_pointer))[2])
907
908 static void
909 gst_value_init_int_range (GValue * value)
910 {
911   gint *vals = g_slice_alloc0 (3 * sizeof (gint));
912   value->data[0].v_pointer = vals;
913   INT_RANGE_MIN (value) = 0;
914   INT_RANGE_MAX (value) = 0;
915   INT_RANGE_STEP (value) = 1;
916 }
917
918 static void
919 gst_value_free_int_range (GValue * value)
920 {
921   g_return_if_fail (GST_VALUE_HOLDS_INT_RANGE (value));
922   g_slice_free1 (3 * sizeof (gint), value->data[0].v_pointer);
923   value->data[0].v_pointer = NULL;
924 }
925
926 static void
927 gst_value_copy_int_range (const GValue * src_value, GValue * dest_value)
928 {
929   gint *vals = (gint *) dest_value->data[0].v_pointer;
930   gint *src_vals = (gint *) src_value->data[0].v_pointer;
931
932   if (vals == NULL) {
933     gst_value_init_int_range (dest_value);
934   }
935   if (src_vals != NULL) {
936     INT_RANGE_MIN (dest_value) = INT_RANGE_MIN (src_value);
937     INT_RANGE_MAX (dest_value) = INT_RANGE_MAX (src_value);
938     INT_RANGE_STEP (dest_value) = INT_RANGE_STEP (src_value);
939   }
940 }
941
942 static gchar *
943 gst_value_collect_int_range (GValue * value, guint n_collect_values,
944     GTypeCValue * collect_values, guint collect_flags)
945 {
946   gint *vals = value->data[0].v_pointer;
947
948   if (n_collect_values != 2)
949     return g_strdup_printf ("not enough value locations for `%s' passed",
950         G_VALUE_TYPE_NAME (value));
951   if (collect_values[0].v_int >= collect_values[1].v_int)
952     return g_strdup_printf ("range start is not smaller than end for `%s'",
953         G_VALUE_TYPE_NAME (value));
954
955   if (vals == NULL) {
956     gst_value_init_int_range (value);
957   }
958
959   gst_value_set_int_range_step (value, collect_values[0].v_int,
960       collect_values[1].v_int, 1);
961
962   return NULL;
963 }
964
965 static gchar *
966 gst_value_lcopy_int_range (const GValue * value, guint n_collect_values,
967     GTypeCValue * collect_values, guint collect_flags)
968 {
969   guint32 *int_range_start = collect_values[0].v_pointer;
970   guint32 *int_range_end = collect_values[1].v_pointer;
971   guint32 *int_range_step = collect_values[2].v_pointer;
972   gint *vals = (gint *) value->data[0].v_pointer;
973
974   if (!int_range_start)
975     return g_strdup_printf ("start value location for `%s' passed as NULL",
976         G_VALUE_TYPE_NAME (value));
977   if (!int_range_end)
978     return g_strdup_printf ("end value location for `%s' passed as NULL",
979         G_VALUE_TYPE_NAME (value));
980   if (!int_range_step)
981     return g_strdup_printf ("step value location for `%s' passed as NULL",
982         G_VALUE_TYPE_NAME (value));
983
984   if (G_UNLIKELY (vals == NULL)) {
985     return g_strdup_printf ("Uninitialised `%s' passed",
986         G_VALUE_TYPE_NAME (value));
987   }
988
989   *int_range_start = INT_RANGE_MIN (value);
990   *int_range_end = INT_RANGE_MAX (value);
991   *int_range_step = INT_RANGE_STEP (value);
992
993   return NULL;
994 }
995
996 /**
997  * gst_value_set_int_range_step:
998  * @value: a GValue initialized to GST_TYPE_INT_RANGE
999  * @start: the start of the range
1000  * @end: the end of the range
1001  * @step: the step of the range
1002  *
1003  * Sets @value to the range specified by @start, @end and @step.
1004  */
1005 void
1006 gst_value_set_int_range_step (GValue * value, gint start, gint end, gint step)
1007 {
1008   g_return_if_fail (GST_VALUE_HOLDS_INT_RANGE (value));
1009   g_return_if_fail (start < end);
1010   g_return_if_fail (step > 0);
1011   g_return_if_fail (start % step == 0);
1012   g_return_if_fail (end % step == 0);
1013
1014   INT_RANGE_MIN (value) = start / step;
1015   INT_RANGE_MAX (value) = end / step;
1016   INT_RANGE_STEP (value) = step;
1017 }
1018
1019 /**
1020  * gst_value_set_int_range:
1021  * @value: a GValue initialized to GST_TYPE_INT_RANGE
1022  * @start: the start of the range
1023  * @end: the end of the range
1024  *
1025  * Sets @value to the range specified by @start and @end.
1026  */
1027 void
1028 gst_value_set_int_range (GValue * value, gint start, gint end)
1029 {
1030   gst_value_set_int_range_step (value, start, end, 1);
1031 }
1032
1033 /**
1034  * gst_value_get_int_range_min:
1035  * @value: a GValue initialized to GST_TYPE_INT_RANGE
1036  *
1037  * Gets the minimum of the range specified by @value.
1038  *
1039  * Returns: the minimum of the range
1040  */
1041 gint
1042 gst_value_get_int_range_min (const GValue * value)
1043 {
1044   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
1045
1046   return INT_RANGE_MIN (value) * INT_RANGE_STEP (value);
1047 }
1048
1049 /**
1050  * gst_value_get_int_range_max:
1051  * @value: a GValue initialized to GST_TYPE_INT_RANGE
1052  *
1053  * Gets the maximum of the range specified by @value.
1054  *
1055  * Returns: the maximum of the range
1056  */
1057 gint
1058 gst_value_get_int_range_max (const GValue * value)
1059 {
1060   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
1061
1062   return INT_RANGE_MAX (value) * INT_RANGE_STEP (value);
1063 }
1064
1065 /**
1066  * gst_value_get_int_range_step:
1067  * @value: a GValue initialized to GST_TYPE_INT_RANGE
1068  *
1069  * Gets the step of the range specified by @value.
1070  *
1071  * Returns: the step of the range
1072  */
1073 gint
1074 gst_value_get_int_range_step (const GValue * value)
1075 {
1076   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
1077
1078   return INT_RANGE_STEP (value);
1079 }
1080
1081 static void
1082 gst_value_transform_int_range_string (const GValue * src_value,
1083     GValue * dest_value)
1084 {
1085   if (INT_RANGE_STEP (src_value) == 1)
1086     dest_value->data[0].v_pointer = g_strdup_printf ("[%d,%d]",
1087         INT_RANGE_MIN (src_value), INT_RANGE_MAX (src_value));
1088   else
1089     dest_value->data[0].v_pointer = g_strdup_printf ("[%d,%d,%d]",
1090         INT_RANGE_MIN (src_value) * INT_RANGE_STEP (src_value),
1091         INT_RANGE_MAX (src_value) * INT_RANGE_STEP (src_value),
1092         INT_RANGE_STEP (src_value));
1093 }
1094
1095 static gint
1096 gst_value_compare_int_range (const GValue * value1, const GValue * value2)
1097 {
1098   /* calculate the number of values in each range */
1099   gint n1 = INT_RANGE_MAX (value1) - INT_RANGE_MIN (value1) + 1;
1100   gint n2 = INT_RANGE_MAX (value2) - INT_RANGE_MIN (value2) + 1;
1101
1102   /* they must be equal */
1103   if (n1 != n2)
1104     return GST_VALUE_UNORDERED;
1105
1106   /* if empty, equal */
1107   if (n1 == 0)
1108     return GST_VALUE_EQUAL;
1109
1110   /* if more than one value, then it is only equal if the step is equal
1111      and bounds lie on the same value */
1112   if (n1 > 1) {
1113     if (INT_RANGE_STEP (value1) == INT_RANGE_STEP (value2) &&
1114         INT_RANGE_MIN (value1) == INT_RANGE_MIN (value2) &&
1115         INT_RANGE_MAX (value1) == INT_RANGE_MAX (value2)) {
1116       return GST_VALUE_EQUAL;
1117     }
1118     return GST_VALUE_UNORDERED;
1119   } else {
1120     /* if just one, only if the value is equal */
1121     if (INT_RANGE_MIN (value1) == INT_RANGE_MIN (value2))
1122       return GST_VALUE_EQUAL;
1123     return GST_VALUE_UNORDERED;
1124   }
1125 }
1126
1127 static gchar *
1128 gst_value_serialize_int_range (const GValue * value)
1129 {
1130   if (INT_RANGE_STEP (value) == 1)
1131     return g_strdup_printf ("[ %d, %d ]", INT_RANGE_MIN (value),
1132         INT_RANGE_MAX (value));
1133   else
1134     return g_strdup_printf ("[ %d, %d, %d ]",
1135         INT_RANGE_MIN (value) * INT_RANGE_STEP (value),
1136         INT_RANGE_MAX (value) * INT_RANGE_STEP (value), INT_RANGE_STEP (value));
1137 }
1138
1139 static gboolean
1140 gst_value_deserialize_int_range (GValue * dest, const gchar * s)
1141 {
1142   g_warning ("unimplemented");
1143   return FALSE;
1144 }
1145
1146 /***************
1147  * int64 range *
1148  *
1149  * Values in the range are defined as any value greater or equal
1150  * to min*step, AND lesser or equal to max*step.
1151  * For step == 1, this falls back to the traditional range semantics.
1152  ***************/
1153
1154 #define INT64_RANGE_MIN(v) (((gint64 *)((v)->data[0].v_pointer))[0])
1155 #define INT64_RANGE_MAX(v) (((gint64 *)((v)->data[0].v_pointer))[1])
1156 #define INT64_RANGE_STEP(v) (((gint64 *)((v)->data[0].v_pointer))[2])
1157
1158 static void
1159 gst_value_init_int64_range (GValue * value)
1160 {
1161   gint64 *vals = g_slice_alloc0 (3 * sizeof (gint64));
1162   value->data[0].v_pointer = vals;
1163   INT64_RANGE_MIN (value) = 0;
1164   INT64_RANGE_MAX (value) = 0;
1165   INT64_RANGE_STEP (value) = 1;
1166 }
1167
1168 static void
1169 gst_value_free_int64_range (GValue * value)
1170 {
1171   g_return_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value));
1172   g_slice_free1 (3 * sizeof (gint64), value->data[0].v_pointer);
1173   value->data[0].v_pointer = NULL;
1174 }
1175
1176 static void
1177 gst_value_copy_int64_range (const GValue * src_value, GValue * dest_value)
1178 {
1179   gint64 *vals = (gint64 *) dest_value->data[0].v_pointer;
1180   gint64 *src_vals = (gint64 *) src_value->data[0].v_pointer;
1181
1182   if (vals == NULL) {
1183     gst_value_init_int64_range (dest_value);
1184   }
1185
1186   if (src_vals != NULL) {
1187     INT64_RANGE_MIN (dest_value) = INT64_RANGE_MIN (src_value);
1188     INT64_RANGE_MAX (dest_value) = INT64_RANGE_MAX (src_value);
1189     INT64_RANGE_STEP (dest_value) = INT64_RANGE_STEP (src_value);
1190   }
1191 }
1192
1193 static gchar *
1194 gst_value_collect_int64_range (GValue * value, guint n_collect_values,
1195     GTypeCValue * collect_values, guint collect_flags)
1196 {
1197   gint64 *vals = value->data[0].v_pointer;
1198
1199   if (n_collect_values != 2)
1200     return g_strdup_printf ("not enough value locations for `%s' passed",
1201         G_VALUE_TYPE_NAME (value));
1202   if (collect_values[0].v_int64 >= collect_values[1].v_int64)
1203     return g_strdup_printf ("range start is not smaller than end for `%s'",
1204         G_VALUE_TYPE_NAME (value));
1205
1206   if (vals == NULL) {
1207     gst_value_init_int64_range (value);
1208   }
1209
1210   gst_value_set_int64_range_step (value, collect_values[0].v_int64,
1211       collect_values[1].v_int64, 1);
1212
1213   return NULL;
1214 }
1215
1216 static gchar *
1217 gst_value_lcopy_int64_range (const GValue * value, guint n_collect_values,
1218     GTypeCValue * collect_values, guint collect_flags)
1219 {
1220   guint64 *int_range_start = collect_values[0].v_pointer;
1221   guint64 *int_range_end = collect_values[1].v_pointer;
1222   guint64 *int_range_step = collect_values[2].v_pointer;
1223   gint64 *vals = (gint64 *) value->data[0].v_pointer;
1224
1225   if (!int_range_start)
1226     return g_strdup_printf ("start value location for `%s' passed as NULL",
1227         G_VALUE_TYPE_NAME (value));
1228   if (!int_range_end)
1229     return g_strdup_printf ("end value location for `%s' passed as NULL",
1230         G_VALUE_TYPE_NAME (value));
1231   if (!int_range_step)
1232     return g_strdup_printf ("step value location for `%s' passed as NULL",
1233         G_VALUE_TYPE_NAME (value));
1234
1235   if (G_UNLIKELY (vals == NULL)) {
1236     return g_strdup_printf ("Uninitialised `%s' passed",
1237         G_VALUE_TYPE_NAME (value));
1238   }
1239
1240   *int_range_start = INT64_RANGE_MIN (value);
1241   *int_range_end = INT64_RANGE_MAX (value);
1242   *int_range_step = INT64_RANGE_STEP (value);
1243
1244   return NULL;
1245 }
1246
1247 /**
1248  * gst_value_set_int64_range_step:
1249  * @value: a GValue initialized to GST_TYPE_INT64_RANGE
1250  * @start: the start of the range
1251  * @end: the end of the range
1252  * @step: the step of the range
1253  *
1254  * Sets @value to the range specified by @start, @end and @step.
1255  */
1256 void
1257 gst_value_set_int64_range_step (GValue * value, gint64 start, gint64 end,
1258     gint64 step)
1259 {
1260   g_return_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value));
1261   g_return_if_fail (start < end);
1262   g_return_if_fail (step > 0);
1263   g_return_if_fail (start % step == 0);
1264   g_return_if_fail (end % step == 0);
1265
1266   INT64_RANGE_MIN (value) = start / step;
1267   INT64_RANGE_MAX (value) = end / step;
1268   INT64_RANGE_STEP (value) = step;
1269 }
1270
1271 /**
1272  * gst_value_set_int64_range:
1273  * @value: a GValue initialized to GST_TYPE_INT64_RANGE
1274  * @start: the start of the range
1275  * @end: the end of the range
1276  *
1277  * Sets @value to the range specified by @start and @end.
1278  */
1279 void
1280 gst_value_set_int64_range (GValue * value, gint64 start, gint64 end)
1281 {
1282   gst_value_set_int64_range_step (value, start, end, 1);
1283 }
1284
1285 /**
1286  * gst_value_get_int64_range_min:
1287  * @value: a GValue initialized to GST_TYPE_INT64_RANGE
1288  *
1289  * Gets the minimum of the range specified by @value.
1290  *
1291  * Returns: the minimum of the range
1292  */
1293 gint64
1294 gst_value_get_int64_range_min (const GValue * value)
1295 {
1296   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value), 0);
1297
1298   return INT64_RANGE_MIN (value) * INT64_RANGE_STEP (value);
1299 }
1300
1301 /**
1302  * gst_value_get_int64_range_max:
1303  * @value: a GValue initialized to GST_TYPE_INT64_RANGE
1304  *
1305  * Gets the maximum of the range specified by @value.
1306  *
1307  * Returns: the maximum of the range
1308  */
1309 gint64
1310 gst_value_get_int64_range_max (const GValue * value)
1311 {
1312   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value), 0);
1313
1314   return INT64_RANGE_MAX (value) * INT64_RANGE_STEP (value);
1315 }
1316
1317 /**
1318  * gst_value_get_int64_range_step:
1319  * @value: a GValue initialized to GST_TYPE_INT64_RANGE
1320  *
1321  * Gets the step of the range specified by @value.
1322  *
1323  * Returns: the step of the range
1324  */
1325 gint64
1326 gst_value_get_int64_range_step (const GValue * value)
1327 {
1328   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value), 0);
1329
1330   return INT64_RANGE_STEP (value);
1331 }
1332
1333 static void
1334 gst_value_transform_int64_range_string (const GValue * src_value,
1335     GValue * dest_value)
1336 {
1337   if (INT64_RANGE_STEP (src_value) == 1)
1338     dest_value->data[0].v_pointer =
1339         g_strdup_printf ("(gint64)[%" G_GINT64_FORMAT ",%" G_GINT64_FORMAT "]",
1340         INT64_RANGE_MIN (src_value), INT64_RANGE_MAX (src_value));
1341   else
1342     dest_value->data[0].v_pointer =
1343         g_strdup_printf ("(gint64)[%" G_GINT64_FORMAT ",%" G_GINT64_FORMAT
1344         ",%" G_GINT64_FORMAT "]",
1345         INT64_RANGE_MIN (src_value) * INT64_RANGE_STEP (src_value),
1346         INT64_RANGE_MAX (src_value) * INT64_RANGE_STEP (src_value),
1347         INT64_RANGE_STEP (src_value));
1348 }
1349
1350 static gint
1351 gst_value_compare_int64_range (const GValue * value1, const GValue * value2)
1352 {
1353   /* calculate the number of values in each range */
1354   gint64 n1 = INT64_RANGE_MAX (value1) - INT64_RANGE_MIN (value1) + 1;
1355   gint64 n2 = INT64_RANGE_MAX (value2) - INT64_RANGE_MIN (value2) + 1;
1356
1357   /* they must be equal */
1358   if (n1 != n2)
1359     return GST_VALUE_UNORDERED;
1360
1361   /* if empty, equal */
1362   if (n1 == 0)
1363     return GST_VALUE_EQUAL;
1364
1365   /* if more than one value, then it is only equal if the step is equal
1366      and bounds lie on the same value */
1367   if (n1 > 1) {
1368     if (INT64_RANGE_STEP (value1) == INT64_RANGE_STEP (value2) &&
1369         INT64_RANGE_MIN (value1) == INT64_RANGE_MIN (value2) &&
1370         INT64_RANGE_MAX (value1) == INT64_RANGE_MAX (value2)) {
1371       return GST_VALUE_EQUAL;
1372     }
1373     return GST_VALUE_UNORDERED;
1374   } else {
1375     /* if just one, only if the value is equal */
1376     if (INT64_RANGE_MIN (value1) == INT64_RANGE_MIN (value2))
1377       return GST_VALUE_EQUAL;
1378     return GST_VALUE_UNORDERED;
1379   }
1380 }
1381
1382 static gchar *
1383 gst_value_serialize_int64_range (const GValue * value)
1384 {
1385   if (INT64_RANGE_STEP (value) == 1)
1386     return g_strdup_printf ("[ %" G_GINT64_FORMAT ", %" G_GINT64_FORMAT " ]",
1387         INT64_RANGE_MIN (value), INT64_RANGE_MAX (value));
1388   else
1389     return g_strdup_printf ("[ %" G_GINT64_FORMAT ", %" G_GINT64_FORMAT ", %"
1390         G_GINT64_FORMAT " ]",
1391         INT64_RANGE_MIN (value) * INT64_RANGE_STEP (value),
1392         INT64_RANGE_MAX (value) * INT64_RANGE_STEP (value),
1393         INT64_RANGE_STEP (value));
1394 }
1395
1396 static gboolean
1397 gst_value_deserialize_int64_range (GValue * dest, const gchar * s)
1398 {
1399   g_warning ("unimplemented");
1400   return FALSE;
1401 }
1402
1403 /****************
1404  * double range *
1405  ****************/
1406
1407 static void
1408 gst_value_init_double_range (GValue * value)
1409 {
1410   value->data[0].v_double = 0;
1411   value->data[1].v_double = 0;
1412 }
1413
1414 static void
1415 gst_value_copy_double_range (const GValue * src_value, GValue * dest_value)
1416 {
1417   dest_value->data[0].v_double = src_value->data[0].v_double;
1418   dest_value->data[1].v_double = src_value->data[1].v_double;
1419 }
1420
1421 static gchar *
1422 gst_value_collect_double_range (GValue * value, guint n_collect_values,
1423     GTypeCValue * collect_values, guint collect_flags)
1424 {
1425   if (n_collect_values != 2)
1426     return g_strdup_printf ("not enough value locations for `%s' passed",
1427         G_VALUE_TYPE_NAME (value));
1428   if (collect_values[0].v_double >= collect_values[1].v_double)
1429     return g_strdup_printf ("range start is not smaller than end for `%s'",
1430         G_VALUE_TYPE_NAME (value));
1431
1432   value->data[0].v_double = collect_values[0].v_double;
1433   value->data[1].v_double = collect_values[1].v_double;
1434
1435   return NULL;
1436 }
1437
1438 static gchar *
1439 gst_value_lcopy_double_range (const GValue * value, guint n_collect_values,
1440     GTypeCValue * collect_values, guint collect_flags)
1441 {
1442   gdouble *double_range_start = collect_values[0].v_pointer;
1443   gdouble *double_range_end = collect_values[1].v_pointer;
1444
1445   if (!double_range_start)
1446     return g_strdup_printf ("start value location for `%s' passed as NULL",
1447         G_VALUE_TYPE_NAME (value));
1448   if (!double_range_end)
1449     return g_strdup_printf ("end value location for `%s' passed as NULL",
1450         G_VALUE_TYPE_NAME (value));
1451
1452   *double_range_start = value->data[0].v_double;
1453   *double_range_end = value->data[1].v_double;
1454
1455   return NULL;
1456 }
1457
1458 /**
1459  * gst_value_set_double_range:
1460  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
1461  * @start: the start of the range
1462  * @end: the end of the range
1463  *
1464  * Sets @value to the range specified by @start and @end.
1465  */
1466 void
1467 gst_value_set_double_range (GValue * value, gdouble start, gdouble end)
1468 {
1469   g_return_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value));
1470   g_return_if_fail (start < end);
1471
1472   value->data[0].v_double = start;
1473   value->data[1].v_double = end;
1474 }
1475
1476 /**
1477  * gst_value_get_double_range_min:
1478  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
1479  *
1480  * Gets the minimum of the range specified by @value.
1481  *
1482  * Returns: the minimum of the range
1483  */
1484 gdouble
1485 gst_value_get_double_range_min (const GValue * value)
1486 {
1487   g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
1488
1489   return value->data[0].v_double;
1490 }
1491
1492 /**
1493  * gst_value_get_double_range_max:
1494  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
1495  *
1496  * Gets the maximum of the range specified by @value.
1497  *
1498  * Returns: the maximum of the range
1499  */
1500 gdouble
1501 gst_value_get_double_range_max (const GValue * value)
1502 {
1503   g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
1504
1505   return value->data[1].v_double;
1506 }
1507
1508 static void
1509 gst_value_transform_double_range_string (const GValue * src_value,
1510     GValue * dest_value)
1511 {
1512   gchar s1[G_ASCII_DTOSTR_BUF_SIZE], s2[G_ASCII_DTOSTR_BUF_SIZE];
1513
1514   dest_value->data[0].v_pointer = g_strdup_printf ("[%s,%s]",
1515       g_ascii_dtostr (s1, G_ASCII_DTOSTR_BUF_SIZE,
1516           src_value->data[0].v_double),
1517       g_ascii_dtostr (s2, G_ASCII_DTOSTR_BUF_SIZE,
1518           src_value->data[1].v_double));
1519 }
1520
1521 static gint
1522 gst_value_compare_double_range (const GValue * value1, const GValue * value2)
1523 {
1524   if (value2->data[0].v_double == value1->data[0].v_double &&
1525       value2->data[1].v_double == value1->data[1].v_double)
1526     return GST_VALUE_EQUAL;
1527   return GST_VALUE_UNORDERED;
1528 }
1529
1530 static gchar *
1531 gst_value_serialize_double_range (const GValue * value)
1532 {
1533   gchar d1[G_ASCII_DTOSTR_BUF_SIZE];
1534   gchar d2[G_ASCII_DTOSTR_BUF_SIZE];
1535
1536   g_ascii_dtostr (d1, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
1537   g_ascii_dtostr (d2, G_ASCII_DTOSTR_BUF_SIZE, value->data[1].v_double);
1538   return g_strdup_printf ("[ %s, %s ]", d1, d2);
1539 }
1540
1541 static gboolean
1542 gst_value_deserialize_double_range (GValue * dest, const gchar * s)
1543 {
1544   g_warning ("unimplemented");
1545   return FALSE;
1546 }
1547
1548 /****************
1549  * fraction range *
1550  ****************/
1551
1552 static void
1553 gst_value_init_fraction_range (GValue * value)
1554 {
1555   GValue *vals;
1556   GType ftype;
1557
1558   ftype = GST_TYPE_FRACTION;
1559
1560   value->data[0].v_pointer = vals = g_slice_alloc0 (2 * sizeof (GValue));
1561   g_value_init (&vals[0], ftype);
1562   g_value_init (&vals[1], ftype);
1563 }
1564
1565 static void
1566 gst_value_free_fraction_range (GValue * value)
1567 {
1568   GValue *vals = (GValue *) value->data[0].v_pointer;
1569
1570   if (vals != NULL) {
1571     /* we know the two values contain fractions without internal allocs */
1572     /* g_value_unset (&vals[0]); */
1573     /* g_value_unset (&vals[1]); */
1574     g_slice_free1 (2 * sizeof (GValue), vals);
1575     value->data[0].v_pointer = NULL;
1576   }
1577 }
1578
1579 static void
1580 gst_value_copy_fraction_range (const GValue * src_value, GValue * dest_value)
1581 {
1582   GValue *vals = (GValue *) dest_value->data[0].v_pointer;
1583   GValue *src_vals = (GValue *) src_value->data[0].v_pointer;
1584
1585   if (vals == NULL) {
1586     gst_value_init_fraction_range (dest_value);
1587     vals = dest_value->data[0].v_pointer;
1588   }
1589   if (src_vals != NULL) {
1590     g_value_copy (&src_vals[0], &vals[0]);
1591     g_value_copy (&src_vals[1], &vals[1]);
1592   }
1593 }
1594
1595 static gchar *
1596 gst_value_collect_fraction_range (GValue * value, guint n_collect_values,
1597     GTypeCValue * collect_values, guint collect_flags)
1598 {
1599   GValue *vals = (GValue *) value->data[0].v_pointer;
1600
1601   if (n_collect_values != 4)
1602     return g_strdup_printf ("not enough value locations for `%s' passed",
1603         G_VALUE_TYPE_NAME (value));
1604   if (collect_values[1].v_int == 0)
1605     return g_strdup_printf ("passed '0' as first denominator for `%s'",
1606         G_VALUE_TYPE_NAME (value));
1607   if (collect_values[3].v_int == 0)
1608     return g_strdup_printf ("passed '0' as second denominator for `%s'",
1609         G_VALUE_TYPE_NAME (value));
1610   if (gst_util_fraction_compare (collect_values[0].v_int,
1611           collect_values[1].v_int, collect_values[2].v_int,
1612           collect_values[3].v_int) >= 0)
1613     return g_strdup_printf ("range start is not smaller than end for `%s'",
1614         G_VALUE_TYPE_NAME (value));
1615
1616   if (vals == NULL) {
1617     gst_value_init_fraction_range (value);
1618     vals = value->data[0].v_pointer;
1619   }
1620
1621   gst_value_set_fraction (&vals[0], collect_values[0].v_int,
1622       collect_values[1].v_int);
1623   gst_value_set_fraction (&vals[1], collect_values[2].v_int,
1624       collect_values[3].v_int);
1625
1626   return NULL;
1627 }
1628
1629 static gchar *
1630 gst_value_lcopy_fraction_range (const GValue * value, guint n_collect_values,
1631     GTypeCValue * collect_values, guint collect_flags)
1632 {
1633   gint i;
1634   gint *dest_values[4];
1635   GValue *vals = (GValue *) value->data[0].v_pointer;
1636
1637   if (G_UNLIKELY (n_collect_values != 4))
1638     return g_strdup_printf ("not enough value locations for `%s' passed",
1639         G_VALUE_TYPE_NAME (value));
1640
1641   for (i = 0; i < 4; i++) {
1642     if (G_UNLIKELY (collect_values[i].v_pointer == NULL)) {
1643       return g_strdup_printf ("value location for `%s' passed as NULL",
1644           G_VALUE_TYPE_NAME (value));
1645     }
1646     dest_values[i] = collect_values[i].v_pointer;
1647   }
1648
1649   if (G_UNLIKELY (vals == NULL)) {
1650     return g_strdup_printf ("Uninitialised `%s' passed",
1651         G_VALUE_TYPE_NAME (value));
1652   }
1653
1654   dest_values[0][0] = gst_value_get_fraction_numerator (&vals[0]);
1655   dest_values[1][0] = gst_value_get_fraction_denominator (&vals[0]);
1656   dest_values[2][0] = gst_value_get_fraction_numerator (&vals[1]);
1657   dest_values[3][0] = gst_value_get_fraction_denominator (&vals[1]);
1658   return NULL;
1659 }
1660
1661 /**
1662  * gst_value_set_fraction_range:
1663  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1664  * @start: the start of the range (a GST_TYPE_FRACTION GValue)
1665  * @end: the end of the range (a GST_TYPE_FRACTION GValue)
1666  *
1667  * Sets @value to the range specified by @start and @end.
1668  */
1669 void
1670 gst_value_set_fraction_range (GValue * value, const GValue * start,
1671     const GValue * end)
1672 {
1673   GValue *vals;
1674
1675   g_return_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value));
1676   g_return_if_fail (GST_VALUE_HOLDS_FRACTION (start));
1677   g_return_if_fail (GST_VALUE_HOLDS_FRACTION (end));
1678   g_return_if_fail (gst_util_fraction_compare (start->data[0].v_int,
1679           start->data[1].v_int, end->data[0].v_int, end->data[1].v_int) < 0);
1680
1681   vals = (GValue *) value->data[0].v_pointer;
1682   if (vals == NULL) {
1683     gst_value_init_fraction_range (value);
1684     vals = value->data[0].v_pointer;
1685   }
1686   g_value_copy (start, &vals[0]);
1687   g_value_copy (end, &vals[1]);
1688 }
1689
1690 /**
1691  * gst_value_set_fraction_range_full:
1692  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1693  * @numerator_start: the numerator start of the range
1694  * @denominator_start: the denominator start of the range
1695  * @numerator_end: the numerator end of the range
1696  * @denominator_end: the denominator end of the range
1697  *
1698  * Sets @value to the range specified by @numerator_start/@denominator_start
1699  * and @numerator_end/@denominator_end.
1700  */
1701 void
1702 gst_value_set_fraction_range_full (GValue * value,
1703     gint numerator_start, gint denominator_start,
1704     gint numerator_end, gint denominator_end)
1705 {
1706   GValue start = { 0 };
1707   GValue end = { 0 };
1708
1709   g_return_if_fail (value != NULL);
1710   g_return_if_fail (denominator_start != 0);
1711   g_return_if_fail (denominator_end != 0);
1712   g_return_if_fail (gst_util_fraction_compare (numerator_start,
1713           denominator_start, numerator_end, denominator_end) < 0);
1714
1715   g_value_init (&start, GST_TYPE_FRACTION);
1716   g_value_init (&end, GST_TYPE_FRACTION);
1717
1718   gst_value_set_fraction (&start, numerator_start, denominator_start);
1719   gst_value_set_fraction (&end, numerator_end, denominator_end);
1720   gst_value_set_fraction_range (value, &start, &end);
1721
1722   /* we know the two values contain fractions without internal allocs */
1723   /* g_value_unset (&start); */
1724   /* g_value_unset (&end);   */
1725 }
1726
1727 /**
1728  * gst_value_get_fraction_range_min:
1729  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1730  *
1731  * Gets the minimum of the range specified by @value.
1732  *
1733  * Returns: the minimum of the range
1734  */
1735 const GValue *
1736 gst_value_get_fraction_range_min (const GValue * value)
1737 {
1738   GValue *vals;
1739
1740   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value), NULL);
1741
1742   vals = (GValue *) value->data[0].v_pointer;
1743   if (vals != NULL) {
1744     return &vals[0];
1745   }
1746
1747   return NULL;
1748 }
1749
1750 /**
1751  * gst_value_get_fraction_range_max:
1752  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1753  *
1754  * Gets the maximum of the range specified by @value.
1755  *
1756  * Returns: the maximum of the range
1757  */
1758 const GValue *
1759 gst_value_get_fraction_range_max (const GValue * value)
1760 {
1761   GValue *vals;
1762
1763   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value), NULL);
1764
1765   vals = (GValue *) value->data[0].v_pointer;
1766   if (vals != NULL) {
1767     return &vals[1];
1768   }
1769
1770   return NULL;
1771 }
1772
1773 static gchar *
1774 gst_value_serialize_fraction_range (const GValue * value)
1775 {
1776   GValue *vals = (GValue *) value->data[0].v_pointer;
1777   gchar *retval;
1778
1779   if (vals == NULL) {
1780     retval = g_strdup ("[ 0/1, 0/1 ]");
1781   } else {
1782     gchar *start, *end;
1783
1784     start = gst_value_serialize_fraction (&vals[0]);
1785     end = gst_value_serialize_fraction (&vals[1]);
1786
1787     retval = g_strdup_printf ("[ %s, %s ]", start, end);
1788     g_free (start);
1789     g_free (end);
1790   }
1791
1792   return retval;
1793 }
1794
1795 static void
1796 gst_value_transform_fraction_range_string (const GValue * src_value,
1797     GValue * dest_value)
1798 {
1799   dest_value->data[0].v_pointer =
1800       gst_value_serialize_fraction_range (src_value);
1801 }
1802
1803 static gint
1804 gst_value_compare_fraction_range (const GValue * value1, const GValue * value2)
1805 {
1806   GValue *vals1, *vals2;
1807   GstValueCompareFunc compare;
1808
1809   if (value2->data[0].v_pointer == value1->data[0].v_pointer)
1810     return GST_VALUE_EQUAL;     /* Only possible if both are NULL */
1811
1812   if (value2->data[0].v_pointer == NULL || value1->data[0].v_pointer == NULL)
1813     return GST_VALUE_UNORDERED;
1814
1815   vals1 = (GValue *) value1->data[0].v_pointer;
1816   vals2 = (GValue *) value2->data[0].v_pointer;
1817   if ((compare = gst_value_get_compare_func (&vals1[0]))) {
1818     if (gst_value_compare_with_func (&vals1[0], &vals2[0], compare) ==
1819         GST_VALUE_EQUAL &&
1820         gst_value_compare_with_func (&vals1[1], &vals2[1], compare) ==
1821         GST_VALUE_EQUAL)
1822       return GST_VALUE_EQUAL;
1823   }
1824   return GST_VALUE_UNORDERED;
1825 }
1826
1827 static gboolean
1828 gst_value_deserialize_fraction_range (GValue * dest, const gchar * s)
1829 {
1830   g_warning ("unimplemented");
1831   return FALSE;
1832 }
1833
1834 /***********
1835  * GstCaps *
1836  ***********/
1837
1838 /**
1839  * gst_value_set_caps:
1840  * @value: a GValue initialized to GST_TYPE_CAPS
1841  * @caps: (transfer none): the caps to set the value to
1842  *
1843  * Sets the contents of @value to @caps. A reference to the
1844  * provided @caps will be taken by the @value.
1845  */
1846 void
1847 gst_value_set_caps (GValue * value, const GstCaps * caps)
1848 {
1849   g_return_if_fail (G_IS_VALUE (value));
1850   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS);
1851   g_return_if_fail (caps == NULL || GST_IS_CAPS (caps));
1852
1853   g_value_set_boxed (value, caps);
1854 }
1855
1856 /**
1857  * gst_value_get_caps:
1858  * @value: a GValue initialized to GST_TYPE_CAPS
1859  *
1860  * Gets the contents of @value. The reference count of the returned
1861  * #GstCaps will not be modified, therefore the caller must take one
1862  * before getting rid of the @value.
1863  *
1864  * Returns: (transfer none): the contents of @value
1865  */
1866 const GstCaps *
1867 gst_value_get_caps (const GValue * value)
1868 {
1869   g_return_val_if_fail (G_IS_VALUE (value), NULL);
1870   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS, NULL);
1871
1872   return (GstCaps *) g_value_get_boxed (value);
1873 }
1874
1875 static gint
1876 gst_value_compare_caps (const GValue * value1, const GValue * value2)
1877 {
1878   GstCaps *caps1 = GST_CAPS (gst_value_get_caps (value1));
1879   GstCaps *caps2 = GST_CAPS (gst_value_get_caps (value2));
1880
1881   if (gst_caps_is_equal (caps1, caps2))
1882     return GST_VALUE_EQUAL;
1883   return GST_VALUE_UNORDERED;
1884 }
1885
1886 static gchar *
1887 gst_value_serialize_caps (const GValue * value)
1888 {
1889   GstCaps *caps = g_value_get_boxed (value);
1890   return gst_string_take_and_wrap (gst_caps_to_string (caps));
1891 }
1892
1893 static gboolean
1894 gst_value_deserialize_caps (GValue * dest, const gchar * s)
1895 {
1896   GstCaps *caps;
1897
1898   if (*s != '"') {
1899     caps = gst_caps_from_string (s);
1900   } else {
1901     gchar *str = gst_string_unwrap (s);
1902
1903     if (G_UNLIKELY (!str))
1904       return FALSE;
1905
1906     caps = gst_caps_from_string (str);
1907     g_free (str);
1908   }
1909
1910   if (caps) {
1911     g_value_take_boxed (dest, caps);
1912     return TRUE;
1913   }
1914   return FALSE;
1915 }
1916
1917 /**************
1918  * GstSegment *
1919  **************/
1920
1921 static gchar *
1922 gst_value_serialize_segment_internal (const GValue * value, gboolean escape)
1923 {
1924   GstSegment *seg = g_value_get_boxed (value);
1925   gchar *t, *res;
1926   GstStructure *s;
1927
1928   s = gst_structure_new ("GstSegment",
1929       "flags", GST_TYPE_SEGMENT_FLAGS, seg->flags,
1930       "rate", G_TYPE_DOUBLE, seg->rate,
1931       "applied-rate", G_TYPE_DOUBLE, seg->applied_rate,
1932       "format", GST_TYPE_FORMAT, seg->format,
1933       "base", G_TYPE_UINT64, seg->base,
1934       "offset", G_TYPE_UINT64, seg->offset,
1935       "start", G_TYPE_UINT64, seg->start,
1936       "stop", G_TYPE_UINT64, seg->stop,
1937       "time", G_TYPE_UINT64, seg->time,
1938       "position", G_TYPE_UINT64, seg->position,
1939       "duration", G_TYPE_UINT64, seg->duration, NULL);
1940   t = gst_structure_to_string (s);
1941   if (escape) {
1942     res = g_strdup_printf ("\"%s\"", t);
1943     g_free (t);
1944   } else {
1945     res = t;
1946   }
1947   gst_structure_free (s);
1948
1949   return res;
1950 }
1951
1952 static gchar *
1953 gst_value_serialize_segment (const GValue * value)
1954 {
1955   return gst_value_serialize_segment_internal (value, TRUE);
1956 }
1957
1958 static gboolean
1959 gst_value_deserialize_segment (GValue * dest, const gchar * s)
1960 {
1961   GstStructure *str;
1962   GstSegment seg;
1963   gboolean res;
1964
1965   str = gst_structure_from_string (s, NULL);
1966   if (str == NULL)
1967     return FALSE;
1968
1969   res = gst_structure_get (str,
1970       "flags", GST_TYPE_SEGMENT_FLAGS, &seg.flags,
1971       "rate", G_TYPE_DOUBLE, &seg.rate,
1972       "applied-rate", G_TYPE_DOUBLE, &seg.applied_rate,
1973       "format", GST_TYPE_FORMAT, &seg.format,
1974       "base", G_TYPE_UINT64, &seg.base,
1975       "offset", G_TYPE_UINT64, &seg.offset,
1976       "start", G_TYPE_UINT64, &seg.start,
1977       "stop", G_TYPE_UINT64, &seg.stop,
1978       "time", G_TYPE_UINT64, &seg.time,
1979       "position", G_TYPE_UINT64, &seg.position,
1980       "duration", G_TYPE_UINT64, &seg.duration, NULL);
1981   gst_structure_free (str);
1982
1983   if (res)
1984     g_value_set_boxed (dest, &seg);
1985
1986   return res;
1987 }
1988
1989 /****************
1990  * GstStructure *
1991  ****************/
1992
1993 /**
1994  * gst_value_set_structure:
1995  * @value: a GValue initialized to GST_TYPE_STRUCTURE
1996  * @structure: the structure to set the value to
1997  *
1998  * Sets the contents of @value to @structure.  The actual
1999  */
2000 void
2001 gst_value_set_structure (GValue * value, const GstStructure * structure)
2002 {
2003   g_return_if_fail (G_IS_VALUE (value));
2004   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE);
2005   g_return_if_fail (structure == NULL || GST_IS_STRUCTURE (structure));
2006
2007   g_value_set_boxed (value, structure);
2008 }
2009
2010 /**
2011  * gst_value_get_structure:
2012  * @value: a GValue initialized to GST_TYPE_STRUCTURE
2013  *
2014  * Gets the contents of @value.
2015  *
2016  * Returns: (transfer none): the contents of @value
2017  */
2018 const GstStructure *
2019 gst_value_get_structure (const GValue * value)
2020 {
2021   g_return_val_if_fail (G_IS_VALUE (value), NULL);
2022   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE, NULL);
2023
2024   return (GstStructure *) g_value_get_boxed (value);
2025 }
2026
2027 static gchar *
2028 gst_value_serialize_structure (const GValue * value)
2029 {
2030   GstStructure *structure = g_value_get_boxed (value);
2031
2032   return gst_string_take_and_wrap (gst_structure_to_string (structure));
2033 }
2034
2035 static gboolean
2036 gst_value_deserialize_structure (GValue * dest, const gchar * s)
2037 {
2038   GstStructure *structure;
2039
2040   if (*s != '"') {
2041     structure = gst_structure_from_string (s, NULL);
2042   } else {
2043     gchar *str = gst_string_unwrap (s);
2044
2045     if (G_UNLIKELY (!str))
2046       return FALSE;
2047
2048     structure = gst_structure_from_string (str, NULL);
2049     g_free (str);
2050   }
2051
2052   if (G_LIKELY (structure)) {
2053     g_value_take_boxed (dest, structure);
2054     return TRUE;
2055   }
2056   return FALSE;
2057 }
2058
2059 /*******************
2060  * GstCapsFeatures *
2061  *******************/
2062
2063 /**
2064  * gst_value_set_caps_features:
2065  * @value: a GValue initialized to GST_TYPE_CAPS_FEATURES
2066  * @features: the features to set the value to
2067  *
2068  * Sets the contents of @value to @features.
2069  */
2070 void
2071 gst_value_set_caps_features (GValue * value, const GstCapsFeatures * features)
2072 {
2073   g_return_if_fail (G_IS_VALUE (value));
2074   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS_FEATURES);
2075   g_return_if_fail (features == NULL || GST_IS_CAPS_FEATURES (features));
2076
2077   g_value_set_boxed (value, features);
2078 }
2079
2080 /**
2081  * gst_value_get_caps_features:
2082  * @value: a GValue initialized to GST_TYPE_CAPS_FEATURES
2083  *
2084  * Gets the contents of @value.
2085  *
2086  * Returns: (transfer none): the contents of @value
2087  */
2088 const GstCapsFeatures *
2089 gst_value_get_caps_features (const GValue * value)
2090 {
2091   g_return_val_if_fail (G_IS_VALUE (value), NULL);
2092   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS_FEATURES, NULL);
2093
2094   return (GstCapsFeatures *) g_value_get_boxed (value);
2095 }
2096
2097 static gchar *
2098 gst_value_serialize_caps_features (const GValue * value)
2099 {
2100   GstCapsFeatures *features = g_value_get_boxed (value);
2101
2102   return gst_string_take_and_wrap (gst_caps_features_to_string (features));
2103 }
2104
2105 static gboolean
2106 gst_value_deserialize_caps_features (GValue * dest, const gchar * s)
2107 {
2108   GstCapsFeatures *features;
2109
2110   if (*s != '"') {
2111     features = gst_caps_features_from_string (s);
2112   } else {
2113     gchar *str = gst_string_unwrap (s);
2114
2115     if (G_UNLIKELY (!str))
2116       return FALSE;
2117
2118     features = gst_caps_features_from_string (str);
2119     g_free (str);
2120   }
2121
2122   if (G_LIKELY (features)) {
2123     g_value_take_boxed (dest, features);
2124     return TRUE;
2125   }
2126   return FALSE;
2127 }
2128
2129 /**************
2130  * GstTagList *
2131  **************/
2132
2133 static gboolean
2134 gst_value_deserialize_tag_list (GValue * dest, const gchar * s)
2135 {
2136   GstTagList *taglist;
2137
2138   if (*s != '"') {
2139     taglist = gst_tag_list_new_from_string (s);
2140   } else {
2141     gchar *str = gst_string_unwrap (s);
2142
2143     if (G_UNLIKELY (!str))
2144       return FALSE;
2145
2146     taglist = gst_tag_list_new_from_string (str);
2147     g_free (str);
2148   }
2149
2150   if (G_LIKELY (taglist != NULL)) {
2151     g_value_take_boxed (dest, taglist);
2152     return TRUE;
2153   }
2154   return FALSE;
2155 }
2156
2157 static gchar *
2158 gst_value_serialize_tag_list (const GValue * value)
2159 {
2160   GstTagList *taglist = g_value_get_boxed (value);
2161
2162   return gst_string_take_and_wrap (gst_tag_list_to_string (taglist));
2163 }
2164
2165
2166 /*************
2167  * GstBuffer *
2168  *************/
2169
2170 static gint
2171 compare_buffer (GstBuffer * buf1, GstBuffer * buf2)
2172 {
2173   gsize size1, size2;
2174   GstMapInfo info1, info2;
2175   gint result, mret;
2176
2177   if (buf1 == buf2)
2178     return GST_VALUE_EQUAL;
2179
2180   size1 = gst_buffer_get_size (buf1);
2181   size2 = gst_buffer_get_size (buf2);
2182
2183   if (size1 != size2)
2184     return GST_VALUE_UNORDERED;
2185
2186   if (size1 == 0)
2187     return GST_VALUE_EQUAL;
2188
2189   if (!gst_buffer_map (buf1, &info1, GST_MAP_READ))
2190     return GST_VALUE_UNORDERED;
2191
2192   if (!gst_buffer_map (buf2, &info2, GST_MAP_READ)) {
2193     gst_buffer_unmap (buf1, &info1);
2194     return GST_VALUE_UNORDERED;
2195   }
2196
2197   mret = memcmp (info1.data, info2.data, info1.size);
2198   if (mret == 0)
2199     result = GST_VALUE_EQUAL;
2200   else if (mret < 0)
2201     result = GST_VALUE_LESS_THAN;
2202   else
2203     result = GST_VALUE_GREATER_THAN;
2204
2205   gst_buffer_unmap (buf1, &info1);
2206   gst_buffer_unmap (buf2, &info2);
2207
2208   return result;
2209 }
2210
2211 static gint
2212 gst_value_compare_buffer (const GValue * value1, const GValue * value2)
2213 {
2214   GstBuffer *buf1 = gst_value_get_buffer (value1);
2215   GstBuffer *buf2 = gst_value_get_buffer (value2);
2216
2217   return compare_buffer (buf1, buf2);
2218 }
2219
2220 static gchar *
2221 gst_value_serialize_buffer (const GValue * value)
2222 {
2223   GstMapInfo info;
2224   guint8 *data;
2225   gint i;
2226   gchar *string;
2227   GstBuffer *buffer;
2228
2229   buffer = gst_value_get_buffer (value);
2230   if (buffer == NULL)
2231     return NULL;
2232
2233   if (!gst_buffer_map (buffer, &info, GST_MAP_READ))
2234     return NULL;
2235
2236   data = info.data;
2237
2238   string = g_malloc (info.size * 2 + 1);
2239   for (i = 0; i < info.size; i++) {
2240     sprintf (string + i * 2, "%02x", data[i]);
2241   }
2242   string[info.size * 2] = 0;
2243
2244   gst_buffer_unmap (buffer, &info);
2245
2246   return string;
2247 }
2248
2249 static gboolean
2250 gst_value_deserialize_buffer (GValue * dest, const gchar * s)
2251 {
2252   GstBuffer *buffer;
2253   gint len;
2254   gchar ts[3];
2255   GstMapInfo info;
2256   guint8 *data;
2257   gint i;
2258
2259   len = strlen (s);
2260   if (len & 1)
2261     goto wrong_length;
2262
2263   buffer = gst_buffer_new_allocate (NULL, len / 2, NULL);
2264   if (!gst_buffer_map (buffer, &info, GST_MAP_WRITE))
2265     goto map_failed;
2266   data = info.data;
2267
2268   for (i = 0; i < len / 2; i++) {
2269     if (!isxdigit ((int) s[i * 2]) || !isxdigit ((int) s[i * 2 + 1]))
2270       goto wrong_char;
2271
2272     ts[0] = s[i * 2 + 0];
2273     ts[1] = s[i * 2 + 1];
2274     ts[2] = 0;
2275
2276     data[i] = (guint8) strtoul (ts, NULL, 16);
2277   }
2278   gst_buffer_unmap (buffer, &info);
2279
2280   gst_value_take_buffer (dest, buffer);
2281
2282   return TRUE;
2283
2284   /* ERRORS */
2285 wrong_length:
2286   {
2287     return FALSE;
2288   }
2289 map_failed:
2290   {
2291     return FALSE;
2292   }
2293 wrong_char:
2294   {
2295     gst_buffer_unref (buffer);
2296     gst_buffer_unmap (buffer, &info);
2297     return FALSE;
2298   }
2299 }
2300
2301 /*************
2302  * GstSample *
2303  *************/
2304
2305 /* This function is mostly used for comparing image/buffer tags in taglists */
2306 static gint
2307 gst_value_compare_sample (const GValue * value1, const GValue * value2)
2308 {
2309   GstBuffer *buf1 = gst_sample_get_buffer (gst_value_get_sample (value1));
2310   GstBuffer *buf2 = gst_sample_get_buffer (gst_value_get_sample (value2));
2311
2312   /* FIXME: should we take into account anything else such as caps? */
2313   return compare_buffer (buf1, buf2);
2314 }
2315
2316 static gchar *
2317 gst_value_serialize_sample (const GValue * value)
2318 {
2319   const GstStructure *info_structure;
2320   GstSegment *segment;
2321   GstBuffer *buffer;
2322   GstCaps *caps;
2323   GstSample *sample;
2324   GValue val = { 0, };
2325   gchar *info_str, *caps_str, *tmp;
2326   gchar *buf_str, *seg_str, *s;
2327
2328   sample = g_value_get_boxed (value);
2329
2330   buffer = gst_sample_get_buffer (sample);
2331   if (buffer) {
2332     g_value_init (&val, GST_TYPE_BUFFER);
2333     g_value_set_boxed (&val, buffer);
2334     buf_str = gst_value_serialize_buffer (&val);
2335     g_value_unset (&val);
2336   } else {
2337     buf_str = g_strdup ("None");
2338   }
2339
2340   caps = gst_sample_get_caps (sample);
2341   if (caps) {
2342     tmp = gst_caps_to_string (caps);
2343     caps_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1);
2344     g_strdelimit (caps_str, "=", '_');
2345     g_free (tmp);
2346   } else {
2347     caps_str = g_strdup ("None");
2348   }
2349
2350   segment = gst_sample_get_segment (sample);
2351   if (segment) {
2352     g_value_init (&val, GST_TYPE_SEGMENT);
2353     g_value_set_boxed (&val, segment);
2354     tmp = gst_value_serialize_segment_internal (&val, FALSE);
2355     seg_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1);
2356     g_strdelimit (seg_str, "=", '_');
2357     g_free (tmp);
2358     g_value_unset (&val);
2359   } else {
2360     seg_str = g_strdup ("None");
2361   }
2362
2363   info_structure = gst_sample_get_info (sample);
2364   if (info_structure) {
2365     tmp = gst_structure_to_string (info_structure);
2366     info_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1);
2367     g_strdelimit (info_str, "=", '_');
2368     g_free (tmp);
2369   } else {
2370     info_str = g_strdup ("None");
2371   }
2372
2373   s = g_strconcat (buf_str, ":", caps_str, ":", seg_str, ":", info_str, NULL);
2374   g_free (buf_str);
2375   g_free (caps_str);
2376   g_free (seg_str);
2377   g_free (info_str);
2378
2379   return s;
2380 }
2381
2382 static gboolean
2383 gst_value_deserialize_sample (GValue * dest, const gchar * s)
2384 {
2385   GValue bval = G_VALUE_INIT, sval = G_VALUE_INIT;
2386   GstStructure *info;
2387   GstSample *sample;
2388   GstCaps *caps;
2389   gboolean ret = FALSE;
2390   gchar **fields;
2391   gsize outlen;
2392   gint len;
2393
2394   GST_TRACE ("deserialize '%s'", s);
2395
2396   fields = g_strsplit (s, ":", -1);
2397   len = g_strv_length (fields);
2398   if (len != 4)
2399     goto wrong_length;
2400
2401   g_value_init (&bval, GST_TYPE_BUFFER);
2402   g_value_init (&sval, GST_TYPE_SEGMENT);
2403
2404   if (!gst_value_deserialize_buffer (&bval, fields[0]))
2405     goto fail;
2406
2407   if (strcmp (fields[1], "None") != 0) {
2408     g_strdelimit (fields[1], "_", '=');
2409     g_base64_decode_inplace (fields[1], &outlen);
2410     GST_TRACE ("caps    : %s", fields[1]);
2411     caps = gst_caps_from_string (fields[1]);
2412     if (caps == NULL)
2413       goto fail;
2414   } else {
2415     caps = NULL;
2416   }
2417
2418   if (strcmp (fields[2], "None") != 0) {
2419     g_strdelimit (fields[2], "_", '=');
2420     g_base64_decode_inplace (fields[2], &outlen);
2421     GST_TRACE ("segment : %s", fields[2]);
2422     if (!gst_value_deserialize_segment (&sval, fields[2]))
2423       goto fail;
2424   }
2425
2426   if (strcmp (fields[3], "None") != 0) {
2427     g_strdelimit (fields[3], "_", '=');
2428     g_base64_decode_inplace (fields[3], &outlen);
2429     GST_TRACE ("info    : %s", fields[3]);
2430     info = gst_structure_from_string (fields[3], NULL);
2431     if (info == NULL)
2432       goto fail;
2433   } else {
2434     info = NULL;
2435   }
2436
2437   sample = gst_sample_new (gst_value_get_buffer (&bval), caps,
2438       g_value_get_boxed (&sval), info);
2439
2440   g_value_take_boxed (dest, sample);
2441
2442   if (caps)
2443     gst_caps_unref (caps);
2444
2445   ret = TRUE;
2446
2447 fail:
2448
2449   g_value_unset (&bval);
2450   g_value_unset (&sval);
2451
2452 wrong_length:
2453
2454   g_strfreev (fields);
2455
2456   return ret;
2457 }
2458
2459 /***********
2460  * boolean *
2461  ***********/
2462
2463 static gint
2464 gst_value_compare_boolean (const GValue * value1, const GValue * value2)
2465 {
2466   if ((value1->data[0].v_int != 0) == (value2->data[0].v_int != 0))
2467     return GST_VALUE_EQUAL;
2468   return GST_VALUE_UNORDERED;
2469 }
2470
2471 static gchar *
2472 gst_value_serialize_boolean (const GValue * value)
2473 {
2474   if (value->data[0].v_int) {
2475     return g_strdup ("true");
2476   }
2477   return g_strdup ("false");
2478 }
2479
2480 static gboolean
2481 gst_value_deserialize_boolean (GValue * dest, const gchar * s)
2482 {
2483   gboolean ret = FALSE;
2484
2485   if (g_ascii_strcasecmp (s, "true") == 0 ||
2486       g_ascii_strcasecmp (s, "yes") == 0 ||
2487       g_ascii_strcasecmp (s, "t") == 0 || strcmp (s, "1") == 0) {
2488     g_value_set_boolean (dest, TRUE);
2489     ret = TRUE;
2490   } else if (g_ascii_strcasecmp (s, "false") == 0 ||
2491       g_ascii_strcasecmp (s, "no") == 0 ||
2492       g_ascii_strcasecmp (s, "f") == 0 || strcmp (s, "0") == 0) {
2493     g_value_set_boolean (dest, FALSE);
2494     ret = TRUE;
2495   }
2496
2497   return ret;
2498 }
2499
2500 #define CREATE_SERIALIZATION_START(_type,_macro)                        \
2501 static gint                                                             \
2502 gst_value_compare_ ## _type                                             \
2503 (const GValue * value1, const GValue * value2)                          \
2504 {                                                                       \
2505   g ## _type val1 = g_value_get_ ## _type (value1);                     \
2506   g ## _type val2 = g_value_get_ ## _type (value2);                     \
2507   if (val1 > val2)                                                      \
2508     return GST_VALUE_GREATER_THAN;                                      \
2509   if (val1 < val2)                                                      \
2510     return GST_VALUE_LESS_THAN;                                         \
2511   return GST_VALUE_EQUAL;                                               \
2512 }                                                                       \
2513                                                                         \
2514 static gchar *                                                          \
2515 gst_value_serialize_ ## _type (const GValue * value)                    \
2516 {                                                                       \
2517   GValue val = { 0, };                                                  \
2518   g_value_init (&val, G_TYPE_STRING);                                   \
2519   if (!g_value_transform (value, &val))                                 \
2520     g_assert_not_reached ();                                            \
2521   /* NO_COPY_MADNESS!!! */                                              \
2522   return (char *) g_value_get_string (&val);                            \
2523 }
2524
2525 /* deserialize the given s into to as a gint64.
2526  * check if the result is actually storeable in the given size number of
2527  * bytes.
2528  */
2529 static gboolean
2530 gst_value_deserialize_int_helper (gint64 * to, const gchar * s,
2531     gint64 min, gint64 max, gint size)
2532 {
2533   gboolean ret = FALSE;
2534   gchar *end;
2535   gint64 mask = -1;
2536
2537   errno = 0;
2538   *to = g_ascii_strtoull (s, &end, 0);
2539   /* a range error is a definitive no-no */
2540   if (errno == ERANGE) {
2541     return FALSE;
2542   }
2543
2544   if (*end == 0) {
2545     ret = TRUE;
2546   } else {
2547     if (g_ascii_strcasecmp (s, "little_endian") == 0) {
2548       *to = G_LITTLE_ENDIAN;
2549       ret = TRUE;
2550     } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {
2551       *to = G_BIG_ENDIAN;
2552       ret = TRUE;
2553     } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {
2554       *to = G_BYTE_ORDER;
2555       ret = TRUE;
2556     } else if (g_ascii_strcasecmp (s, "min") == 0) {
2557       *to = min;
2558       ret = TRUE;
2559     } else if (g_ascii_strcasecmp (s, "max") == 0) {
2560       *to = max;
2561       ret = TRUE;
2562     }
2563   }
2564   if (ret) {
2565     /* by definition, a gint64 fits into a gint64; so ignore those */
2566     if (size != sizeof (mask)) {
2567       if (*to >= 0) {
2568         /* for positive numbers, we create a mask of 1's outside of the range
2569          * and 0's inside the range.  An and will thus keep only 1 bits
2570          * outside of the range */
2571         mask <<= (size * 8);
2572         if ((mask & *to) != 0) {
2573           ret = FALSE;
2574         }
2575       } else {
2576         /* for negative numbers, we do a 2's complement version */
2577         mask <<= ((size * 8) - 1);
2578         if ((mask & *to) != mask) {
2579           ret = FALSE;
2580         }
2581       }
2582     }
2583   }
2584   return ret;
2585 }
2586
2587 #define CREATE_SERIALIZATION(_type,_macro)                              \
2588 CREATE_SERIALIZATION_START(_type,_macro)                                \
2589                                                                         \
2590 static gboolean                                                         \
2591 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s)         \
2592 {                                                                       \
2593   gint64 x;                                                             \
2594                                                                         \
2595   if (gst_value_deserialize_int_helper (&x, s, G_MIN ## _macro,         \
2596       G_MAX ## _macro, sizeof (g ## _type))) {                          \
2597     g_value_set_ ## _type (dest, /*(g ## _type)*/ x);                   \
2598     return TRUE;                                                        \
2599   } else {                                                              \
2600     return FALSE;                                                       \
2601   }                                                                     \
2602 }
2603
2604 #define CREATE_USERIALIZATION(_type,_macro)                             \
2605 CREATE_SERIALIZATION_START(_type,_macro)                                \
2606                                                                         \
2607 static gboolean                                                         \
2608 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s)         \
2609 {                                                                       \
2610   gint64 x;                                                             \
2611   gchar *end;                                                           \
2612   gboolean ret = FALSE;                                                 \
2613                                                                         \
2614   errno = 0;                                                            \
2615   x = g_ascii_strtoull (s, &end, 0);                                    \
2616   /* a range error is a definitive no-no */                             \
2617   if (errno == ERANGE) {                                                \
2618     return FALSE;                                                       \
2619   }                                                                     \
2620   /* the cast ensures the range check later on makes sense */           \
2621   x = (g ## _type) x;                                                   \
2622   if (*end == 0) {                                                      \
2623     ret = TRUE;                                                         \
2624   } else {                                                              \
2625     if (g_ascii_strcasecmp (s, "little_endian") == 0) {                 \
2626       x = G_LITTLE_ENDIAN;                                              \
2627       ret = TRUE;                                                       \
2628     } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {             \
2629       x = G_BIG_ENDIAN;                                                 \
2630       ret = TRUE;                                                       \
2631     } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {             \
2632       x = G_BYTE_ORDER;                                                 \
2633       ret = TRUE;                                                       \
2634     } else if (g_ascii_strcasecmp (s, "min") == 0) {                    \
2635       x = 0;                                                            \
2636       ret = TRUE;                                                       \
2637     } else if (g_ascii_strcasecmp (s, "max") == 0) {                    \
2638       x = G_MAX ## _macro;                                              \
2639       ret = TRUE;                                                       \
2640     }                                                                   \
2641   }                                                                     \
2642   if (ret) {                                                            \
2643     if (x > G_MAX ## _macro) {                                          \
2644       ret = FALSE;                                                      \
2645     } else {                                                            \
2646       g_value_set_ ## _type (dest, x);                                  \
2647     }                                                                   \
2648   }                                                                     \
2649   return ret;                                                           \
2650 }
2651
2652 #define REGISTER_SERIALIZATION(_gtype, _type)                           \
2653 G_STMT_START {                                                          \
2654   static const GstValueTable gst_value = {                              \
2655     _gtype,                                                             \
2656     gst_value_compare_ ## _type,                                        \
2657     gst_value_serialize_ ## _type,                                      \
2658     gst_value_deserialize_ ## _type,                                    \
2659   };                                                                    \
2660                                                                         \
2661   gst_value_register (&gst_value);                                      \
2662 } G_STMT_END
2663
2664 CREATE_SERIALIZATION (int, INT);
2665 CREATE_SERIALIZATION (int64, INT64);
2666 CREATE_SERIALIZATION (long, LONG);
2667
2668 CREATE_USERIALIZATION (uint, UINT);
2669 CREATE_USERIALIZATION (uint64, UINT64);
2670 CREATE_USERIALIZATION (ulong, ULONG);
2671
2672 /* FIXME 0.11: remove this again, plugins shouldn't have uchar properties */
2673 #ifndef G_MAXUCHAR
2674 #define G_MAXUCHAR 255
2675 #endif
2676 CREATE_USERIALIZATION (uchar, UCHAR);
2677
2678 /**********
2679  * double *
2680  **********/
2681 static gint
2682 gst_value_compare_double (const GValue * value1, const GValue * value2)
2683 {
2684   if (value1->data[0].v_double > value2->data[0].v_double)
2685     return GST_VALUE_GREATER_THAN;
2686   if (value1->data[0].v_double < value2->data[0].v_double)
2687     return GST_VALUE_LESS_THAN;
2688   if (value1->data[0].v_double == value2->data[0].v_double)
2689     return GST_VALUE_EQUAL;
2690   return GST_VALUE_UNORDERED;
2691 }
2692
2693 static gchar *
2694 gst_value_serialize_double (const GValue * value)
2695 {
2696   gchar d[G_ASCII_DTOSTR_BUF_SIZE];
2697
2698   g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
2699   return g_strdup (d);
2700 }
2701
2702 static gboolean
2703 gst_value_deserialize_double (GValue * dest, const gchar * s)
2704 {
2705   gdouble x;
2706   gboolean ret = FALSE;
2707   gchar *end;
2708
2709   x = g_ascii_strtod (s, &end);
2710   if (*end == 0) {
2711     ret = TRUE;
2712   } else {
2713     if (g_ascii_strcasecmp (s, "min") == 0) {
2714       x = -G_MAXDOUBLE;
2715       ret = TRUE;
2716     } else if (g_ascii_strcasecmp (s, "max") == 0) {
2717       x = G_MAXDOUBLE;
2718       ret = TRUE;
2719     }
2720   }
2721   if (ret) {
2722     g_value_set_double (dest, x);
2723   }
2724   return ret;
2725 }
2726
2727 /*********
2728  * float *
2729  *********/
2730
2731 static gint
2732 gst_value_compare_float (const GValue * value1, const GValue * value2)
2733 {
2734   if (value1->data[0].v_float > value2->data[0].v_float)
2735     return GST_VALUE_GREATER_THAN;
2736   if (value1->data[0].v_float < value2->data[0].v_float)
2737     return GST_VALUE_LESS_THAN;
2738   if (value1->data[0].v_float == value2->data[0].v_float)
2739     return GST_VALUE_EQUAL;
2740   return GST_VALUE_UNORDERED;
2741 }
2742
2743 static gchar *
2744 gst_value_serialize_float (const GValue * value)
2745 {
2746   gchar d[G_ASCII_DTOSTR_BUF_SIZE];
2747
2748   g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_float);
2749   return g_strdup (d);
2750 }
2751
2752 static gboolean
2753 gst_value_deserialize_float (GValue * dest, const gchar * s)
2754 {
2755   gdouble x;
2756   gboolean ret = FALSE;
2757   gchar *end;
2758
2759   x = g_ascii_strtod (s, &end);
2760   if (*end == 0) {
2761     ret = TRUE;
2762   } else {
2763     if (g_ascii_strcasecmp (s, "min") == 0) {
2764       x = -G_MAXFLOAT;
2765       ret = TRUE;
2766     } else if (g_ascii_strcasecmp (s, "max") == 0) {
2767       x = G_MAXFLOAT;
2768       ret = TRUE;
2769     }
2770   }
2771   if (x > G_MAXFLOAT || x < -G_MAXFLOAT)
2772     ret = FALSE;
2773   if (ret) {
2774     g_value_set_float (dest, (float) x);
2775   }
2776   return ret;
2777 }
2778
2779 /**********
2780  * string *
2781  **********/
2782
2783 static gint
2784 gst_value_compare_string (const GValue * value1, const GValue * value2)
2785 {
2786   if (G_UNLIKELY (!value1->data[0].v_pointer || !value2->data[0].v_pointer)) {
2787     /* if only one is NULL, no match - otherwise both NULL == EQUAL */
2788     if (value1->data[0].v_pointer != value2->data[0].v_pointer)
2789       return GST_VALUE_UNORDERED;
2790   } else {
2791     gint x = strcmp (value1->data[0].v_pointer, value2->data[0].v_pointer);
2792
2793     if (x < 0)
2794       return GST_VALUE_LESS_THAN;
2795     if (x > 0)
2796       return GST_VALUE_GREATER_THAN;
2797   }
2798
2799   return GST_VALUE_EQUAL;
2800 }
2801
2802 static gint
2803 gst_string_measure_wrapping (const gchar * s)
2804 {
2805   gint len;
2806   gboolean wrap = FALSE;
2807
2808   if (G_UNLIKELY (s == NULL))
2809     return -1;
2810
2811   /* Special case: the actual string NULL needs wrapping */
2812   if (G_UNLIKELY (strcmp (s, "NULL") == 0))
2813     return 4;
2814
2815   len = 0;
2816   while (*s) {
2817     if (GST_ASCII_IS_STRING (*s)) {
2818       len++;
2819     } else if (*s < 0x20 || *s >= 0x7f) {
2820       wrap = TRUE;
2821       len += 4;
2822     } else {
2823       wrap = TRUE;
2824       len += 2;
2825     }
2826     s++;
2827   }
2828
2829   /* Wrap the string if we found something that needs
2830    * wrapping, or the empty string (len == 0) */
2831   return (wrap || len == 0) ? len : -1;
2832 }
2833
2834 static gchar *
2835 gst_string_wrap_inner (const gchar * s, gint len)
2836 {
2837   gchar *d, *e;
2838
2839   e = d = g_malloc (len + 3);
2840
2841   *e++ = '\"';
2842   while (*s) {
2843     if (GST_ASCII_IS_STRING (*s)) {
2844       *e++ = *s++;
2845     } else if (*s < 0x20 || *s >= 0x7f) {
2846       *e++ = '\\';
2847       *e++ = '0' + ((*(guchar *) s) >> 6);
2848       *e++ = '0' + (((*s) >> 3) & 0x7);
2849       *e++ = '0' + ((*s++) & 0x7);
2850     } else {
2851       *e++ = '\\';
2852       *e++ = *s++;
2853     }
2854   }
2855   *e++ = '\"';
2856   *e = 0;
2857
2858   g_assert (e - d <= len + 3);
2859   return d;
2860 }
2861
2862 /* Do string wrapping/escaping */
2863 static gchar *
2864 gst_string_wrap (const gchar * s)
2865 {
2866   gint len = gst_string_measure_wrapping (s);
2867
2868   if (G_LIKELY (len < 0))
2869     return g_strdup (s);
2870
2871   return gst_string_wrap_inner (s, len);
2872 }
2873
2874 /* Same as above, but take ownership of the string */
2875 static gchar *
2876 gst_string_take_and_wrap (gchar * s)
2877 {
2878   gchar *out;
2879   gint len = gst_string_measure_wrapping (s);
2880
2881   if (G_LIKELY (len < 0))
2882     return s;
2883
2884   out = gst_string_wrap_inner (s, len);
2885   g_free (s);
2886
2887   return out;
2888 }
2889
2890 /*
2891  * This function takes a string delimited with double quotes (")
2892  * and unescapes any \xxx octal numbers.
2893  *
2894  * If sequences of \y are found where y is not in the range of
2895  * 0->3, y is copied unescaped.
2896  *
2897  * If \xyy is found where x is an octal number but y is not, an
2898  * error is encountered and NULL is returned.
2899  *
2900  * the input string must be \0 terminated.
2901  */
2902 static gchar *
2903 gst_string_unwrap (const gchar * s)
2904 {
2905   gchar *ret;
2906   gchar *read, *write;
2907
2908   /* NULL string returns NULL */
2909   if (s == NULL)
2910     return NULL;
2911
2912   /* strings not starting with " are invalid */
2913   if (*s != '"')
2914     return NULL;
2915
2916   /* make copy of original string to hold the result. This
2917    * string will always be smaller than the original */
2918   ret = g_strdup (s);
2919   read = ret;
2920   write = ret;
2921
2922   /* need to move to the next position as we parsed the " */
2923   read++;
2924
2925   while (*read) {
2926     if (GST_ASCII_IS_STRING (*read)) {
2927       /* normal chars are just copied */
2928       *write++ = *read++;
2929     } else if (*read == '"') {
2930       /* quote marks end of string */
2931       break;
2932     } else if (*read == '\\') {
2933       /* got an escape char, move to next position to read a tripplet
2934        * of octal numbers */
2935       read++;
2936       /* is the next char a possible first octal number? */
2937       if (*read >= '0' && *read <= '3') {
2938         /* parse other 2 numbers, if one of them is not in the range of
2939          * an octal number, we error. We also catch the case where a zero
2940          * byte is found here. */
2941         if (read[1] < '0' || read[1] > '7' || read[2] < '0' || read[2] > '7')
2942           goto beach;
2943
2944         /* now convert the octal number to a byte again. */
2945         *write++ = ((read[0] - '0') << 6) +
2946             ((read[1] - '0') << 3) + (read[2] - '0');
2947
2948         read += 3;
2949       } else {
2950         /* if we run into a \0 here, we definitely won't get a quote later */
2951         if (*read == 0)
2952           goto beach;
2953
2954         /* else copy \X sequence */
2955         *write++ = *read++;
2956       }
2957     } else {
2958       /* weird character, error */
2959       goto beach;
2960     }
2961   }
2962   /* if the string is not ending in " and zero terminated, we error */
2963   if (*read != '"' || read[1] != '\0')
2964     goto beach;
2965
2966   /* null terminate result string and return */
2967   *write = '\0';
2968   return ret;
2969
2970 beach:
2971   g_free (ret);
2972   return NULL;
2973 }
2974
2975 static gchar *
2976 gst_value_serialize_string (const GValue * value)
2977 {
2978   return gst_string_wrap (value->data[0].v_pointer);
2979 }
2980
2981 static gboolean
2982 gst_value_deserialize_string (GValue * dest, const gchar * s)
2983 {
2984   if (G_UNLIKELY (strcmp (s, "NULL") == 0)) {
2985     g_value_set_string (dest, NULL);
2986     return TRUE;
2987   } else if (G_LIKELY (*s != '"')) {
2988     if (!g_utf8_validate (s, -1, NULL))
2989       return FALSE;
2990     g_value_set_string (dest, s);
2991     return TRUE;
2992   } else {
2993     gchar *str = gst_string_unwrap (s);
2994     if (G_UNLIKELY (!str))
2995       return FALSE;
2996     g_value_take_string (dest, str);
2997   }
2998
2999   return TRUE;
3000 }
3001
3002 /********
3003  * enum *
3004  ********/
3005
3006 static gint
3007 gst_value_compare_enum (const GValue * value1, const GValue * value2)
3008 {
3009   GEnumValue *en1, *en2;
3010   GEnumClass *klass1 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value1));
3011   GEnumClass *klass2 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value2));
3012
3013   g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
3014   g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
3015   en1 = g_enum_get_value (klass1, g_value_get_enum (value1));
3016   en2 = g_enum_get_value (klass2, g_value_get_enum (value2));
3017   g_type_class_unref (klass1);
3018   g_type_class_unref (klass2);
3019   g_return_val_if_fail (en1, GST_VALUE_UNORDERED);
3020   g_return_val_if_fail (en2, GST_VALUE_UNORDERED);
3021   if (en1->value < en2->value)
3022     return GST_VALUE_LESS_THAN;
3023   if (en1->value > en2->value)
3024     return GST_VALUE_GREATER_THAN;
3025
3026   return GST_VALUE_EQUAL;
3027 }
3028
3029 static gchar *
3030 gst_value_serialize_enum (const GValue * value)
3031 {
3032   GEnumValue *en;
3033   GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value));
3034
3035   g_return_val_if_fail (klass, NULL);
3036   en = g_enum_get_value (klass, g_value_get_enum (value));
3037   g_type_class_unref (klass);
3038
3039   /* might be one of the custom formats registered later */
3040   if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (value) == GST_TYPE_FORMAT)) {
3041     const GstFormatDefinition *format_def;
3042
3043     format_def = gst_format_get_details ((GstFormat) g_value_get_enum (value));
3044     g_return_val_if_fail (format_def != NULL, NULL);
3045     return g_strdup (format_def->description);
3046   }
3047
3048   g_return_val_if_fail (en, NULL);
3049   return g_strdup (en->value_name);
3050 }
3051
3052 static gint
3053 gst_value_deserialize_enum_iter_cmp (const GValue * format_def_value,
3054     const gchar * s)
3055 {
3056   const GstFormatDefinition *format_def =
3057       g_value_get_pointer (format_def_value);
3058
3059   if (g_ascii_strcasecmp (s, format_def->nick) == 0)
3060     return 0;
3061
3062   return g_ascii_strcasecmp (s, format_def->description);
3063 }
3064
3065 static gboolean
3066 gst_value_deserialize_enum (GValue * dest, const gchar * s)
3067 {
3068   GEnumValue *en;
3069   gchar *endptr = NULL;
3070   GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (dest));
3071
3072   g_return_val_if_fail (klass, FALSE);
3073   if (!(en = g_enum_get_value_by_name (klass, s))) {
3074     if (!(en = g_enum_get_value_by_nick (klass, s))) {
3075       gint i = strtol (s, &endptr, 0);
3076
3077       if (endptr && *endptr == '\0') {
3078         en = g_enum_get_value (klass, i);
3079       }
3080     }
3081   }
3082   g_type_class_unref (klass);
3083
3084   /* might be one of the custom formats registered later */
3085   if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (dest) == GST_TYPE_FORMAT)) {
3086     GValue res = { 0, };
3087     const GstFormatDefinition *format_def;
3088     GstIterator *iter;
3089     gboolean found;
3090
3091     iter = gst_format_iterate_definitions ();
3092
3093     found = gst_iterator_find_custom (iter,
3094         (GCompareFunc) gst_value_deserialize_enum_iter_cmp, &res, (gpointer) s);
3095
3096     if (found) {
3097       format_def = g_value_get_pointer (&res);
3098       g_return_val_if_fail (format_def != NULL, FALSE);
3099       g_value_set_enum (dest, (gint) format_def->value);
3100       g_value_unset (&res);
3101     }
3102     gst_iterator_free (iter);
3103     return found;
3104   }
3105
3106   /* enum name/nick not found */
3107   if (en == NULL)
3108     return FALSE;
3109
3110   g_value_set_enum (dest, en->value);
3111   return TRUE;
3112 }
3113
3114 /********
3115  * flags *
3116  ********/
3117
3118 /* we just compare the value here */
3119 static gint
3120 gst_value_compare_flags (const GValue * value1, const GValue * value2)
3121 {
3122   guint fl1, fl2;
3123   GFlagsClass *klass1 =
3124       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value1));
3125   GFlagsClass *klass2 =
3126       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value2));
3127
3128   g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
3129   g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
3130   fl1 = g_value_get_flags (value1);
3131   fl2 = g_value_get_flags (value2);
3132   g_type_class_unref (klass1);
3133   g_type_class_unref (klass2);
3134   if (fl1 < fl2)
3135     return GST_VALUE_LESS_THAN;
3136   if (fl1 > fl2)
3137     return GST_VALUE_GREATER_THAN;
3138
3139   return GST_VALUE_EQUAL;
3140 }
3141
3142 /* the different flags are serialized separated with a + */
3143 static gchar *
3144 gst_value_serialize_flags (const GValue * value)
3145 {
3146   guint flags;
3147   GFlagsValue *fl;
3148   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value));
3149   gchar *result, *tmp;
3150   gboolean first = TRUE;
3151
3152   g_return_val_if_fail (klass, NULL);
3153
3154   flags = g_value_get_flags (value);
3155
3156   /* if no flags are set, try to serialize to the _NONE string */
3157   if (!flags) {
3158     fl = g_flags_get_first_value (klass, flags);
3159     if (fl)
3160       return g_strdup (fl->value_name);
3161     else
3162       return g_strdup ("0");
3163   }
3164
3165   /* some flags are set, so serialize one by one */
3166   result = g_strdup ("");
3167   while (flags) {
3168     fl = g_flags_get_first_value (klass, flags);
3169     if (fl != NULL) {
3170       tmp = g_strconcat (result, (first ? "" : "+"), fl->value_name, NULL);
3171       g_free (result);
3172       result = tmp;
3173       first = FALSE;
3174
3175       /* clear flag */
3176       flags &= ~fl->value;
3177     }
3178   }
3179   g_type_class_unref (klass);
3180
3181   return result;
3182 }
3183
3184 static gboolean
3185 gst_value_deserialize_flags (GValue * dest, const gchar * s)
3186 {
3187   GFlagsValue *fl;
3188   gchar *endptr = NULL;
3189   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (dest));
3190   gchar **split;
3191   guint flags;
3192   gint i;
3193
3194   g_return_val_if_fail (klass, FALSE);
3195
3196   /* split into parts delimited with + */
3197   split = g_strsplit (s, "+", 0);
3198
3199   flags = 0;
3200   i = 0;
3201   /* loop over each part */
3202   while (split[i]) {
3203     if (!(fl = g_flags_get_value_by_name (klass, split[i]))) {
3204       if (!(fl = g_flags_get_value_by_nick (klass, split[i]))) {
3205         gint val = strtol (split[i], &endptr, 0);
3206
3207         /* just or numeric value */
3208         if (endptr && *endptr == '\0') {
3209           flags |= val;
3210         }
3211       }
3212     }
3213     if (fl) {
3214       flags |= fl->value;
3215     }
3216     i++;
3217   }
3218   g_strfreev (split);
3219   g_type_class_unref (klass);
3220   g_value_set_flags (dest, flags);
3221
3222   return TRUE;
3223 }
3224
3225 /****************
3226  * subset *
3227  ****************/
3228
3229 static gboolean
3230 gst_value_is_subset_int_range_int_range (const GValue * value1,
3231     const GValue * value2)
3232 {
3233   gint gcd;
3234
3235   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value1), FALSE);
3236   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value2), FALSE);
3237
3238   if (INT_RANGE_MIN (value1) * INT_RANGE_STEP (value1) <
3239       INT_RANGE_MIN (value2) * INT_RANGE_STEP (value2))
3240     return FALSE;
3241   if (INT_RANGE_MAX (value1) * INT_RANGE_STEP (value1) >
3242       INT_RANGE_MAX (value2) * INT_RANGE_STEP (value2))
3243     return FALSE;
3244
3245   if (INT_RANGE_MIN (value2) == INT_RANGE_MAX (value2)) {
3246     if ((INT_RANGE_MIN (value2) * INT_RANGE_STEP (value2)) %
3247         INT_RANGE_STEP (value1))
3248       return FALSE;
3249     return TRUE;
3250   }
3251
3252   gcd =
3253       gst_util_greatest_common_divisor (INT_RANGE_STEP (value1),
3254       INT_RANGE_STEP (value2));
3255   if (gcd != MIN (INT_RANGE_STEP (value1), INT_RANGE_STEP (value2)))
3256     return FALSE;
3257
3258   return TRUE;
3259 }
3260
3261 static gboolean
3262 gst_value_is_subset_int64_range_int64_range (const GValue * value1,
3263     const GValue * value2)
3264 {
3265   gint64 gcd;
3266
3267   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value1), FALSE);
3268   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value2), FALSE);
3269
3270   if (INT64_RANGE_MIN (value1) < INT64_RANGE_MIN (value2))
3271     return FALSE;
3272   if (INT64_RANGE_MAX (value1) > INT64_RANGE_MAX (value2))
3273     return FALSE;
3274
3275   if (INT64_RANGE_MIN (value2) == INT64_RANGE_MAX (value2)) {
3276     if ((INT64_RANGE_MIN (value2) * INT64_RANGE_STEP (value2)) %
3277         INT64_RANGE_STEP (value1))
3278       return FALSE;
3279     return TRUE;
3280   }
3281
3282   gcd =
3283       gst_util_greatest_common_divisor_int64 (INT64_RANGE_STEP (value1),
3284       INT64_RANGE_STEP (value2));
3285   if (gcd != MIN (INT64_RANGE_STEP (value1), INT64_RANGE_STEP (value2)))
3286     return FALSE;
3287
3288   return TRUE;
3289 }
3290
3291 /**
3292  * gst_value_is_subset:
3293  * @value1: a #GValue
3294  * @value2: a #GValue
3295  *
3296  * Check that @value1 is a subset of @value2.
3297  *
3298  * Return: %TRUE is @value1 is a subset of @value2
3299  */
3300 gboolean
3301 gst_value_is_subset (const GValue * value1, const GValue * value2)
3302 {
3303   /* special case for int/int64 ranges, since we cannot compute
3304      the difference for those when they have different steps,
3305      and it's actually a lot simpler to compute whether a range
3306      is a subset of another. */
3307   if (GST_VALUE_HOLDS_INT_RANGE (value1) && GST_VALUE_HOLDS_INT_RANGE (value2)) {
3308     return gst_value_is_subset_int_range_int_range (value1, value2);
3309   } else if (GST_VALUE_HOLDS_INT64_RANGE (value1)
3310       && GST_VALUE_HOLDS_INT64_RANGE (value2)) {
3311     return gst_value_is_subset_int64_range_int64_range (value1, value2);
3312   }
3313
3314   /*
3315    * 1 - [1,2] = empty
3316    * -> !subset
3317    *
3318    * [1,2] - 1 = 2
3319    *  -> 1 - [1,2] = empty
3320    *  -> subset
3321    *
3322    * [1,3] - [1,2] = 3
3323    * -> [1,2] - [1,3] = empty
3324    * -> subset
3325    *
3326    * {1,2} - {1,3} = 2
3327    * -> {1,3} - {1,2} = 3
3328    * -> !subset
3329    *
3330    *  First caps subtraction needs to return a non-empty set, second
3331    *  subtractions needs to give en empty set.
3332    *  Both substractions are switched below, as it's faster that way.
3333    */
3334   if (!gst_value_subtract (NULL, value1, value2)) {
3335     if (gst_value_subtract (NULL, value2, value1)) {
3336       return TRUE;
3337     }
3338   }
3339   return FALSE;
3340 }
3341
3342 /*********
3343  * union *
3344  *********/
3345
3346 static gboolean
3347 gst_value_union_int_int_range (GValue * dest, const GValue * src1,
3348     const GValue * src2)
3349 {
3350   gint v = src1->data[0].v_int;
3351
3352   /* check if it's already in the range */
3353   if (INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2) <= v &&
3354       INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2) >= v &&
3355       v % INT_RANGE_STEP (src2) == 0) {
3356     if (dest)
3357       gst_value_init_and_copy (dest, src2);
3358     return TRUE;
3359   }
3360
3361   /* check if it extends the range */
3362   if (v == (INT_RANGE_MIN (src2) - 1) * INT_RANGE_STEP (src2)) {
3363     if (dest) {
3364       gst_value_init_and_copy (dest, src2);
3365       --INT_RANGE_MIN (src2);
3366     }
3367     return TRUE;
3368   }
3369   if (v == (INT_RANGE_MAX (src2) + 1) * INT_RANGE_STEP (src2)) {
3370     if (dest) {
3371       gst_value_init_and_copy (dest, src2);
3372       ++INT_RANGE_MAX (src2);
3373     }
3374     return TRUE;
3375   }
3376
3377   return FALSE;
3378 }
3379
3380 static gboolean
3381 gst_value_union_int_range_int_range (GValue * dest, const GValue * src1,
3382     const GValue * src2)
3383 {
3384   /* We can union in several special cases:
3385      1 - one is a subset of another
3386      2 - same step and not disjoint
3387      3 - different step, at least one with one value which matches a 'next' or 'previous'
3388      - anything else ?
3389    */
3390
3391   /* 1 - subset */
3392   if (gst_value_is_subset_int_range_int_range (src1, src2)) {
3393     if (dest)
3394       gst_value_init_and_copy (dest, src2);
3395     return TRUE;
3396   }
3397   if (gst_value_is_subset_int_range_int_range (src2, src1)) {
3398     if (dest)
3399       gst_value_init_and_copy (dest, src1);
3400     return TRUE;
3401   }
3402
3403   /* 2 - same step and not disjoint */
3404   if (INT_RANGE_STEP (src1) == INT_RANGE_STEP (src2)) {
3405     if ((INT_RANGE_MIN (src1) <= INT_RANGE_MAX (src2) + 1 &&
3406             INT_RANGE_MAX (src1) >= INT_RANGE_MIN (src2) - 1) ||
3407         (INT_RANGE_MIN (src2) <= INT_RANGE_MAX (src1) + 1 &&
3408             INT_RANGE_MAX (src2) >= INT_RANGE_MIN (src1) - 1)) {
3409       if (dest) {
3410         gint step = INT_RANGE_STEP (src1);
3411         gint min = step * MIN (INT_RANGE_MIN (src1), INT_RANGE_MIN (src2));
3412         gint max = step * MAX (INT_RANGE_MAX (src1), INT_RANGE_MAX (src2));
3413         g_value_init (dest, GST_TYPE_INT_RANGE);
3414         gst_value_set_int_range_step (dest, min, max, step);
3415       }
3416       return TRUE;
3417     }
3418   }
3419
3420   /* 3 - single value matches next or previous */
3421   if (INT_RANGE_STEP (src1) != INT_RANGE_STEP (src2)) {
3422     gint n1 = INT_RANGE_MAX (src1) - INT_RANGE_MIN (src1) + 1;
3423     gint n2 = INT_RANGE_MAX (src2) - INT_RANGE_MIN (src2) + 1;
3424     if (n1 == 1 || n2 == 1) {
3425       const GValue *range_value = NULL;
3426       gint scalar = 0;
3427       if (n1 == 1) {
3428         range_value = src2;
3429         scalar = INT_RANGE_MIN (src1) * INT_RANGE_STEP (src1);
3430       } else if (n2 == 1) {
3431         range_value = src1;
3432         scalar = INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2);
3433       }
3434
3435       if (scalar ==
3436           (INT_RANGE_MIN (range_value) - 1) * INT_RANGE_STEP (range_value)) {
3437         if (dest) {
3438           gst_value_init_and_copy (dest, range_value);
3439           --INT_RANGE_MIN (range_value);
3440         }
3441         return TRUE;
3442       } else if (scalar ==
3443           (INT_RANGE_MAX (range_value) + 1) * INT_RANGE_STEP (range_value)) {
3444         if (dest) {
3445           gst_value_init_and_copy (dest, range_value);
3446           ++INT_RANGE_MIN (range_value);
3447         }
3448         return TRUE;
3449       }
3450     }
3451   }
3452
3453   /* If we get there, we did not find a way to make a union that can be
3454      represented with our simplistic model. */
3455   return FALSE;
3456 }
3457
3458 /****************
3459  * intersection *
3460  ****************/
3461
3462 static gboolean
3463 gst_value_intersect_int_int_range (GValue * dest, const GValue * src1,
3464     const GValue * src2)
3465 {
3466   if (INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2) <= src1->data[0].v_int &&
3467       INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2) >= src1->data[0].v_int &&
3468       src1->data[0].v_int % INT_RANGE_STEP (src2) == 0) {
3469     if (dest)
3470       gst_value_init_and_copy (dest, src1);
3471     return TRUE;
3472   }
3473
3474   return FALSE;
3475 }
3476
3477 static gboolean
3478 gst_value_intersect_int_range_int_range (GValue * dest, const GValue * src1,
3479     const GValue * src2)
3480 {
3481   gint min;
3482   gint max;
3483   gint step;
3484
3485   step =
3486       INT_RANGE_STEP (src1) /
3487       gst_util_greatest_common_divisor (INT_RANGE_STEP (src1),
3488       INT_RANGE_STEP (src2));
3489   if (G_MAXINT32 / INT_RANGE_STEP (src2) < step)
3490     return FALSE;
3491   step *= INT_RANGE_STEP (src2);
3492
3493   min =
3494       MAX (INT_RANGE_MIN (src1) * INT_RANGE_STEP (src1),
3495       INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2));
3496   min = (min + step - 1) / step * step;
3497   max =
3498       MIN (INT_RANGE_MAX (src1) * INT_RANGE_STEP (src1),
3499       INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2));
3500   max = max / step * step;
3501
3502   if (min < max) {
3503     if (dest) {
3504       g_value_init (dest, GST_TYPE_INT_RANGE);
3505       gst_value_set_int_range_step (dest, min, max, step);
3506     }
3507     return TRUE;
3508   }
3509   if (min == max) {
3510     if (dest) {
3511       g_value_init (dest, G_TYPE_INT);
3512       g_value_set_int (dest, min);
3513     }
3514     return TRUE;
3515   }
3516
3517   return FALSE;
3518 }
3519
3520 #define INT64_RANGE_MIN_VAL(v) (INT64_RANGE_MIN (v) * INT64_RANGE_STEP (v))
3521 #define INT64_RANGE_MAX_VAL(v) (INT64_RANGE_MAX (v) * INT64_RANGE_STEP (v))
3522
3523 static gboolean
3524 gst_value_intersect_int64_int64_range (GValue * dest, const GValue * src1,
3525     const GValue * src2)
3526 {
3527   if (INT64_RANGE_MIN_VAL (src2) <= src1->data[0].v_int64 &&
3528       INT64_RANGE_MAX_VAL (src2) >= src1->data[0].v_int64 &&
3529       src1->data[0].v_int64 % INT64_RANGE_STEP (src2) == 0) {
3530     if (dest)
3531       gst_value_init_and_copy (dest, src1);
3532     return TRUE;
3533   }
3534
3535   return FALSE;
3536 }
3537
3538 static gboolean
3539 gst_value_intersect_int64_range_int64_range (GValue * dest, const GValue * src1,
3540     const GValue * src2)
3541 {
3542   gint64 min;
3543   gint64 max;
3544   gint64 step;
3545
3546   step =
3547       INT64_RANGE_STEP (src1) /
3548       gst_util_greatest_common_divisor_int64 (INT64_RANGE_STEP (src1),
3549       INT64_RANGE_STEP (src2));
3550   if (G_MAXINT64 / INT64_RANGE_STEP (src2) < step)
3551     return FALSE;
3552   step *= INT64_RANGE_STEP (src2);
3553
3554   min =
3555       MAX (INT64_RANGE_MIN (src1) * INT64_RANGE_STEP (src1),
3556       INT64_RANGE_MIN (src2) * INT64_RANGE_STEP (src2));
3557   min = (min + step - 1) / step * step;
3558   max =
3559       MIN (INT64_RANGE_MAX (src1) * INT64_RANGE_STEP (src1),
3560       INT64_RANGE_MAX (src2) * INT64_RANGE_STEP (src2));
3561   max = max / step * step;
3562
3563   if (min < max) {
3564     if (dest) {
3565       g_value_init (dest, GST_TYPE_INT64_RANGE);
3566       gst_value_set_int64_range_step (dest, min, max, step);
3567     }
3568     return TRUE;
3569   }
3570   if (min == max) {
3571     if (dest) {
3572       g_value_init (dest, G_TYPE_INT64);
3573       g_value_set_int64 (dest, min);
3574     }
3575     return TRUE;
3576   }
3577
3578   return FALSE;
3579 }
3580
3581 static gboolean
3582 gst_value_intersect_double_double_range (GValue * dest, const GValue * src1,
3583     const GValue * src2)
3584 {
3585   if (src2->data[0].v_double <= src1->data[0].v_double &&
3586       src2->data[1].v_double >= src1->data[0].v_double) {
3587     if (dest)
3588       gst_value_init_and_copy (dest, src1);
3589     return TRUE;
3590   }
3591
3592   return FALSE;
3593 }
3594
3595 static gboolean
3596 gst_value_intersect_double_range_double_range (GValue * dest,
3597     const GValue * src1, const GValue * src2)
3598 {
3599   gdouble min;
3600   gdouble max;
3601
3602   min = MAX (src1->data[0].v_double, src2->data[0].v_double);
3603   max = MIN (src1->data[1].v_double, src2->data[1].v_double);
3604
3605   if (min < max) {
3606     if (dest) {
3607       g_value_init (dest, GST_TYPE_DOUBLE_RANGE);
3608       gst_value_set_double_range (dest, min, max);
3609     }
3610     return TRUE;
3611   }
3612   if (min == max) {
3613     if (dest) {
3614       g_value_init (dest, G_TYPE_DOUBLE);
3615       g_value_set_int (dest, (int) min);
3616     }
3617     return TRUE;
3618   }
3619
3620   return FALSE;
3621 }
3622
3623 static gboolean
3624 gst_value_intersect_list (GValue * dest, const GValue * value1,
3625     const GValue * value2)
3626 {
3627   guint i, size;
3628   GValue intersection = { 0, };
3629   gboolean ret = FALSE;
3630
3631   size = VALUE_LIST_SIZE (value1);
3632   for (i = 0; i < size; i++) {
3633     const GValue *cur = VALUE_LIST_GET_VALUE (value1, i);
3634
3635     /* quicker version when we don't need the resulting set */
3636     if (!dest) {
3637       if (gst_value_intersect (NULL, cur, value2)) {
3638         ret = TRUE;
3639         break;
3640       }
3641       continue;
3642     }
3643
3644     if (gst_value_intersect (&intersection, cur, value2)) {
3645       /* append value */
3646       if (!ret) {
3647         gst_value_move (dest, &intersection);
3648         ret = TRUE;
3649       } else if (GST_VALUE_HOLDS_LIST (dest)) {
3650         _gst_value_list_append_and_take_value (dest, &intersection);
3651       } else {
3652         GValue temp;
3653
3654         gst_value_move (&temp, dest);
3655         gst_value_list_merge (dest, &temp, &intersection);
3656         g_value_unset (&temp);
3657         g_value_unset (&intersection);
3658       }
3659     }
3660   }
3661
3662   return ret;
3663 }
3664
3665 static gboolean
3666 gst_value_intersect_array (GValue * dest, const GValue * src1,
3667     const GValue * src2)
3668 {
3669   guint size;
3670   guint n;
3671   GValue val = { 0 };
3672
3673   /* only works on similar-sized arrays */
3674   size = gst_value_array_get_size (src1);
3675   if (size != gst_value_array_get_size (src2))
3676     return FALSE;
3677
3678   /* quicker value when we don't need the resulting set */
3679   if (!dest) {
3680     for (n = 0; n < size; n++) {
3681       if (!gst_value_intersect (NULL, gst_value_array_get_value (src1, n),
3682               gst_value_array_get_value (src2, n))) {
3683         return FALSE;
3684       }
3685     }
3686     return TRUE;
3687   }
3688
3689   g_value_init (dest, GST_TYPE_ARRAY);
3690
3691   for (n = 0; n < size; n++) {
3692     if (!gst_value_intersect (&val, gst_value_array_get_value (src1, n),
3693             gst_value_array_get_value (src2, n))) {
3694       g_value_unset (dest);
3695       return FALSE;
3696     }
3697     _gst_value_array_append_and_take_value (dest, &val);
3698   }
3699
3700   return TRUE;
3701 }
3702
3703 static gboolean
3704 gst_value_intersect_fraction_fraction_range (GValue * dest, const GValue * src1,
3705     const GValue * src2)
3706 {
3707   gint res1, res2;
3708   GValue *vals;
3709   GstValueCompareFunc compare;
3710
3711   vals = src2->data[0].v_pointer;
3712
3713   if (vals == NULL)
3714     return FALSE;
3715
3716   if ((compare = gst_value_get_compare_func (src1))) {
3717     res1 = gst_value_compare_with_func (&vals[0], src1, compare);
3718     res2 = gst_value_compare_with_func (&vals[1], src1, compare);
3719
3720     if ((res1 == GST_VALUE_EQUAL || res1 == GST_VALUE_LESS_THAN) &&
3721         (res2 == GST_VALUE_EQUAL || res2 == GST_VALUE_GREATER_THAN)) {
3722       if (dest)
3723         gst_value_init_and_copy (dest, src1);
3724       return TRUE;
3725     }
3726   }
3727
3728   return FALSE;
3729 }
3730
3731 static gboolean
3732 gst_value_intersect_fraction_range_fraction_range (GValue * dest,
3733     const GValue * src1, const GValue * src2)
3734 {
3735   GValue *min;
3736   GValue *max;
3737   gint res;
3738   GValue *vals1, *vals2;
3739   GstValueCompareFunc compare;
3740
3741   vals1 = src1->data[0].v_pointer;
3742   vals2 = src2->data[0].v_pointer;
3743   g_return_val_if_fail (vals1 != NULL && vals2 != NULL, FALSE);
3744
3745   if ((compare = gst_value_get_compare_func (&vals1[0]))) {
3746     /* min = MAX (src1.start, src2.start) */
3747     res = gst_value_compare_with_func (&vals1[0], &vals2[0], compare);
3748     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
3749     if (res == GST_VALUE_LESS_THAN)
3750       min = &vals2[0];          /* Take the max of the 2 */
3751     else
3752       min = &vals1[0];
3753
3754     /* max = MIN (src1.end, src2.end) */
3755     res = gst_value_compare_with_func (&vals1[1], &vals2[1], compare);
3756     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
3757     if (res == GST_VALUE_GREATER_THAN)
3758       max = &vals2[1];          /* Take the min of the 2 */
3759     else
3760       max = &vals1[1];
3761
3762     res = gst_value_compare_with_func (min, max, compare);
3763     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
3764     if (res == GST_VALUE_LESS_THAN) {
3765       if (dest) {
3766         g_value_init (dest, GST_TYPE_FRACTION_RANGE);
3767         vals1 = dest->data[0].v_pointer;
3768         g_value_copy (min, &vals1[0]);
3769         g_value_copy (max, &vals1[1]);
3770       }
3771       return TRUE;
3772     }
3773     if (res == GST_VALUE_EQUAL) {
3774       if (dest)
3775         gst_value_init_and_copy (dest, min);
3776       return TRUE;
3777     }
3778   }
3779
3780   return FALSE;
3781 }
3782
3783 /***************
3784  * subtraction *
3785  ***************/
3786
3787 static gboolean
3788 gst_value_subtract_int_int_range (GValue * dest, const GValue * minuend,
3789     const GValue * subtrahend)
3790 {
3791   gint min = gst_value_get_int_range_min (subtrahend);
3792   gint max = gst_value_get_int_range_max (subtrahend);
3793   gint step = gst_value_get_int_range_step (subtrahend);
3794   gint val = g_value_get_int (minuend);
3795
3796   if (step == 0)
3797     return FALSE;
3798
3799   /* subtracting a range from an int only works if the int is not in the
3800    * range */
3801   if (val < min || val > max || val % step) {
3802     /* and the result is the int */
3803     if (dest)
3804       gst_value_init_and_copy (dest, minuend);
3805     return TRUE;
3806   }
3807   return FALSE;
3808 }
3809
3810 /* creates a new int range based on input values.
3811  */
3812 static gboolean
3813 gst_value_create_new_range (GValue * dest, gint min1, gint max1, gint min2,
3814     gint max2, gint step)
3815 {
3816   GValue v1 = { 0, };
3817   GValue v2 = { 0, };
3818   GValue *pv1, *pv2;            /* yeah, hungarian! */
3819
3820   g_return_val_if_fail (step > 0, FALSE);
3821   g_return_val_if_fail (min1 % step == 0, FALSE);
3822   g_return_val_if_fail (max1 % step == 0, FALSE);
3823   g_return_val_if_fail (min2 % step == 0, FALSE);
3824   g_return_val_if_fail (max2 % step == 0, FALSE);
3825
3826   if (min1 <= max1 && min2 <= max2) {
3827     pv1 = &v1;
3828     pv2 = &v2;
3829   } else if (min1 <= max1) {
3830     pv1 = dest;
3831     pv2 = NULL;
3832   } else if (min2 <= max2) {
3833     pv1 = NULL;
3834     pv2 = dest;
3835   } else {
3836     return FALSE;
3837   }
3838
3839   if (!dest)
3840     return TRUE;
3841
3842   if (min1 < max1) {
3843     g_value_init (pv1, GST_TYPE_INT_RANGE);
3844     gst_value_set_int_range_step (pv1, min1, max1, step);
3845   } else if (min1 == max1) {
3846     g_value_init (pv1, G_TYPE_INT);
3847     g_value_set_int (pv1, min1);
3848   }
3849   if (min2 < max2) {
3850     g_value_init (pv2, GST_TYPE_INT_RANGE);
3851     gst_value_set_int_range_step (pv2, min2, max2, step);
3852   } else if (min2 == max2) {
3853     g_value_init (pv2, G_TYPE_INT);
3854     g_value_set_int (pv2, min2);
3855   }
3856
3857   if (min1 <= max1 && min2 <= max2) {
3858     gst_value_list_concat (dest, pv1, pv2);
3859     g_value_unset (pv1);
3860     g_value_unset (pv2);
3861   }
3862   return TRUE;
3863 }
3864
3865 static gboolean
3866 gst_value_subtract_int_range_int (GValue * dest, const GValue * minuend,
3867     const GValue * subtrahend)
3868 {
3869   gint min = gst_value_get_int_range_min (minuend);
3870   gint max = gst_value_get_int_range_max (minuend);
3871   gint step = gst_value_get_int_range_step (minuend);
3872   gint val = g_value_get_int (subtrahend);
3873
3874   g_return_val_if_fail (min < max, FALSE);
3875
3876   if (step == 0)
3877     return FALSE;
3878
3879   /* value is outside of the range, return range unchanged */
3880   if (val < min || val > max || val % step) {
3881     if (dest)
3882       gst_value_init_and_copy (dest, minuend);
3883     return TRUE;
3884   } else {
3885     /* max must be MAXINT too as val <= max */
3886     if (val >= G_MAXINT - step + 1) {
3887       max -= step;
3888       val -= step;
3889     }
3890     /* min must be MININT too as val >= max */
3891     if (val <= G_MININT + step - 1) {
3892       min += step;
3893       val += step;
3894     }
3895     if (dest)
3896       gst_value_create_new_range (dest, min, val - step, val + step, max, step);
3897   }
3898   return TRUE;
3899 }
3900
3901 static gboolean
3902 gst_value_subtract_int_range_int_range (GValue * dest, const GValue * minuend,
3903     const GValue * subtrahend)
3904 {
3905   gint min1 = gst_value_get_int_range_min (minuend);
3906   gint max1 = gst_value_get_int_range_max (minuend);
3907   gint step1 = gst_value_get_int_range_step (minuend);
3908   gint min2 = gst_value_get_int_range_min (subtrahend);
3909   gint max2 = gst_value_get_int_range_max (subtrahend);
3910   gint step2 = gst_value_get_int_range_step (subtrahend);
3911   gint step;
3912
3913   if (step1 != step2) {
3914     /* ENOIMPL */
3915     g_assert (FALSE);
3916     return FALSE;
3917   }
3918   step = step1;
3919
3920   if (step == 0)
3921     return FALSE;
3922
3923   if (max2 >= max1 && min2 <= min1) {
3924     return FALSE;
3925   } else if (max2 >= max1) {
3926     return gst_value_create_new_range (dest, min1, MIN (min2 - step, max1),
3927         step, 0, step);
3928   } else if (min2 <= min1) {
3929     return gst_value_create_new_range (dest, MAX (max2 + step, min1), max1,
3930         step, 0, step);
3931   } else {
3932     return gst_value_create_new_range (dest, min1, MIN (min2 - step, max1),
3933         MAX (max2 + step, min1), max1, step);
3934   }
3935 }
3936
3937 static gboolean
3938 gst_value_subtract_int64_int64_range (GValue * dest, const GValue * minuend,
3939     const GValue * subtrahend)
3940 {
3941   gint64 min = gst_value_get_int64_range_min (subtrahend);
3942   gint64 max = gst_value_get_int64_range_max (subtrahend);
3943   gint64 step = gst_value_get_int64_range_step (subtrahend);
3944   gint64 val = g_value_get_int64 (minuend);
3945
3946   if (step == 0)
3947     return FALSE;
3948   /* subtracting a range from an int64 only works if the int64 is not in the
3949    * range */
3950   if (val < min || val > max || val % step) {
3951     /* and the result is the int64 */
3952     if (dest)
3953       gst_value_init_and_copy (dest, minuend);
3954     return TRUE;
3955   }
3956   return FALSE;
3957 }
3958
3959 /* creates a new int64 range based on input values.
3960  */
3961 static gboolean
3962 gst_value_create_new_int64_range (GValue * dest, gint64 min1, gint64 max1,
3963     gint64 min2, gint64 max2, gint64 step)
3964 {
3965   GValue v1 = { 0, };
3966   GValue v2 = { 0, };
3967   GValue *pv1, *pv2;            /* yeah, hungarian! */
3968
3969   g_return_val_if_fail (step > 0, FALSE);
3970   g_return_val_if_fail (min1 % step == 0, FALSE);
3971   g_return_val_if_fail (max1 % step == 0, FALSE);
3972   g_return_val_if_fail (min2 % step == 0, FALSE);
3973   g_return_val_if_fail (max2 % step == 0, FALSE);
3974
3975   if (min1 <= max1 && min2 <= max2) {
3976     pv1 = &v1;
3977     pv2 = &v2;
3978   } else if (min1 <= max1) {
3979     pv1 = dest;
3980     pv2 = NULL;
3981   } else if (min2 <= max2) {
3982     pv1 = NULL;
3983     pv2 = dest;
3984   } else {
3985     return FALSE;
3986   }
3987
3988   if (!dest)
3989     return TRUE;
3990
3991   if (min1 < max1) {
3992     g_value_init (pv1, GST_TYPE_INT64_RANGE);
3993     gst_value_set_int64_range_step (pv1, min1, max1, step);
3994   } else if (min1 == max1) {
3995     g_value_init (pv1, G_TYPE_INT64);
3996     g_value_set_int64 (pv1, min1);
3997   }
3998   if (min2 < max2) {
3999     g_value_init (pv2, GST_TYPE_INT64_RANGE);
4000     gst_value_set_int64_range_step (pv2, min2, max2, step);
4001   } else if (min2 == max2) {
4002     g_value_init (pv2, G_TYPE_INT64);
4003     g_value_set_int64 (pv2, min2);
4004   }
4005
4006   if (min1 <= max1 && min2 <= max2) {
4007     gst_value_list_concat (dest, pv1, pv2);
4008     g_value_unset (pv1);
4009     g_value_unset (pv2);
4010   }
4011   return TRUE;
4012 }
4013
4014 static gboolean
4015 gst_value_subtract_int64_range_int64 (GValue * dest, const GValue * minuend,
4016     const GValue * subtrahend)
4017 {
4018   gint64 min = gst_value_get_int64_range_min (minuend);
4019   gint64 max = gst_value_get_int64_range_max (minuend);
4020   gint64 step = gst_value_get_int64_range_step (minuend);
4021   gint64 val = g_value_get_int64 (subtrahend);
4022
4023   g_return_val_if_fail (min < max, FALSE);
4024
4025   if (step == 0)
4026     return FALSE;
4027
4028   /* value is outside of the range, return range unchanged */
4029   if (val < min || val > max || val % step) {
4030     if (dest)
4031       gst_value_init_and_copy (dest, minuend);
4032     return TRUE;
4033   } else {
4034     /* max must be MAXINT64 too as val <= max */
4035     if (val >= G_MAXINT64 - step + 1) {
4036       max -= step;
4037       val -= step;
4038     }
4039     /* min must be MININT64 too as val >= max */
4040     if (val <= G_MININT64 + step - 1) {
4041       min += step;
4042       val += step;
4043     }
4044     if (dest)
4045       gst_value_create_new_int64_range (dest, min, val - step, val + step, max,
4046           step);
4047   }
4048   return TRUE;
4049 }
4050
4051 static gboolean
4052 gst_value_subtract_int64_range_int64_range (GValue * dest,
4053     const GValue * minuend, const GValue * subtrahend)
4054 {
4055   gint64 min1 = gst_value_get_int64_range_min (minuend);
4056   gint64 max1 = gst_value_get_int64_range_max (minuend);
4057   gint64 step1 = gst_value_get_int64_range_step (minuend);
4058   gint64 min2 = gst_value_get_int64_range_min (subtrahend);
4059   gint64 max2 = gst_value_get_int64_range_max (subtrahend);
4060   gint64 step2 = gst_value_get_int64_range_step (subtrahend);
4061   gint64 step;
4062
4063   if (step1 != step2) {
4064     /* ENOIMPL */
4065     g_assert (FALSE);
4066     return FALSE;
4067   }
4068
4069   if (step1 == 0)
4070     return FALSE;
4071
4072   step = step1;
4073
4074   if (max2 >= max1 && min2 <= min1) {
4075     return FALSE;
4076   } else if (max2 >= max1) {
4077     return gst_value_create_new_int64_range (dest, min1, MIN (min2 - step,
4078             max1), step, 0, step);
4079   } else if (min2 <= min1) {
4080     return gst_value_create_new_int64_range (dest, MAX (max2 + step, min1),
4081         max1, step, 0, step);
4082   } else {
4083     return gst_value_create_new_int64_range (dest, min1, MIN (min2 - step,
4084             max1), MAX (max2 + step, min1), max1, step);
4085   }
4086 }
4087
4088 static gboolean
4089 gst_value_subtract_double_double_range (GValue * dest, const GValue * minuend,
4090     const GValue * subtrahend)
4091 {
4092   gdouble min = gst_value_get_double_range_min (subtrahend);
4093   gdouble max = gst_value_get_double_range_max (subtrahend);
4094   gdouble val = g_value_get_double (minuend);
4095
4096   if (val < min || val > max) {
4097     if (dest)
4098       gst_value_init_and_copy (dest, minuend);
4099     return TRUE;
4100   }
4101   return FALSE;
4102 }
4103
4104 static gboolean
4105 gst_value_subtract_double_range_double (GValue * dest, const GValue * minuend,
4106     const GValue * subtrahend)
4107 {
4108   /* since we don't have open ranges, we cannot create a hole in
4109    * a double range. We return the original range */
4110   if (dest)
4111     gst_value_init_and_copy (dest, minuend);
4112   return TRUE;
4113 }
4114
4115 static gboolean
4116 gst_value_subtract_double_range_double_range (GValue * dest,
4117     const GValue * minuend, const GValue * subtrahend)
4118 {
4119   /* since we don't have open ranges, we have to approximate */
4120   /* done like with ints */
4121   gdouble min1 = gst_value_get_double_range_min (minuend);
4122   gdouble max2 = gst_value_get_double_range_max (minuend);
4123   gdouble max1 = MIN (gst_value_get_double_range_min (subtrahend), max2);
4124   gdouble min2 = MAX (gst_value_get_double_range_max (subtrahend), min1);
4125   GValue v1 = { 0, };
4126   GValue v2 = { 0, };
4127   GValue *pv1, *pv2;            /* yeah, hungarian! */
4128
4129   if (min1 < max1 && min2 < max2) {
4130     pv1 = &v1;
4131     pv2 = &v2;
4132   } else if (min1 < max1) {
4133     pv1 = dest;
4134     pv2 = NULL;
4135   } else if (min2 < max2) {
4136     pv1 = NULL;
4137     pv2 = dest;
4138   } else {
4139     return FALSE;
4140   }
4141
4142   if (!dest)
4143     return TRUE;
4144
4145   if (min1 < max1) {
4146     g_value_init (pv1, GST_TYPE_DOUBLE_RANGE);
4147     gst_value_set_double_range (pv1, min1, max1);
4148   }
4149   if (min2 < max2) {
4150     g_value_init (pv2, GST_TYPE_DOUBLE_RANGE);
4151     gst_value_set_double_range (pv2, min2, max2);
4152   }
4153
4154   if (min1 < max1 && min2 < max2) {
4155     gst_value_list_concat (dest, pv1, pv2);
4156     g_value_unset (pv1);
4157     g_value_unset (pv2);
4158   }
4159   return TRUE;
4160 }
4161
4162 static gboolean
4163 gst_value_subtract_from_list (GValue * dest, const GValue * minuend,
4164     const GValue * subtrahend)
4165 {
4166   guint i, size;
4167   GValue subtraction = { 0, };
4168   gboolean ret = FALSE;
4169   GType ltype;
4170
4171   ltype = gst_value_list_get_type ();
4172
4173   size = VALUE_LIST_SIZE (minuend);
4174   for (i = 0; i < size; i++) {
4175     const GValue *cur = VALUE_LIST_GET_VALUE (minuend, i);
4176
4177     /* quicker version when we can discard the result */
4178     if (!dest) {
4179       if (gst_value_subtract (NULL, cur, subtrahend)) {
4180         ret = TRUE;
4181         break;
4182       }
4183       continue;
4184     }
4185
4186     if (gst_value_subtract (&subtraction, cur, subtrahend)) {
4187       if (!ret) {
4188         gst_value_move (dest, &subtraction);
4189         ret = TRUE;
4190       } else if (G_VALUE_HOLDS (dest, ltype)
4191           && !G_VALUE_HOLDS (&subtraction, ltype)) {
4192         _gst_value_list_append_and_take_value (dest, &subtraction);
4193       } else {
4194         GValue temp;
4195
4196         gst_value_move (&temp, dest);
4197         gst_value_list_concat (dest, &temp, &subtraction);
4198         g_value_unset (&temp);
4199         g_value_unset (&subtraction);
4200       }
4201     }
4202   }
4203   return ret;
4204 }
4205
4206 static gboolean
4207 gst_value_subtract_list (GValue * dest, const GValue * minuend,
4208     const GValue * subtrahend)
4209 {
4210   guint i, size;
4211   GValue data[2] = { {0,}, {0,} };
4212   GValue *subtraction = &data[0], *result = &data[1];
4213
4214   gst_value_init_and_copy (result, minuend);
4215   size = VALUE_LIST_SIZE (subtrahend);
4216   for (i = 0; i < size; i++) {
4217     const GValue *cur = VALUE_LIST_GET_VALUE (subtrahend, i);
4218
4219     if (gst_value_subtract (subtraction, result, cur)) {
4220       GValue *temp = result;
4221
4222       result = subtraction;
4223       subtraction = temp;
4224       g_value_unset (subtraction);
4225     } else {
4226       g_value_unset (result);
4227       return FALSE;
4228     }
4229   }
4230   if (dest) {
4231     gst_value_move (dest, result);
4232   } else {
4233     g_value_unset (result);
4234   }
4235   return TRUE;
4236 }
4237
4238 static gboolean
4239 gst_value_subtract_fraction_fraction_range (GValue * dest,
4240     const GValue * minuend, const GValue * subtrahend)
4241 {
4242   const GValue *min = gst_value_get_fraction_range_min (subtrahend);
4243   const GValue *max = gst_value_get_fraction_range_max (subtrahend);
4244   GstValueCompareFunc compare;
4245
4246   if ((compare = gst_value_get_compare_func (minuend))) {
4247     /* subtracting a range from an fraction only works if the fraction
4248      * is not in the range */
4249     if (gst_value_compare_with_func (minuend, min, compare) ==
4250         GST_VALUE_LESS_THAN ||
4251         gst_value_compare_with_func (minuend, max, compare) ==
4252         GST_VALUE_GREATER_THAN) {
4253       /* and the result is the value */
4254       if (dest)
4255         gst_value_init_and_copy (dest, minuend);
4256       return TRUE;
4257     }
4258   }
4259   return FALSE;
4260 }
4261
4262 static gboolean
4263 gst_value_subtract_fraction_range_fraction (GValue * dest,
4264     const GValue * minuend, const GValue * subtrahend)
4265 {
4266   /* since we don't have open ranges, we cannot create a hole in
4267    * a range. We return the original range */
4268   if (dest)
4269     gst_value_init_and_copy (dest, minuend);
4270   return TRUE;
4271 }
4272
4273 static gboolean
4274 gst_value_subtract_fraction_range_fraction_range (GValue * dest,
4275     const GValue * minuend, const GValue * subtrahend)
4276 {
4277   /* since we don't have open ranges, we have to approximate */
4278   /* done like with ints and doubles. Creates a list of 2 fraction ranges */
4279   const GValue *min1 = gst_value_get_fraction_range_min (minuend);
4280   const GValue *max2 = gst_value_get_fraction_range_max (minuend);
4281   const GValue *max1 = gst_value_get_fraction_range_min (subtrahend);
4282   const GValue *min2 = gst_value_get_fraction_range_max (subtrahend);
4283   gint cmp1, cmp2;
4284   GValue v1 = { 0, };
4285   GValue v2 = { 0, };
4286   GValue *pv1, *pv2;            /* yeah, hungarian! */
4287   GstValueCompareFunc compare;
4288
4289   g_return_val_if_fail (min1 != NULL && max1 != NULL, FALSE);
4290   g_return_val_if_fail (min2 != NULL && max2 != NULL, FALSE);
4291
4292   compare = gst_value_get_compare_func (min1);
4293   g_return_val_if_fail (compare, FALSE);
4294
4295   cmp1 = gst_value_compare_with_func (max2, max1, compare);
4296   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
4297   if (cmp1 == GST_VALUE_LESS_THAN)
4298     max1 = max2;
4299   cmp1 = gst_value_compare_with_func (min1, min2, compare);
4300   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
4301   if (cmp1 == GST_VALUE_GREATER_THAN)
4302     min2 = min1;
4303
4304   cmp1 = gst_value_compare_with_func (min1, max1, compare);
4305   cmp2 = gst_value_compare_with_func (min2, max2, compare);
4306
4307   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
4308     pv1 = &v1;
4309     pv2 = &v2;
4310   } else if (cmp1 == GST_VALUE_LESS_THAN) {
4311     pv1 = dest;
4312     pv2 = NULL;
4313   } else if (cmp2 == GST_VALUE_LESS_THAN) {
4314     pv1 = NULL;
4315     pv2 = dest;
4316   } else {
4317     return FALSE;
4318   }
4319
4320   if (!dest)
4321     return TRUE;
4322
4323   if (cmp1 == GST_VALUE_LESS_THAN) {
4324     g_value_init (pv1, GST_TYPE_FRACTION_RANGE);
4325     gst_value_set_fraction_range (pv1, min1, max1);
4326   }
4327   if (cmp2 == GST_VALUE_LESS_THAN) {
4328     g_value_init (pv2, GST_TYPE_FRACTION_RANGE);
4329     gst_value_set_fraction_range (pv2, min2, max2);
4330   }
4331
4332   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
4333     gst_value_list_concat (dest, pv1, pv2);
4334     g_value_unset (pv1);
4335     g_value_unset (pv2);
4336   }
4337   return TRUE;
4338 }
4339
4340
4341 /**************
4342  * comparison *
4343  **************/
4344
4345 /*
4346  * gst_value_get_compare_func:
4347  * @value1: a value to get the compare function for
4348  *
4349  * Determines the compare function to be used with values of the same type as
4350  * @value1. The function can be given to gst_value_compare_with_func().
4351  *
4352  * Returns: A #GstValueCompareFunc value
4353  */
4354 static GstValueCompareFunc
4355 gst_value_get_compare_func (const GValue * value1)
4356 {
4357   GstValueTable *table, *best = NULL;
4358   guint i;
4359   GType type1;
4360
4361   type1 = G_VALUE_TYPE (value1);
4362
4363   /* this is a fast check */
4364   best = gst_value_hash_lookup_type (type1);
4365
4366   /* slower checks */
4367   if (G_UNLIKELY (!best || !best->compare)) {
4368     guint len = gst_value_table->len;
4369
4370     best = NULL;
4371     for (i = 0; i < len; i++) {
4372       table = &g_array_index (gst_value_table, GstValueTable, i);
4373       if (table->compare && g_type_is_a (type1, table->type)) {
4374         if (!best || g_type_is_a (table->type, best->type))
4375           best = table;
4376       }
4377     }
4378   }
4379   if (G_LIKELY (best))
4380     return best->compare;
4381
4382   return NULL;
4383 }
4384
4385 /**
4386  * gst_value_can_compare:
4387  * @value1: a value to compare
4388  * @value2: another value to compare
4389  *
4390  * Determines if @value1 and @value2 can be compared.
4391  *
4392  * Returns: TRUE if the values can be compared
4393  */
4394 gboolean
4395 gst_value_can_compare (const GValue * value1, const GValue * value2)
4396 {
4397   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4398   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4399
4400   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
4401     return FALSE;
4402
4403   return gst_value_get_compare_func (value1) != NULL;
4404 }
4405
4406 static gboolean
4407 gst_value_list_equals_range (const GValue * list, const GValue * value)
4408 {
4409   const GValue *first;
4410   guint list_size, n;
4411
4412   g_return_val_if_fail (G_IS_VALUE (list), FALSE);
4413   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
4414   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (list), FALSE);
4415
4416   /* TODO: compare against an empty list ? No type though... */
4417   list_size = VALUE_LIST_SIZE (list);
4418   if (list_size == 0)
4419     return FALSE;
4420
4421   /* compare the basic types - they have to match */
4422   first = VALUE_LIST_GET_VALUE (list, 0);
4423 #define CHECK_TYPES(type,prefix) \
4424   (prefix##_VALUE_HOLDS_##type(first) && GST_VALUE_HOLDS_##type##_RANGE (value))
4425   if (CHECK_TYPES (INT, G)) {
4426     const gint rmin = gst_value_get_int_range_min (value);
4427     const gint rmax = gst_value_get_int_range_max (value);
4428     const gint rstep = gst_value_get_int_range_step (value);
4429     if (rstep == 0)
4430       return FALSE;
4431     /* note: this will overflow for min 0 and max INT_MAX, but this
4432        would only be equal to a list of INT_MAX elements, which seems
4433        very unlikely */
4434     if (list_size != rmax / rstep - rmin / rstep + 1)
4435       return FALSE;
4436     for (n = 0; n < list_size; ++n) {
4437       gint v = g_value_get_int (VALUE_LIST_GET_VALUE (list, n));
4438       if (v < rmin || v > rmax || v % rstep) {
4439         return FALSE;
4440       }
4441     }
4442     return TRUE;
4443   } else if (CHECK_TYPES (INT64, G)) {
4444     const gint64 rmin = gst_value_get_int64_range_min (value);
4445     const gint64 rmax = gst_value_get_int64_range_max (value);
4446     const gint64 rstep = gst_value_get_int64_range_step (value);
4447     GST_DEBUG ("List/range of int64s");
4448     if (list_size != rmax / rstep - rmin / rstep + 1)
4449       return FALSE;
4450     for (n = 0; n < list_size; ++n) {
4451       gint64 v = g_value_get_int64 (VALUE_LIST_GET_VALUE (list, n));
4452       if (v < rmin || v > rmax || v % rstep)
4453         return FALSE;
4454     }
4455     return TRUE;
4456   }
4457 #undef CHECK_TYPES
4458
4459   /* other combinations don't make sense for equality */
4460   return FALSE;
4461 }
4462
4463 /**
4464  * gst_value_compare:
4465  * @value1: a value to compare
4466  * @value2: another value to compare
4467  *
4468  * Compares @value1 and @value2.  If @value1 and @value2 cannot be
4469  * compared, the function returns GST_VALUE_UNORDERED.  Otherwise,
4470  * if @value1 is greater than @value2, GST_VALUE_GREATER_THAN is returned.
4471  * If @value1 is less than @value2, GST_VALUE_LESS_THAN is returned.
4472  * If the values are equal, GST_VALUE_EQUAL is returned.
4473  *
4474  * Returns: comparison result
4475  */
4476 gint
4477 gst_value_compare (const GValue * value1, const GValue * value2)
4478 {
4479   GstValueCompareFunc compare;
4480   GType ltype;
4481
4482   g_return_val_if_fail (G_IS_VALUE (value1), GST_VALUE_LESS_THAN);
4483   g_return_val_if_fail (G_IS_VALUE (value2), GST_VALUE_GREATER_THAN);
4484
4485   /* Special cases: lists and scalar values ("{ 1 }" and "1" are equal),
4486      as well as lists and ranges ("{ 1, 2 }" and "[ 1, 2 ]" are equal) */
4487   ltype = gst_value_list_get_type ();
4488   if (G_VALUE_HOLDS (value1, ltype) && !G_VALUE_HOLDS (value2, ltype)) {
4489     gint i, n, ret;
4490
4491     if (gst_value_list_equals_range (value1, value2)) {
4492       return GST_VALUE_EQUAL;
4493     }
4494
4495     n = gst_value_list_get_size (value1);
4496     if (n == 0)
4497       return GST_VALUE_UNORDERED;
4498
4499     for (i = 0; i < n; i++) {
4500       const GValue *elt;
4501
4502       elt = gst_value_list_get_value (value1, i);
4503       ret = gst_value_compare (elt, value2);
4504       if (ret != GST_VALUE_EQUAL && n == 1)
4505         return ret;
4506       else if (ret != GST_VALUE_EQUAL)
4507         return GST_VALUE_UNORDERED;
4508     }
4509
4510     return GST_VALUE_EQUAL;
4511   } else if (G_VALUE_HOLDS (value2, ltype) && !G_VALUE_HOLDS (value1, ltype)) {
4512     gint i, n, ret;
4513
4514     if (gst_value_list_equals_range (value2, value1)) {
4515       return GST_VALUE_EQUAL;
4516     }
4517
4518     n = gst_value_list_get_size (value2);
4519     if (n == 0)
4520       return GST_VALUE_UNORDERED;
4521
4522     for (i = 0; i < n; i++) {
4523       const GValue *elt;
4524
4525       elt = gst_value_list_get_value (value2, i);
4526       ret = gst_value_compare (elt, value1);
4527       if (ret != GST_VALUE_EQUAL && n == 1)
4528         return ret;
4529       else if (ret != GST_VALUE_EQUAL)
4530         return GST_VALUE_UNORDERED;
4531     }
4532
4533     return GST_VALUE_EQUAL;
4534   }
4535
4536   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
4537     return GST_VALUE_UNORDERED;
4538
4539   compare = gst_value_get_compare_func (value1);
4540   if (compare) {
4541     return compare (value1, value2);
4542   }
4543
4544   g_critical ("unable to compare values of type %s\n",
4545       g_type_name (G_VALUE_TYPE (value1)));
4546   return GST_VALUE_UNORDERED;
4547 }
4548
4549 /*
4550  * gst_value_compare_with_func:
4551  * @value1: a value to compare
4552  * @value2: another value to compare
4553  * @compare: compare function
4554  *
4555  * Compares @value1 and @value2 using the @compare function. Works like
4556  * gst_value_compare() but allows to save time determining the compare function
4557  * a multiple times. 
4558  *
4559  * Returns: comparison result
4560  */
4561 static gint
4562 gst_value_compare_with_func (const GValue * value1, const GValue * value2,
4563     GstValueCompareFunc compare)
4564 {
4565   g_assert (compare);
4566
4567   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
4568     return GST_VALUE_UNORDERED;
4569
4570   return compare (value1, value2);
4571 }
4572
4573 /* union */
4574
4575 /**
4576  * gst_value_can_union:
4577  * @value1: a value to union
4578  * @value2: another value to union
4579  *
4580  * Determines if @value1 and @value2 can be non-trivially unioned.
4581  * Any two values can be trivially unioned by adding both of them
4582  * to a GstValueList.  However, certain types have the possibility
4583  * to be unioned in a simpler way.  For example, an integer range
4584  * and an integer can be unioned if the integer is a subset of the
4585  * integer range.  If there is the possibility that two values can
4586  * be unioned, this function returns TRUE.
4587  *
4588  * Returns: TRUE if there is a function allowing the two values to
4589  * be unioned.
4590  */
4591 gboolean
4592 gst_value_can_union (const GValue * value1, const GValue * value2)
4593 {
4594   GstValueUnionInfo *union_info;
4595   guint i, len;
4596
4597   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4598   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4599
4600   len = gst_value_union_funcs->len;
4601
4602   for (i = 0; i < len; i++) {
4603     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
4604     if (union_info->type1 == G_VALUE_TYPE (value1) &&
4605         union_info->type2 == G_VALUE_TYPE (value2))
4606       return TRUE;
4607     if (union_info->type1 == G_VALUE_TYPE (value2) &&
4608         union_info->type2 == G_VALUE_TYPE (value1))
4609       return TRUE;
4610   }
4611
4612   return FALSE;
4613 }
4614
4615 /**
4616  * gst_value_union:
4617  * @dest: (out caller-allocates): the destination value
4618  * @value1: a value to union
4619  * @value2: another value to union
4620  *
4621  * Creates a GValue corresponding to the union of @value1 and @value2.
4622  *
4623  * Returns: TRUE if the union succeeded.
4624  */
4625 gboolean
4626 gst_value_union (GValue * dest, const GValue * value1, const GValue * value2)
4627 {
4628   const GstValueUnionInfo *union_info;
4629   guint i, len;
4630   GType type1, type2;
4631
4632   g_return_val_if_fail (dest != NULL, FALSE);
4633   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4634   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4635   g_return_val_if_fail (gst_value_list_or_array_are_compatible (value1, value2),
4636       FALSE);
4637
4638   len = gst_value_union_funcs->len;
4639   type1 = G_VALUE_TYPE (value1);
4640   type2 = G_VALUE_TYPE (value2);
4641
4642   for (i = 0; i < len; i++) {
4643     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
4644     if (union_info->type1 == type1 && union_info->type2 == type2) {
4645       return union_info->func (dest, value1, value2);
4646     }
4647     if (union_info->type1 == type2 && union_info->type2 == type1) {
4648       return union_info->func (dest, value2, value1);
4649     }
4650   }
4651
4652   gst_value_list_concat (dest, value1, value2);
4653   return TRUE;
4654 }
4655
4656 /* gst_value_register_union_func: (skip)
4657  * @type1: a type to union
4658  * @type2: another type to union
4659  * @func: a function that implements creating a union between the two types
4660  *
4661  * Registers a union function that can create a union between #GValue items
4662  * of the type @type1 and @type2.
4663  *
4664  * Union functions should be registered at startup before any pipelines are
4665  * started, as gst_value_register_union_func() is not thread-safe and cannot
4666  * be used at the same time as gst_value_union() or gst_value_can_union().
4667  */
4668 static void
4669 gst_value_register_union_func (GType type1, GType type2, GstValueUnionFunc func)
4670 {
4671   GstValueUnionInfo union_info;
4672
4673   union_info.type1 = type1;
4674   union_info.type2 = type2;
4675   union_info.func = func;
4676
4677   g_array_append_val (gst_value_union_funcs, union_info);
4678 }
4679
4680 /* intersection */
4681
4682 /**
4683  * gst_value_can_intersect:
4684  * @value1: a value to intersect
4685  * @value2: another value to intersect
4686  *
4687  * Determines if intersecting two values will produce a valid result.
4688  * Two values will produce a valid intersection if they have the same
4689  * type.
4690  *
4691  * Returns: TRUE if the values can intersect
4692  */
4693 gboolean
4694 gst_value_can_intersect (const GValue * value1, const GValue * value2)
4695 {
4696   GstValueIntersectInfo *intersect_info;
4697   guint i, len;
4698   GType ltype, type1, type2;
4699
4700   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4701   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4702
4703   ltype = gst_value_list_get_type ();
4704
4705   /* special cases */
4706   if (G_VALUE_HOLDS (value1, ltype) || G_VALUE_HOLDS (value2, ltype))
4707     return TRUE;
4708
4709   type1 = G_VALUE_TYPE (value1);
4710   type2 = G_VALUE_TYPE (value2);
4711
4712   /* practically all GstValue types have a compare function (_can_compare=TRUE)
4713    * GstStructure and GstCaps have npot, but are intersectable */
4714   if (type1 == type2)
4715     return TRUE;
4716
4717   /* check registered intersect functions */
4718   len = gst_value_intersect_funcs->len;
4719   for (i = 0; i < len; i++) {
4720     intersect_info = &g_array_index (gst_value_intersect_funcs,
4721         GstValueIntersectInfo, i);
4722     if ((intersect_info->type1 == type1 && intersect_info->type2 == type2) ||
4723         (intersect_info->type1 == type2 && intersect_info->type2 == type1))
4724       return TRUE;
4725   }
4726
4727   return gst_value_can_compare (value1, value2);
4728 }
4729
4730 /**
4731  * gst_value_intersect:
4732  * @dest: (out caller-allocates) (transfer full): a uninitialized #GValue that will hold the calculated
4733  * intersection value. May be NULL if the resulting set if not needed.
4734  * @value1: a value to intersect
4735  * @value2: another value to intersect
4736  *
4737  * Calculates the intersection of two values.  If the values have
4738  * a non-empty intersection, the value representing the intersection
4739  * is placed in @dest, unless NULL.  If the intersection is non-empty,
4740  * @dest is not modified.
4741  *
4742  * Returns: TRUE if the intersection is non-empty
4743  */
4744 gboolean
4745 gst_value_intersect (GValue * dest, const GValue * value1,
4746     const GValue * value2)
4747 {
4748   GstValueIntersectInfo *intersect_info;
4749   guint i, len;
4750   GType ltype, type1, type2;
4751
4752   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4753   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4754
4755   ltype = gst_value_list_get_type ();
4756
4757   /* special cases first */
4758   if (G_VALUE_HOLDS (value1, ltype))
4759     return gst_value_intersect_list (dest, value1, value2);
4760   if (G_VALUE_HOLDS (value2, ltype))
4761     return gst_value_intersect_list (dest, value2, value1);
4762
4763   if (gst_value_compare (value1, value2) == GST_VALUE_EQUAL) {
4764     if (dest)
4765       gst_value_init_and_copy (dest, value1);
4766     return TRUE;
4767   }
4768
4769   type1 = G_VALUE_TYPE (value1);
4770   type2 = G_VALUE_TYPE (value2);
4771
4772   len = gst_value_intersect_funcs->len;
4773   for (i = 0; i < len; i++) {
4774     intersect_info = &g_array_index (gst_value_intersect_funcs,
4775         GstValueIntersectInfo, i);
4776     if (intersect_info->type1 == type1 && intersect_info->type2 == type2) {
4777       return intersect_info->func (dest, value1, value2);
4778     }
4779     if (intersect_info->type1 == type2 && intersect_info->type2 == type1) {
4780       return intersect_info->func (dest, value2, value1);
4781     }
4782   }
4783   return FALSE;
4784 }
4785
4786
4787
4788 /* gst_value_register_intersect_func: (skip)
4789  * @type1: the first type to intersect
4790  * @type2: the second type to intersect
4791  * @func: the intersection function
4792  *
4793  * Registers a function that is called to calculate the intersection
4794  * of the values having the types @type1 and @type2.
4795  *
4796  * Intersect functions should be registered at startup before any pipelines are
4797  * started, as gst_value_register_intersect_func() is not thread-safe and
4798  * cannot be used at the same time as gst_value_intersect() or
4799  * gst_value_can_intersect().
4800  */
4801 static void
4802 gst_value_register_intersect_func (GType type1, GType type2,
4803     GstValueIntersectFunc func)
4804 {
4805   GstValueIntersectInfo intersect_info;
4806
4807   intersect_info.type1 = type1;
4808   intersect_info.type2 = type2;
4809   intersect_info.func = func;
4810
4811   g_array_append_val (gst_value_intersect_funcs, intersect_info);
4812 }
4813
4814
4815 /* subtraction */
4816
4817 /**
4818  * gst_value_subtract:
4819  * @dest: (out caller-allocates): the destination value for the result if the
4820  *     subtraction is not empty. May be NULL, in which case the resulting set
4821  *     will not be computed, which can give a fair speedup.
4822  * @minuend: the value to subtract from
4823  * @subtrahend: the value to subtract
4824  *
4825  * Subtracts @subtrahend from @minuend and stores the result in @dest.
4826  * Note that this means subtraction as in sets, not as in mathematics.
4827  *
4828  * Returns: %TRUE if the subtraction is not empty
4829  */
4830 gboolean
4831 gst_value_subtract (GValue * dest, const GValue * minuend,
4832     const GValue * subtrahend)
4833 {
4834   GstValueSubtractInfo *info;
4835   guint i, len;
4836   GType ltype, mtype, stype;
4837
4838   g_return_val_if_fail (G_IS_VALUE (minuend), FALSE);
4839   g_return_val_if_fail (G_IS_VALUE (subtrahend), FALSE);
4840
4841   ltype = gst_value_list_get_type ();
4842
4843   /* special cases first */
4844   if (G_VALUE_HOLDS (minuend, ltype))
4845     return gst_value_subtract_from_list (dest, minuend, subtrahend);
4846   if (G_VALUE_HOLDS (subtrahend, ltype))
4847     return gst_value_subtract_list (dest, minuend, subtrahend);
4848
4849   mtype = G_VALUE_TYPE (minuend);
4850   stype = G_VALUE_TYPE (subtrahend);
4851
4852   len = gst_value_subtract_funcs->len;
4853   for (i = 0; i < len; i++) {
4854     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
4855     if (info->minuend == mtype && info->subtrahend == stype) {
4856       return info->func (dest, minuend, subtrahend);
4857     }
4858   }
4859
4860   if (gst_value_compare (minuend, subtrahend) != GST_VALUE_EQUAL) {
4861     if (dest)
4862       gst_value_init_and_copy (dest, minuend);
4863     return TRUE;
4864   }
4865
4866   return FALSE;
4867 }
4868
4869 #if 0
4870 gboolean
4871 gst_value_subtract (GValue * dest, const GValue * minuend,
4872     const GValue * subtrahend)
4873 {
4874   gboolean ret = gst_value_subtract2 (dest, minuend, subtrahend);
4875
4876   g_printerr ("\"%s\"  -  \"%s\"  =  \"%s\"\n", gst_value_serialize (minuend),
4877       gst_value_serialize (subtrahend),
4878       ret ? gst_value_serialize (dest) : "---");
4879   return ret;
4880 }
4881 #endif
4882
4883 /**
4884  * gst_value_can_subtract:
4885  * @minuend: the value to subtract from
4886  * @subtrahend: the value to subtract
4887  *
4888  * Checks if it's possible to subtract @subtrahend from @minuend.
4889  *
4890  * Returns: TRUE if a subtraction is possible
4891  */
4892 gboolean
4893 gst_value_can_subtract (const GValue * minuend, const GValue * subtrahend)
4894 {
4895   GstValueSubtractInfo *info;
4896   guint i, len;
4897   GType ltype, mtype, stype;
4898
4899   g_return_val_if_fail (G_IS_VALUE (minuend), FALSE);
4900   g_return_val_if_fail (G_IS_VALUE (subtrahend), FALSE);
4901
4902   ltype = gst_value_list_get_type ();
4903
4904   /* special cases */
4905   if (G_VALUE_HOLDS (minuend, ltype) || G_VALUE_HOLDS (subtrahend, ltype))
4906     return TRUE;
4907
4908   mtype = G_VALUE_TYPE (minuend);
4909   stype = G_VALUE_TYPE (subtrahend);
4910
4911   len = gst_value_subtract_funcs->len;
4912   for (i = 0; i < len; i++) {
4913     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
4914     if (info->minuend == mtype && info->subtrahend == stype)
4915       return TRUE;
4916   }
4917
4918   return gst_value_can_compare (minuend, subtrahend);
4919 }
4920
4921 /* gst_value_register_subtract_func: (skip)
4922  * @minuend_type: type of the minuend
4923  * @subtrahend_type: type of the subtrahend
4924  * @func: function to use
4925  *
4926  * Registers @func as a function capable of subtracting the values of
4927  * @subtrahend_type from values of @minuend_type.
4928  *
4929  * Subtract functions should be registered at startup before any pipelines are
4930  * started, as gst_value_register_subtract_func() is not thread-safe and
4931  * cannot be used at the same time as gst_value_subtract().
4932  */
4933 static void
4934 gst_value_register_subtract_func (GType minuend_type, GType subtrahend_type,
4935     GstValueSubtractFunc func)
4936 {
4937   GstValueSubtractInfo info;
4938
4939   g_return_if_fail (!gst_type_is_fixed (minuend_type)
4940       || !gst_type_is_fixed (subtrahend_type));
4941
4942   info.minuend = minuend_type;
4943   info.subtrahend = subtrahend_type;
4944   info.func = func;
4945
4946   g_array_append_val (gst_value_subtract_funcs, info);
4947 }
4948
4949 /**
4950  * gst_value_register:
4951  * @table: structure containing functions to register
4952  *
4953  * Registers functions to perform calculations on #GValue items of a given
4954  * type. Each type can only be added once.
4955  */
4956 void
4957 gst_value_register (const GstValueTable * table)
4958 {
4959   GstValueTable *found;
4960
4961   g_return_if_fail (table != NULL);
4962
4963   g_array_append_val (gst_value_table, *table);
4964
4965   found = gst_value_hash_lookup_type (table->type);
4966   if (found)
4967     g_warning ("adding type %s multiple times", g_type_name (table->type));
4968
4969   /* FIXME: we're not really doing the const justice, we assume the table is
4970    * static */
4971   gst_value_hash_add_type (table->type, table);
4972 }
4973
4974 /**
4975  * gst_value_init_and_copy:
4976  * @dest: (out caller-allocates): the target value
4977  * @src: the source value
4978  *
4979  * Initialises the target value to be of the same type as source and then copies
4980  * the contents from source to target.
4981  */
4982 void
4983 gst_value_init_and_copy (GValue * dest, const GValue * src)
4984 {
4985   g_return_if_fail (G_IS_VALUE (src));
4986   g_return_if_fail (dest != NULL);
4987
4988   g_value_init (dest, G_VALUE_TYPE (src));
4989   g_value_copy (src, dest);
4990 }
4991
4992 /* move src into dest and clear src */
4993 static void
4994 gst_value_move (GValue * dest, GValue * src)
4995 {
4996   g_assert (G_IS_VALUE (src));
4997   g_assert (dest != NULL);
4998
4999   *dest = *src;
5000   memset (src, 0, sizeof (GValue));
5001 }
5002
5003 /**
5004  * gst_value_serialize:
5005  * @value: a #GValue to serialize
5006  *
5007  * tries to transform the given @value into a string representation that allows
5008  * getting back this string later on using gst_value_deserialize().
5009  *
5010  * Free-function: g_free
5011  *
5012  * Returns: (transfer full): the serialization for @value or NULL if none exists
5013  */
5014 gchar *
5015 gst_value_serialize (const GValue * value)
5016 {
5017   guint i, len;
5018   GValue s_val = { 0 };
5019   GstValueTable *table, *best;
5020   gchar *s;
5021   GType type;
5022
5023   g_return_val_if_fail (G_IS_VALUE (value), NULL);
5024
5025   type = G_VALUE_TYPE (value);
5026
5027   best = gst_value_hash_lookup_type (type);
5028
5029   if (G_UNLIKELY (!best || !best->serialize)) {
5030     len = gst_value_table->len;
5031     best = NULL;
5032     for (i = 0; i < len; i++) {
5033       table = &g_array_index (gst_value_table, GstValueTable, i);
5034       if (table->serialize && g_type_is_a (type, table->type)) {
5035         if (!best || g_type_is_a (table->type, best->type))
5036           best = table;
5037       }
5038     }
5039   }
5040   if (G_LIKELY (best))
5041     return best->serialize (value);
5042
5043   g_value_init (&s_val, G_TYPE_STRING);
5044   if (g_value_transform (value, &s_val)) {
5045     s = gst_string_wrap (g_value_get_string (&s_val));
5046   } else {
5047     s = NULL;
5048   }
5049   g_value_unset (&s_val);
5050
5051   return s;
5052 }
5053
5054 /**
5055  * gst_value_deserialize:
5056  * @dest: (out caller-allocates): #GValue to fill with contents of
5057  *     deserialization
5058  * @src: string to deserialize
5059  *
5060  * Tries to deserialize a string into the type specified by the given GValue.
5061  * If the operation succeeds, TRUE is returned, FALSE otherwise.
5062  *
5063  * Returns: TRUE on success
5064  */
5065 gboolean
5066 gst_value_deserialize (GValue * dest, const gchar * src)
5067 {
5068   GstValueTable *table, *best;
5069   guint i, len;
5070   GType type;
5071
5072   g_return_val_if_fail (src != NULL, FALSE);
5073   g_return_val_if_fail (G_IS_VALUE (dest), FALSE);
5074
5075   type = G_VALUE_TYPE (dest);
5076
5077   best = gst_value_hash_lookup_type (type);
5078   if (G_UNLIKELY (!best || !best->deserialize)) {
5079     len = gst_value_table->len;
5080     best = NULL;
5081     for (i = 0; i < len; i++) {
5082       table = &g_array_index (gst_value_table, GstValueTable, i);
5083       if (table->deserialize && g_type_is_a (type, table->type)) {
5084         if (!best || g_type_is_a (table->type, best->type))
5085           best = table;
5086       }
5087     }
5088   }
5089   if (G_LIKELY (best))
5090     return best->deserialize (dest, src);
5091
5092   return FALSE;
5093 }
5094
5095 /**
5096  * gst_value_is_fixed:
5097  * @value: the #GValue to check
5098  *
5099  * Tests if the given GValue, if available in a GstStructure (or any other
5100  * container) contains a "fixed" (which means: one value) or an "unfixed"
5101  * (which means: multiple possible values, such as data lists or data
5102  * ranges) value.
5103  *
5104  * Returns: true if the value is "fixed".
5105  */
5106
5107 gboolean
5108 gst_value_is_fixed (const GValue * value)
5109 {
5110   GType type;
5111
5112   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
5113
5114   type = G_VALUE_TYPE (value);
5115
5116   /* the most common types are just basic plain glib types */
5117   if (type <= G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
5118     return TRUE;
5119   }
5120
5121   if (type == GST_TYPE_ARRAY) {
5122     gint size, n;
5123     const GValue *kid;
5124
5125     /* check recursively */
5126     size = gst_value_array_get_size (value);
5127     for (n = 0; n < size; n++) {
5128       kid = gst_value_array_get_value (value, n);
5129       if (!gst_value_is_fixed (kid))
5130         return FALSE;
5131     }
5132     return TRUE;
5133   }
5134   return gst_type_is_fixed (type);
5135 }
5136
5137 /**
5138  * gst_value_fixate:
5139  * @dest: the #GValue destination
5140  * @src: the #GValue to fixate
5141  *
5142  * Fixate @src into a new value @dest.
5143  * For ranges, the first element is taken. For lists and arrays, the
5144  * first item is fixated and returned.
5145  * If @src is already fixed, this function returns FALSE.
5146  *
5147  * Returns: true if @dest contains a fixated version of @src.
5148  */
5149 gboolean
5150 gst_value_fixate (GValue * dest, const GValue * src)
5151 {
5152   g_return_val_if_fail (G_IS_VALUE (src), FALSE);
5153   g_return_val_if_fail (dest != NULL, FALSE);
5154
5155   if (G_VALUE_TYPE (src) == GST_TYPE_INT_RANGE) {
5156     g_value_init (dest, G_TYPE_INT);
5157     g_value_set_int (dest, gst_value_get_int_range_min (src));
5158   } else if (G_VALUE_TYPE (src) == GST_TYPE_DOUBLE_RANGE) {
5159     g_value_init (dest, G_TYPE_DOUBLE);
5160     g_value_set_double (dest, gst_value_get_double_range_min (src));
5161   } else if (G_VALUE_TYPE (src) == GST_TYPE_FRACTION_RANGE) {
5162     gst_value_init_and_copy (dest, gst_value_get_fraction_range_min (src));
5163   } else if (G_VALUE_TYPE (src) == GST_TYPE_LIST) {
5164     GValue temp = { 0 };
5165
5166     /* list could be empty */
5167     if (gst_value_list_get_size (src) <= 0)
5168       return FALSE;
5169
5170     gst_value_init_and_copy (&temp, gst_value_list_get_value (src, 0));
5171
5172     if (!gst_value_fixate (dest, &temp)) {
5173       gst_value_move (dest, &temp);
5174     } else {
5175       g_value_unset (&temp);
5176     }
5177   } else if (G_VALUE_TYPE (src) == GST_TYPE_ARRAY) {
5178     gboolean res = FALSE;
5179     guint n, len;
5180
5181     len = gst_value_array_get_size (src);
5182     g_value_init (dest, GST_TYPE_ARRAY);
5183     for (n = 0; n < len; n++) {
5184       GValue kid = { 0 };
5185       const GValue *orig_kid = gst_value_array_get_value (src, n);
5186
5187       if (!gst_value_fixate (&kid, orig_kid))
5188         gst_value_init_and_copy (&kid, orig_kid);
5189       else
5190         res = TRUE;
5191       _gst_value_array_append_and_take_value (dest, &kid);
5192     }
5193
5194     if (!res)
5195       g_value_unset (dest);
5196
5197     return res;
5198   } else {
5199     return FALSE;
5200   }
5201   return TRUE;
5202 }
5203
5204
5205 /************
5206  * fraction *
5207  ************/
5208
5209 /* helper functions */
5210 static void
5211 gst_value_init_fraction (GValue * value)
5212 {
5213   value->data[0].v_int = 0;
5214   value->data[1].v_int = 1;
5215 }
5216
5217 static void
5218 gst_value_copy_fraction (const GValue * src_value, GValue * dest_value)
5219 {
5220   dest_value->data[0].v_int = src_value->data[0].v_int;
5221   dest_value->data[1].v_int = src_value->data[1].v_int;
5222 }
5223
5224 static gchar *
5225 gst_value_collect_fraction (GValue * value, guint n_collect_values,
5226     GTypeCValue * collect_values, guint collect_flags)
5227 {
5228   if (n_collect_values != 2)
5229     return g_strdup_printf ("not enough value locations for `%s' passed",
5230         G_VALUE_TYPE_NAME (value));
5231   if (collect_values[1].v_int == 0)
5232     return g_strdup_printf ("passed '0' as denominator for `%s'",
5233         G_VALUE_TYPE_NAME (value));
5234   if (collect_values[0].v_int < -G_MAXINT)
5235     return
5236         g_strdup_printf
5237         ("passed value smaller than -G_MAXINT as numerator for `%s'",
5238         G_VALUE_TYPE_NAME (value));
5239   if (collect_values[1].v_int < -G_MAXINT)
5240     return
5241         g_strdup_printf
5242         ("passed value smaller than -G_MAXINT as denominator for `%s'",
5243         G_VALUE_TYPE_NAME (value));
5244
5245   gst_value_set_fraction (value,
5246       collect_values[0].v_int, collect_values[1].v_int);
5247
5248   return NULL;
5249 }
5250
5251 static gchar *
5252 gst_value_lcopy_fraction (const GValue * value, guint n_collect_values,
5253     GTypeCValue * collect_values, guint collect_flags)
5254 {
5255   gint *numerator = collect_values[0].v_pointer;
5256   gint *denominator = collect_values[1].v_pointer;
5257
5258   if (!numerator)
5259     return g_strdup_printf ("numerator for `%s' passed as NULL",
5260         G_VALUE_TYPE_NAME (value));
5261   if (!denominator)
5262     return g_strdup_printf ("denominator for `%s' passed as NULL",
5263         G_VALUE_TYPE_NAME (value));
5264
5265   *numerator = value->data[0].v_int;
5266   *denominator = value->data[1].v_int;
5267
5268   return NULL;
5269 }
5270
5271 /**
5272  * gst_value_set_fraction:
5273  * @value: a GValue initialized to #GST_TYPE_FRACTION
5274  * @numerator: the numerator of the fraction
5275  * @denominator: the denominator of the fraction
5276  *
5277  * Sets @value to the fraction specified by @numerator over @denominator.
5278  * The fraction gets reduced to the smallest numerator and denominator,
5279  * and if necessary the sign is moved to the numerator.
5280  */
5281 void
5282 gst_value_set_fraction (GValue * value, gint numerator, gint denominator)
5283 {
5284   gint gcd = 0;
5285
5286   g_return_if_fail (GST_VALUE_HOLDS_FRACTION (value));
5287   g_return_if_fail (denominator != 0);
5288   g_return_if_fail (denominator >= -G_MAXINT);
5289   g_return_if_fail (numerator >= -G_MAXINT);
5290
5291   /* normalize sign */
5292   if (denominator < 0) {
5293     numerator = -numerator;
5294     denominator = -denominator;
5295   }
5296
5297   /* check for reduction */
5298   gcd = gst_util_greatest_common_divisor (numerator, denominator);
5299   if (gcd) {
5300     numerator /= gcd;
5301     denominator /= gcd;
5302   }
5303
5304   g_assert (denominator > 0);
5305
5306   value->data[0].v_int = numerator;
5307   value->data[1].v_int = denominator;
5308 }
5309
5310 /**
5311  * gst_value_get_fraction_numerator:
5312  * @value: a GValue initialized to #GST_TYPE_FRACTION
5313  *
5314  * Gets the numerator of the fraction specified by @value.
5315  *
5316  * Returns: the numerator of the fraction.
5317  */
5318 gint
5319 gst_value_get_fraction_numerator (const GValue * value)
5320 {
5321   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 0);
5322
5323   return value->data[0].v_int;
5324 }
5325
5326 /**
5327  * gst_value_get_fraction_denominator:
5328  * @value: a GValue initialized to #GST_TYPE_FRACTION
5329  *
5330  * Gets the denominator of the fraction specified by @value.
5331  *
5332  * Returns: the denominator of the fraction.
5333  */
5334 gint
5335 gst_value_get_fraction_denominator (const GValue * value)
5336 {
5337   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 1);
5338
5339   return value->data[1].v_int;
5340 }
5341
5342 /**
5343  * gst_value_fraction_multiply:
5344  * @product: a GValue initialized to #GST_TYPE_FRACTION
5345  * @factor1: a GValue initialized to #GST_TYPE_FRACTION
5346  * @factor2: a GValue initialized to #GST_TYPE_FRACTION
5347  *
5348  * Multiplies the two #GValue items containing a #GST_TYPE_FRACTION and sets
5349  * @product to the product of the two fractions.
5350  *
5351  * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise.
5352  */
5353 gboolean
5354 gst_value_fraction_multiply (GValue * product, const GValue * factor1,
5355     const GValue * factor2)
5356 {
5357   gint n1, n2, d1, d2;
5358   gint res_n, res_d;
5359
5360   g_return_val_if_fail (product != NULL, FALSE);
5361   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor1), FALSE);
5362   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor2), FALSE);
5363
5364   n1 = factor1->data[0].v_int;
5365   n2 = factor2->data[0].v_int;
5366   d1 = factor1->data[1].v_int;
5367   d2 = factor2->data[1].v_int;
5368
5369   if (!gst_util_fraction_multiply (n1, d1, n2, d2, &res_n, &res_d))
5370     return FALSE;
5371
5372   gst_value_set_fraction (product, res_n, res_d);
5373
5374   return TRUE;
5375 }
5376
5377 /**
5378  * gst_value_fraction_subtract:
5379  * @dest: a GValue initialized to #GST_TYPE_FRACTION
5380  * @minuend: a GValue initialized to #GST_TYPE_FRACTION
5381  * @subtrahend: a GValue initialized to #GST_TYPE_FRACTION
5382  *
5383  * Subtracts the @subtrahend from the @minuend and sets @dest to the result.
5384  *
5385  * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise.
5386  */
5387 gboolean
5388 gst_value_fraction_subtract (GValue * dest,
5389     const GValue * minuend, const GValue * subtrahend)
5390 {
5391   gint n1, n2, d1, d2;
5392   gint res_n, res_d;
5393
5394   g_return_val_if_fail (dest != NULL, FALSE);
5395   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (minuend), FALSE);
5396   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (subtrahend), FALSE);
5397
5398   n1 = minuend->data[0].v_int;
5399   n2 = subtrahend->data[0].v_int;
5400   d1 = minuend->data[1].v_int;
5401   d2 = subtrahend->data[1].v_int;
5402
5403   if (!gst_util_fraction_add (n1, d1, -n2, d2, &res_n, &res_d))
5404     return FALSE;
5405   gst_value_set_fraction (dest, res_n, res_d);
5406
5407   return TRUE;
5408 }
5409
5410 static gchar *
5411 gst_value_serialize_fraction (const GValue * value)
5412 {
5413   gint32 numerator = value->data[0].v_int;
5414   gint32 denominator = value->data[1].v_int;
5415   gboolean positive = TRUE;
5416
5417   /* get the sign and make components absolute */
5418   if (numerator < 0) {
5419     numerator = -numerator;
5420     positive = !positive;
5421   }
5422   if (denominator < 0) {
5423     denominator = -denominator;
5424     positive = !positive;
5425   }
5426
5427   return g_strdup_printf ("%s%d/%d",
5428       positive ? "" : "-", numerator, denominator);
5429 }
5430
5431 static gboolean
5432 gst_value_deserialize_fraction (GValue * dest, const gchar * s)
5433 {
5434   gint num, den;
5435   gint num_chars;
5436
5437   if (G_UNLIKELY (s == NULL))
5438     return FALSE;
5439
5440   if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_FRACTION (dest)))
5441     return FALSE;
5442
5443   if (sscanf (s, "%d/%d%n", &num, &den, &num_chars) >= 2) {
5444     if (s[num_chars] != 0)
5445       return FALSE;
5446     if (den == 0)
5447       return FALSE;
5448
5449     gst_value_set_fraction (dest, num, den);
5450     return TRUE;
5451   } else if (g_ascii_strcasecmp (s, "1/max") == 0) {
5452     gst_value_set_fraction (dest, 1, G_MAXINT);
5453     return TRUE;
5454   } else if (sscanf (s, "%d%n", &num, &num_chars) >= 1) {
5455     if (s[num_chars] != 0)
5456       return FALSE;
5457     gst_value_set_fraction (dest, num, 1);
5458     return TRUE;
5459   } else if (g_ascii_strcasecmp (s, "min") == 0) {
5460     gst_value_set_fraction (dest, -G_MAXINT, 1);
5461     return TRUE;
5462   } else if (g_ascii_strcasecmp (s, "max") == 0) {
5463     gst_value_set_fraction (dest, G_MAXINT, 1);
5464     return TRUE;
5465   }
5466
5467   return FALSE;
5468 }
5469
5470 static void
5471 gst_value_transform_fraction_string (const GValue * src_value,
5472     GValue * dest_value)
5473 {
5474   dest_value->data[0].v_pointer = gst_value_serialize_fraction (src_value);
5475 }
5476
5477 static void
5478 gst_value_transform_string_fraction (const GValue * src_value,
5479     GValue * dest_value)
5480 {
5481   if (!gst_value_deserialize_fraction (dest_value,
5482           src_value->data[0].v_pointer))
5483     /* If the deserialize fails, ensure we leave the fraction in a
5484      * valid, if incorrect, state */
5485     gst_value_set_fraction (dest_value, 0, 1);
5486 }
5487
5488 static void
5489 gst_value_transform_double_fraction (const GValue * src_value,
5490     GValue * dest_value)
5491 {
5492   gdouble src = g_value_get_double (src_value);
5493   gint n, d;
5494
5495   gst_util_double_to_fraction (src, &n, &d);
5496   gst_value_set_fraction (dest_value, n, d);
5497 }
5498
5499 static void
5500 gst_value_transform_float_fraction (const GValue * src_value,
5501     GValue * dest_value)
5502 {
5503   gfloat src = g_value_get_float (src_value);
5504   gint n, d;
5505
5506   gst_util_double_to_fraction (src, &n, &d);
5507   gst_value_set_fraction (dest_value, n, d);
5508 }
5509
5510 static void
5511 gst_value_transform_fraction_double (const GValue * src_value,
5512     GValue * dest_value)
5513 {
5514   dest_value->data[0].v_double = ((double) src_value->data[0].v_int) /
5515       ((double) src_value->data[1].v_int);
5516 }
5517
5518 static void
5519 gst_value_transform_fraction_float (const GValue * src_value,
5520     GValue * dest_value)
5521 {
5522   dest_value->data[0].v_float = ((float) src_value->data[0].v_int) /
5523       ((float) src_value->data[1].v_int);
5524 }
5525
5526 static gint
5527 gst_value_compare_fraction (const GValue * value1, const GValue * value2)
5528 {
5529   gint n1, n2;
5530   gint d1, d2;
5531   gint ret;
5532
5533   n1 = value1->data[0].v_int;
5534   n2 = value2->data[0].v_int;
5535   d1 = value1->data[1].v_int;
5536   d2 = value2->data[1].v_int;
5537
5538   /* fractions are reduced when set, so we can quickly see if they're equal */
5539   if (n1 == n2 && d1 == d2)
5540     return GST_VALUE_EQUAL;
5541
5542   if (d1 == 0 && d2 == 0)
5543     return GST_VALUE_UNORDERED;
5544   else if (d1 == 0)
5545     return GST_VALUE_GREATER_THAN;
5546   else if (d2 == 0)
5547     return GST_VALUE_LESS_THAN;
5548
5549   ret = gst_util_fraction_compare (n1, d1, n2, d2);
5550   if (ret == -1)
5551     return GST_VALUE_LESS_THAN;
5552   else if (ret == 1)
5553     return GST_VALUE_GREATER_THAN;
5554
5555   /* Equality can't happen here because we check for that
5556    * first already */
5557   g_return_val_if_reached (GST_VALUE_UNORDERED);
5558 }
5559
5560 /*********
5561  * GDate *
5562  *********/
5563
5564 static gint
5565 gst_value_compare_date (const GValue * value1, const GValue * value2)
5566 {
5567   const GDate *date1 = (const GDate *) g_value_get_boxed (value1);
5568   const GDate *date2 = (const GDate *) g_value_get_boxed (value2);
5569   guint32 j1, j2;
5570
5571   if (date1 == date2)
5572     return GST_VALUE_EQUAL;
5573
5574   if ((date1 == NULL || !g_date_valid (date1))
5575       && (date2 != NULL && g_date_valid (date2))) {
5576     return GST_VALUE_LESS_THAN;
5577   }
5578
5579   if ((date2 == NULL || !g_date_valid (date2))
5580       && (date1 != NULL && g_date_valid (date1))) {
5581     return GST_VALUE_GREATER_THAN;
5582   }
5583
5584   if (date1 == NULL || date2 == NULL || !g_date_valid (date1)
5585       || !g_date_valid (date2)) {
5586     return GST_VALUE_UNORDERED;
5587   }
5588
5589   j1 = g_date_get_julian (date1);
5590   j2 = g_date_get_julian (date2);
5591
5592   if (j1 == j2)
5593     return GST_VALUE_EQUAL;
5594   else if (j1 < j2)
5595     return GST_VALUE_LESS_THAN;
5596   else
5597     return GST_VALUE_GREATER_THAN;
5598 }
5599
5600 static gchar *
5601 gst_value_serialize_date (const GValue * val)
5602 {
5603   const GDate *date = (const GDate *) g_value_get_boxed (val);
5604
5605   if (date == NULL || !g_date_valid (date))
5606     return g_strdup ("9999-99-99");
5607
5608   return g_strdup_printf ("%04u-%02u-%02u", g_date_get_year (date),
5609       g_date_get_month (date), g_date_get_day (date));
5610 }
5611
5612 static gboolean
5613 gst_value_deserialize_date (GValue * dest, const gchar * s)
5614 {
5615   guint year, month, day;
5616
5617   if (!s || sscanf (s, "%04u-%02u-%02u", &year, &month, &day) != 3)
5618     return FALSE;
5619
5620   if (!g_date_valid_dmy (day, month, year))
5621     return FALSE;
5622
5623   g_value_take_boxed (dest, g_date_new_dmy (day, month, year));
5624   return TRUE;
5625 }
5626
5627 /*************
5628  * GstDateTime *
5629  *************/
5630
5631 static gint
5632 gst_value_compare_date_time (const GValue * value1, const GValue * value2)
5633 {
5634   const GstDateTime *date1 = (const GstDateTime *) g_value_get_boxed (value1);
5635   const GstDateTime *date2 = (const GstDateTime *) g_value_get_boxed (value2);
5636
5637   if (date1 == date2)
5638     return GST_VALUE_EQUAL;
5639
5640   if ((date1 == NULL) && (date2 != NULL)) {
5641     return GST_VALUE_LESS_THAN;
5642   }
5643   if ((date2 == NULL) && (date1 != NULL)) {
5644     return GST_VALUE_LESS_THAN;
5645   }
5646
5647   /* returns GST_VALUE_* */
5648   return __gst_date_time_compare (date1, date2);
5649 }
5650
5651 static gchar *
5652 gst_value_serialize_date_time (const GValue * val)
5653 {
5654   GstDateTime *date = (GstDateTime *) g_value_get_boxed (val);
5655
5656   if (date == NULL)
5657     return g_strdup ("null");
5658
5659   return __gst_date_time_serialize (date, TRUE);
5660 }
5661
5662 static gboolean
5663 gst_value_deserialize_date_time (GValue * dest, const gchar * s)
5664 {
5665   GstDateTime *datetime;
5666
5667   if (!s || strcmp (s, "null") == 0) {
5668     return FALSE;
5669   }
5670
5671   datetime = gst_date_time_new_from_iso8601_string (s);
5672   if (datetime != NULL) {
5673     g_value_take_boxed (dest, datetime);
5674     return TRUE;
5675   }
5676   GST_WARNING ("Failed to deserialize date time string '%s'", s);
5677   return FALSE;
5678 }
5679
5680 static void
5681 gst_value_transform_date_string (const GValue * src_value, GValue * dest_value)
5682 {
5683   dest_value->data[0].v_pointer = gst_value_serialize_date (src_value);
5684 }
5685
5686 static void
5687 gst_value_transform_string_date (const GValue * src_value, GValue * dest_value)
5688 {
5689   gst_value_deserialize_date (dest_value, src_value->data[0].v_pointer);
5690 }
5691
5692
5693 /************
5694  * bitmask *
5695  ************/
5696
5697 /* helper functions */
5698 static void
5699 gst_value_init_bitmask (GValue * value)
5700 {
5701   value->data[0].v_uint64 = 0;
5702 }
5703
5704 static void
5705 gst_value_copy_bitmask (const GValue * src_value, GValue * dest_value)
5706 {
5707   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
5708 }
5709
5710 static gchar *
5711 gst_value_collect_bitmask (GValue * value, guint n_collect_values,
5712     GTypeCValue * collect_values, guint collect_flags)
5713 {
5714   if (n_collect_values != 1)
5715     return g_strdup_printf ("not enough value locations for `%s' passed",
5716         G_VALUE_TYPE_NAME (value));
5717
5718   gst_value_set_bitmask (value, (guint64) collect_values[0].v_int64);
5719
5720   return NULL;
5721 }
5722
5723 static gchar *
5724 gst_value_lcopy_bitmask (const GValue * value, guint n_collect_values,
5725     GTypeCValue * collect_values, guint collect_flags)
5726 {
5727   guint64 *bitmask = collect_values[0].v_pointer;
5728
5729   if (!bitmask)
5730     return g_strdup_printf ("value for `%s' passed as NULL",
5731         G_VALUE_TYPE_NAME (value));
5732
5733   *bitmask = value->data[0].v_uint64;
5734
5735   return NULL;
5736 }
5737
5738 /**
5739  * gst_value_set_bitmask:
5740  * @value: a GValue initialized to #GST_TYPE_BITMASK
5741  * @bitmask: the bitmask
5742  *
5743  * Sets @value to the bitmask specified by @bitmask.
5744  */
5745 void
5746 gst_value_set_bitmask (GValue * value, guint64 bitmask)
5747 {
5748   g_return_if_fail (GST_VALUE_HOLDS_BITMASK (value));
5749
5750   value->data[0].v_uint64 = bitmask;
5751 }
5752
5753 /**
5754  * gst_value_get_bitmask:
5755  * @value: a GValue initialized to #GST_TYPE_BITMASK
5756  *
5757  * Gets the bitmask specified by @value.
5758  *
5759  * Returns: the bitmask.
5760  */
5761 guint64
5762 gst_value_get_bitmask (const GValue * value)
5763 {
5764   g_return_val_if_fail (GST_VALUE_HOLDS_BITMASK (value), 0);
5765
5766   return value->data[0].v_uint64;
5767 }
5768
5769 static gchar *
5770 gst_value_serialize_bitmask (const GValue * value)
5771 {
5772   guint64 bitmask = value->data[0].v_uint64;
5773
5774   return g_strdup_printf ("0x%016" G_GINT64_MODIFIER "x", bitmask);
5775 }
5776
5777 static gboolean
5778 gst_value_deserialize_bitmask (GValue * dest, const gchar * s)
5779 {
5780   gchar *endptr = NULL;
5781   guint64 val;
5782
5783   if (G_UNLIKELY (s == NULL))
5784     return FALSE;
5785
5786   if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_BITMASK (dest)))
5787     return FALSE;
5788
5789   val = g_ascii_strtoull (s, &endptr, 16);
5790   if (val == G_MAXUINT64 && (errno == ERANGE || errno == EINVAL))
5791     return FALSE;
5792   if (val == 0 && endptr == s)
5793     return FALSE;
5794
5795   gst_value_set_bitmask (dest, val);
5796
5797   return TRUE;
5798 }
5799
5800 static void
5801 gst_value_transform_bitmask_string (const GValue * src_value,
5802     GValue * dest_value)
5803 {
5804   dest_value->data[0].v_pointer = gst_value_serialize_bitmask (src_value);
5805 }
5806
5807 static void
5808 gst_value_transform_string_bitmask (const GValue * src_value,
5809     GValue * dest_value)
5810 {
5811   if (!gst_value_deserialize_bitmask (dest_value, src_value->data[0].v_pointer))
5812     gst_value_set_bitmask (dest_value, 0);
5813 }
5814
5815 static void
5816 gst_value_transform_uint64_bitmask (const GValue * src_value,
5817     GValue * dest_value)
5818 {
5819   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
5820 }
5821
5822 static void
5823 gst_value_transform_bitmask_uint64 (const GValue * src_value,
5824     GValue * dest_value)
5825 {
5826   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
5827 }
5828
5829 static gint
5830 gst_value_compare_bitmask (const GValue * value1, const GValue * value2)
5831 {
5832   guint64 v1, v2;
5833
5834   v1 = value1->data[0].v_uint64;
5835   v2 = value2->data[0].v_uint64;
5836
5837   if (v1 == v2)
5838     return GST_VALUE_EQUAL;
5839
5840   return GST_VALUE_UNORDERED;
5841 }
5842
5843 static void
5844 gst_value_transform_object_string (const GValue * src_value,
5845     GValue * dest_value)
5846 {
5847   GstObject *obj;
5848   gchar *str;
5849
5850   obj = g_value_get_object (src_value);
5851   if (obj) {
5852     str =
5853         g_strdup_printf ("(%s) %s", G_OBJECT_TYPE_NAME (obj),
5854         GST_OBJECT_NAME (obj));
5855   } else {
5856     str = g_strdup ("NULL");
5857   }
5858
5859   dest_value->data[0].v_pointer = str;
5860 }
5861
5862 static GTypeInfo _info = {
5863   0,
5864   NULL,
5865   NULL,
5866   NULL,
5867   NULL,
5868   NULL,
5869   0,
5870   0,
5871   NULL,
5872   NULL,
5873 };
5874
5875 static GTypeFundamentalInfo _finfo = {
5876   0
5877 };
5878
5879 #define FUNC_VALUE_GET_TYPE(type, name)                         \
5880 GType gst_ ## type ## _get_type (void)                          \
5881 {                                                               \
5882   static volatile GType gst_ ## type ## _type = 0;                       \
5883                                                                 \
5884   if (g_once_init_enter (&gst_ ## type ## _type)) {             \
5885     GType _type;                                        \
5886     _info.value_table = & _gst_ ## type ## _value_table;        \
5887     _type = g_type_register_fundamental (       \
5888         g_type_fundamental_next (),                             \
5889         name, &_info, &_finfo, 0);                              \
5890     g_once_init_leave(&gst_ ## type ## _type, _type);   \
5891   }                                                             \
5892                                                                 \
5893   return gst_ ## type ## _type;                                 \
5894 }
5895
5896 static const GTypeValueTable _gst_int_range_value_table = {
5897   gst_value_init_int_range,
5898   gst_value_free_int_range,
5899   gst_value_copy_int_range,
5900   NULL,
5901   (char *) "ii",
5902   gst_value_collect_int_range,
5903   (char *) "pp",
5904   gst_value_lcopy_int_range
5905 };
5906
5907 FUNC_VALUE_GET_TYPE (int_range, "GstIntRange");
5908
5909 static const GTypeValueTable _gst_int64_range_value_table = {
5910   gst_value_init_int64_range,
5911   gst_value_free_int64_range,
5912   gst_value_copy_int64_range,
5913   NULL,
5914   (char *) "qq",
5915   gst_value_collect_int64_range,
5916   (char *) "pp",
5917   gst_value_lcopy_int64_range
5918 };
5919
5920 FUNC_VALUE_GET_TYPE (int64_range, "GstInt64Range");
5921
5922 static const GTypeValueTable _gst_double_range_value_table = {
5923   gst_value_init_double_range,
5924   NULL,
5925   gst_value_copy_double_range,
5926   NULL,
5927   (char *) "dd",
5928   gst_value_collect_double_range,
5929   (char *) "pp",
5930   gst_value_lcopy_double_range
5931 };
5932
5933 FUNC_VALUE_GET_TYPE (double_range, "GstDoubleRange");
5934
5935 static const GTypeValueTable _gst_fraction_range_value_table = {
5936   gst_value_init_fraction_range,
5937   gst_value_free_fraction_range,
5938   gst_value_copy_fraction_range,
5939   NULL,
5940   (char *) "iiii",
5941   gst_value_collect_fraction_range,
5942   (char *) "pppp",
5943   gst_value_lcopy_fraction_range
5944 };
5945
5946 FUNC_VALUE_GET_TYPE (fraction_range, "GstFractionRange");
5947
5948 static const GTypeValueTable _gst_value_list_value_table = {
5949   gst_value_init_list_or_array,
5950   gst_value_free_list_or_array,
5951   gst_value_copy_list_or_array,
5952   gst_value_list_or_array_peek_pointer,
5953   (char *) "p",
5954   gst_value_collect_list_or_array,
5955   (char *) "p",
5956   gst_value_lcopy_list_or_array
5957 };
5958
5959 FUNC_VALUE_GET_TYPE (value_list, "GstValueList");
5960
5961 static const GTypeValueTable _gst_value_array_value_table = {
5962   gst_value_init_list_or_array,
5963   gst_value_free_list_or_array,
5964   gst_value_copy_list_or_array,
5965   gst_value_list_or_array_peek_pointer,
5966   (char *) "p",
5967   gst_value_collect_list_or_array,
5968   (char *) "p",
5969   gst_value_lcopy_list_or_array
5970 };
5971
5972 FUNC_VALUE_GET_TYPE (value_array, "GstValueArray");
5973
5974 static const GTypeValueTable _gst_fraction_value_table = {
5975   gst_value_init_fraction,
5976   NULL,
5977   gst_value_copy_fraction,
5978   NULL,
5979   (char *) "ii",
5980   gst_value_collect_fraction,
5981   (char *) "pp",
5982   gst_value_lcopy_fraction
5983 };
5984
5985 FUNC_VALUE_GET_TYPE (fraction, "GstFraction");
5986
5987 G_DEFINE_BOXED_TYPE (GstDateTime, gst_date_time,
5988     (GBoxedCopyFunc) gst_date_time_ref, (GBoxedFreeFunc) gst_date_time_unref);
5989
5990 static const GTypeValueTable _gst_bitmask_value_table = {
5991   gst_value_init_bitmask,
5992   NULL,
5993   gst_value_copy_bitmask,
5994   NULL,
5995   (char *) "q",
5996   gst_value_collect_bitmask,
5997   (char *) "p",
5998   gst_value_lcopy_bitmask
5999 };
6000
6001 FUNC_VALUE_GET_TYPE (bitmask, "GstBitmask");
6002
6003 GType
6004 gst_g_thread_get_type (void)
6005 {
6006 #if GLIB_CHECK_VERSION(2,35,3)
6007   return G_TYPE_THREAD;
6008 #else
6009   static volatile gsize type_id = 0;
6010
6011   if (g_once_init_enter (&type_id)) {
6012     GType tmp =
6013         g_boxed_type_register_static (g_intern_static_string ("GstGThread"),
6014         (GBoxedCopyFunc) g_thread_ref,
6015         (GBoxedFreeFunc) g_thread_unref);
6016     g_once_init_leave (&type_id, tmp);
6017   }
6018
6019   return type_id;
6020 #endif
6021 }
6022
6023 void
6024 _priv_gst_value_initialize (void)
6025 {
6026   gst_value_table = g_array_new (FALSE, FALSE, sizeof (GstValueTable));
6027   gst_value_hash = g_hash_table_new (NULL, NULL);
6028   gst_value_union_funcs = g_array_new (FALSE, FALSE,
6029       sizeof (GstValueUnionInfo));
6030   gst_value_intersect_funcs = g_array_new (FALSE, FALSE,
6031       sizeof (GstValueIntersectInfo));
6032   gst_value_subtract_funcs = g_array_new (FALSE, FALSE,
6033       sizeof (GstValueSubtractInfo));
6034
6035   {
6036     static GstValueTable gst_value = {
6037       0,
6038       gst_value_compare_int_range,
6039       gst_value_serialize_int_range,
6040       gst_value_deserialize_int_range,
6041     };
6042
6043     gst_value.type = gst_int_range_get_type ();
6044     gst_value_register (&gst_value);
6045   }
6046
6047   {
6048     static GstValueTable gst_value = {
6049       0,
6050       gst_value_compare_int64_range,
6051       gst_value_serialize_int64_range,
6052       gst_value_deserialize_int64_range,
6053     };
6054
6055     gst_value.type = gst_int64_range_get_type ();
6056     gst_value_register (&gst_value);
6057   }
6058
6059   {
6060     static GstValueTable gst_value = {
6061       0,
6062       gst_value_compare_double_range,
6063       gst_value_serialize_double_range,
6064       gst_value_deserialize_double_range,
6065     };
6066
6067     gst_value.type = gst_double_range_get_type ();
6068     gst_value_register (&gst_value);
6069   }
6070
6071   {
6072     static GstValueTable gst_value = {
6073       0,
6074       gst_value_compare_fraction_range,
6075       gst_value_serialize_fraction_range,
6076       gst_value_deserialize_fraction_range,
6077     };
6078
6079     gst_value.type = gst_fraction_range_get_type ();
6080     gst_value_register (&gst_value);
6081   }
6082
6083   {
6084     static GstValueTable gst_value = {
6085       0,
6086       gst_value_compare_list,
6087       gst_value_serialize_list,
6088       gst_value_deserialize_list,
6089     };
6090
6091     gst_value.type = gst_value_list_get_type ();
6092     gst_value_register (&gst_value);
6093   }
6094
6095   {
6096     static GstValueTable gst_value = {
6097       0,
6098       gst_value_compare_array,
6099       gst_value_serialize_array,
6100       gst_value_deserialize_array,
6101     };
6102
6103     gst_value.type = gst_value_array_get_type ();
6104     gst_value_register (&gst_value);
6105   }
6106
6107   {
6108 #if 0
6109     static const GTypeValueTable value_table = {
6110       gst_value_init_buffer,
6111       NULL,
6112       gst_value_copy_buffer,
6113       NULL,
6114       "i",
6115       NULL,                     /*gst_value_collect_buffer, */
6116       "p",
6117       NULL                      /*gst_value_lcopy_buffer */
6118     };
6119 #endif
6120     static GstValueTable gst_value = {
6121       0,
6122       gst_value_compare_buffer,
6123       gst_value_serialize_buffer,
6124       gst_value_deserialize_buffer,
6125     };
6126
6127     gst_value.type = GST_TYPE_BUFFER;
6128     gst_value_register (&gst_value);
6129   }
6130   {
6131     static GstValueTable gst_value = {
6132       0,
6133       gst_value_compare_sample,
6134       gst_value_serialize_sample,
6135       gst_value_deserialize_sample,
6136     };
6137
6138     gst_value.type = GST_TYPE_SAMPLE;
6139     gst_value_register (&gst_value);
6140   }
6141   {
6142     static GstValueTable gst_value = {
6143       0,
6144       gst_value_compare_fraction,
6145       gst_value_serialize_fraction,
6146       gst_value_deserialize_fraction,
6147     };
6148
6149     gst_value.type = gst_fraction_get_type ();
6150     gst_value_register (&gst_value);
6151   }
6152   {
6153     static GstValueTable gst_value = {
6154       0,
6155       gst_value_compare_caps,
6156       gst_value_serialize_caps,
6157       gst_value_deserialize_caps,
6158     };
6159
6160     gst_value.type = GST_TYPE_CAPS;
6161     gst_value_register (&gst_value);
6162   }
6163   {
6164     static GstValueTable gst_value = {
6165       0,
6166       NULL,
6167       gst_value_serialize_segment,
6168       gst_value_deserialize_segment,
6169     };
6170
6171     gst_value.type = GST_TYPE_SEGMENT;
6172     gst_value_register (&gst_value);
6173   }
6174   {
6175     static GstValueTable gst_value = {
6176       0,
6177       NULL,
6178       gst_value_serialize_structure,
6179       gst_value_deserialize_structure,
6180     };
6181
6182     gst_value.type = GST_TYPE_STRUCTURE;
6183     gst_value_register (&gst_value);
6184   }
6185   {
6186     static GstValueTable gst_value = {
6187       0,
6188       NULL,
6189       gst_value_serialize_caps_features,
6190       gst_value_deserialize_caps_features,
6191     };
6192
6193     gst_value.type = GST_TYPE_CAPS_FEATURES;
6194     gst_value_register (&gst_value);
6195   }
6196   {
6197     static GstValueTable gst_value = {
6198       0,
6199       NULL,
6200       gst_value_serialize_tag_list,
6201       gst_value_deserialize_tag_list,
6202     };
6203
6204     gst_value.type = GST_TYPE_TAG_LIST;
6205     gst_value_register (&gst_value);
6206   }
6207   {
6208     static GstValueTable gst_value = {
6209       0,
6210       gst_value_compare_date,
6211       gst_value_serialize_date,
6212       gst_value_deserialize_date,
6213     };
6214
6215     gst_value.type = G_TYPE_DATE;
6216     gst_value_register (&gst_value);
6217   }
6218   {
6219     static GstValueTable gst_value = {
6220       0,
6221       gst_value_compare_date_time,
6222       gst_value_serialize_date_time,
6223       gst_value_deserialize_date_time,
6224     };
6225
6226     gst_value.type = gst_date_time_get_type ();
6227     gst_value_register (&gst_value);
6228   }
6229
6230   {
6231     static GstValueTable gst_value = {
6232       0,
6233       gst_value_compare_bitmask,
6234       gst_value_serialize_bitmask,
6235       gst_value_deserialize_bitmask,
6236     };
6237
6238     gst_value.type = gst_bitmask_get_type ();
6239     gst_value_register (&gst_value);
6240   }
6241
6242   REGISTER_SERIALIZATION (G_TYPE_DOUBLE, double);
6243   REGISTER_SERIALIZATION (G_TYPE_FLOAT, float);
6244
6245   REGISTER_SERIALIZATION (G_TYPE_STRING, string);
6246   REGISTER_SERIALIZATION (G_TYPE_BOOLEAN, boolean);
6247   REGISTER_SERIALIZATION (G_TYPE_ENUM, enum);
6248
6249   REGISTER_SERIALIZATION (G_TYPE_FLAGS, flags);
6250
6251   REGISTER_SERIALIZATION (G_TYPE_INT, int);
6252
6253   REGISTER_SERIALIZATION (G_TYPE_INT64, int64);
6254   REGISTER_SERIALIZATION (G_TYPE_LONG, long);
6255
6256   REGISTER_SERIALIZATION (G_TYPE_UINT, uint);
6257   REGISTER_SERIALIZATION (G_TYPE_UINT64, uint64);
6258   REGISTER_SERIALIZATION (G_TYPE_ULONG, ulong);
6259
6260   REGISTER_SERIALIZATION (G_TYPE_UCHAR, uchar);
6261
6262   g_value_register_transform_func (GST_TYPE_INT_RANGE, G_TYPE_STRING,
6263       gst_value_transform_int_range_string);
6264   g_value_register_transform_func (GST_TYPE_INT64_RANGE, G_TYPE_STRING,
6265       gst_value_transform_int64_range_string);
6266   g_value_register_transform_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_STRING,
6267       gst_value_transform_double_range_string);
6268   g_value_register_transform_func (GST_TYPE_FRACTION_RANGE, G_TYPE_STRING,
6269       gst_value_transform_fraction_range_string);
6270   g_value_register_transform_func (GST_TYPE_LIST, G_TYPE_STRING,
6271       gst_value_transform_list_string);
6272   g_value_register_transform_func (GST_TYPE_ARRAY, G_TYPE_STRING,
6273       gst_value_transform_array_string);
6274   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_STRING,
6275       gst_value_transform_fraction_string);
6276   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_FRACTION,
6277       gst_value_transform_string_fraction);
6278   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_DOUBLE,
6279       gst_value_transform_fraction_double);
6280   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_FLOAT,
6281       gst_value_transform_fraction_float);
6282   g_value_register_transform_func (G_TYPE_DOUBLE, GST_TYPE_FRACTION,
6283       gst_value_transform_double_fraction);
6284   g_value_register_transform_func (G_TYPE_FLOAT, GST_TYPE_FRACTION,
6285       gst_value_transform_float_fraction);
6286   g_value_register_transform_func (G_TYPE_DATE, G_TYPE_STRING,
6287       gst_value_transform_date_string);
6288   g_value_register_transform_func (G_TYPE_STRING, G_TYPE_DATE,
6289       gst_value_transform_string_date);
6290   g_value_register_transform_func (GST_TYPE_OBJECT, G_TYPE_STRING,
6291       gst_value_transform_object_string);
6292   g_value_register_transform_func (GST_TYPE_BITMASK, G_TYPE_UINT64,
6293       gst_value_transform_bitmask_uint64);
6294   g_value_register_transform_func (GST_TYPE_BITMASK, G_TYPE_STRING,
6295       gst_value_transform_bitmask_string);
6296   g_value_register_transform_func (G_TYPE_UINT64, GST_TYPE_BITMASK,
6297       gst_value_transform_uint64_bitmask);
6298   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_BITMASK,
6299       gst_value_transform_string_bitmask);
6300
6301   gst_value_register_intersect_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
6302       gst_value_intersect_int_int_range);
6303   gst_value_register_intersect_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
6304       gst_value_intersect_int_range_int_range);
6305   gst_value_register_intersect_func (G_TYPE_INT64, GST_TYPE_INT64_RANGE,
6306       gst_value_intersect_int64_int64_range);
6307   gst_value_register_intersect_func (GST_TYPE_INT64_RANGE, GST_TYPE_INT64_RANGE,
6308       gst_value_intersect_int64_range_int64_range);
6309   gst_value_register_intersect_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
6310       gst_value_intersect_double_double_range);
6311   gst_value_register_intersect_func (GST_TYPE_DOUBLE_RANGE,
6312       GST_TYPE_DOUBLE_RANGE, gst_value_intersect_double_range_double_range);
6313   gst_value_register_intersect_func (GST_TYPE_ARRAY,
6314       GST_TYPE_ARRAY, gst_value_intersect_array);
6315   gst_value_register_intersect_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
6316       gst_value_intersect_fraction_fraction_range);
6317   gst_value_register_intersect_func (GST_TYPE_FRACTION_RANGE,
6318       GST_TYPE_FRACTION_RANGE,
6319       gst_value_intersect_fraction_range_fraction_range);
6320
6321   gst_value_register_subtract_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
6322       gst_value_subtract_int_int_range);
6323   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, G_TYPE_INT,
6324       gst_value_subtract_int_range_int);
6325   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
6326       gst_value_subtract_int_range_int_range);
6327   gst_value_register_subtract_func (G_TYPE_INT64, GST_TYPE_INT64_RANGE,
6328       gst_value_subtract_int64_int64_range);
6329   gst_value_register_subtract_func (GST_TYPE_INT64_RANGE, G_TYPE_INT64,
6330       gst_value_subtract_int64_range_int64);
6331   gst_value_register_subtract_func (GST_TYPE_INT64_RANGE, GST_TYPE_INT64_RANGE,
6332       gst_value_subtract_int64_range_int64_range);
6333   gst_value_register_subtract_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
6334       gst_value_subtract_double_double_range);
6335   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_DOUBLE,
6336       gst_value_subtract_double_range_double);
6337   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE,
6338       GST_TYPE_DOUBLE_RANGE, gst_value_subtract_double_range_double_range);
6339   gst_value_register_subtract_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
6340       gst_value_subtract_fraction_fraction_range);
6341   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE, GST_TYPE_FRACTION,
6342       gst_value_subtract_fraction_range_fraction);
6343   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE,
6344       GST_TYPE_FRACTION_RANGE,
6345       gst_value_subtract_fraction_range_fraction_range);
6346
6347   /* see bug #317246, #64994, #65041 */
6348   {
6349     volatile GType date_type = G_TYPE_DATE;
6350
6351     g_type_name (date_type);
6352   }
6353
6354   gst_value_register_union_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
6355       gst_value_union_int_int_range);
6356   gst_value_register_union_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
6357       gst_value_union_int_range_int_range);
6358
6359 #if 0
6360   /* Implement these if needed */
6361   gst_value_register_union_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
6362       gst_value_union_fraction_fraction_range);
6363   gst_value_register_union_func (GST_TYPE_FRACTION_RANGE,
6364       GST_TYPE_FRACTION_RANGE, gst_value_union_fraction_range_fraction_range);
6365 #endif
6366 }