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