Move dataurisrc element from -bad
[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  * subset *
3432  ****************/
3433
3434 static gboolean
3435 gst_value_is_subset_int_range_int_range (const GValue * value1,
3436     const GValue * value2)
3437 {
3438   gint gcd;
3439
3440   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value1), FALSE);
3441   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value2), FALSE);
3442
3443   if (INT_RANGE_MIN (value1) * INT_RANGE_STEP (value1) <
3444       INT_RANGE_MIN (value2) * INT_RANGE_STEP (value2))
3445     return FALSE;
3446   if (INT_RANGE_MAX (value1) * INT_RANGE_STEP (value1) >
3447       INT_RANGE_MAX (value2) * INT_RANGE_STEP (value2))
3448     return FALSE;
3449
3450   if (INT_RANGE_MIN (value2) == INT_RANGE_MAX (value2)) {
3451     if ((INT_RANGE_MIN (value2) * INT_RANGE_STEP (value2)) %
3452         INT_RANGE_STEP (value1))
3453       return FALSE;
3454     return TRUE;
3455   }
3456
3457   gcd =
3458       gst_util_greatest_common_divisor (INT_RANGE_STEP (value1),
3459       INT_RANGE_STEP (value2));
3460   if (gcd != MIN (INT_RANGE_STEP (value1), INT_RANGE_STEP (value2)))
3461     return FALSE;
3462
3463   return TRUE;
3464 }
3465
3466 static gboolean
3467 gst_value_is_subset_int64_range_int64_range (const GValue * value1,
3468     const GValue * value2)
3469 {
3470   gint64 gcd;
3471
3472   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value1), FALSE);
3473   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value2), FALSE);
3474
3475   if (INT64_RANGE_MIN (value1) < INT64_RANGE_MIN (value2))
3476     return FALSE;
3477   if (INT64_RANGE_MAX (value1) > INT64_RANGE_MAX (value2))
3478     return FALSE;
3479
3480   if (INT64_RANGE_MIN (value2) == INT64_RANGE_MAX (value2)) {
3481     if ((INT64_RANGE_MIN (value2) * INT64_RANGE_STEP (value2)) %
3482         INT64_RANGE_STEP (value1))
3483       return FALSE;
3484     return TRUE;
3485   }
3486
3487   gcd =
3488       gst_util_greatest_common_divisor_int64 (INT64_RANGE_STEP (value1),
3489       INT64_RANGE_STEP (value2));
3490   if (gcd != MIN (INT64_RANGE_STEP (value1), INT64_RANGE_STEP (value2)))
3491     return FALSE;
3492
3493   return TRUE;
3494 }
3495
3496 /* A flag set is a subset of another if the superset allows the
3497  * flags of the subset */
3498 static gboolean
3499 gst_value_is_subset_flagset_flagset (const GValue * value1,
3500     const GValue * value2)
3501 {
3502   guint f1, f2;
3503   guint m1, m2;
3504
3505   g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (value1), FALSE);
3506   g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (value2), FALSE);
3507
3508   f1 = value1->data[0].v_uint;
3509   f2 = value2->data[0].v_uint;
3510
3511   m1 = value1->data[1].v_uint;
3512   m2 = value2->data[1].v_uint;
3513
3514   /* Not a subset if masked bits of superset disagree */
3515   if ((f1 & m1) != (f2 & (m1 & m2)))
3516     return FALSE;
3517
3518   return TRUE;
3519 }
3520
3521 /**
3522  * gst_value_is_subset:
3523  * @value1: a #GValue
3524  * @value2: a #GValue
3525  *
3526  * Check that @value1 is a subset of @value2.
3527  *
3528  * Return: %TRUE is @value1 is a subset of @value2
3529  */
3530 gboolean
3531 gst_value_is_subset (const GValue * value1, const GValue * value2)
3532 {
3533   /* special case for int/int64 ranges, since we cannot compute
3534      the difference for those when they have different steps,
3535      and it's actually a lot simpler to compute whether a range
3536      is a subset of another. */
3537   if (GST_VALUE_HOLDS_INT_RANGE (value1) && GST_VALUE_HOLDS_INT_RANGE (value2)) {
3538     return gst_value_is_subset_int_range_int_range (value1, value2);
3539   } else if (GST_VALUE_HOLDS_INT64_RANGE (value1)
3540       && GST_VALUE_HOLDS_INT64_RANGE (value2)) {
3541     return gst_value_is_subset_int64_range_int64_range (value1, value2);
3542   } else if (GST_VALUE_HOLDS_FLAG_SET (value1) &&
3543       GST_VALUE_HOLDS_FLAG_SET (value2)) {
3544     return gst_value_is_subset_flagset_flagset (value1, value2);
3545   }
3546
3547   /*
3548    * 1 - [1,2] = empty
3549    * -> !subset
3550    *
3551    * [1,2] - 1 = 2
3552    *  -> 1 - [1,2] = empty
3553    *  -> subset
3554    *
3555    * [1,3] - [1,2] = 3
3556    * -> [1,2] - [1,3] = empty
3557    * -> subset
3558    *
3559    * {1,2} - {1,3} = 2
3560    * -> {1,3} - {1,2} = 3
3561    * -> !subset
3562    *
3563    *  First caps subtraction needs to return a non-empty set, second
3564    *  subtractions needs to give en empty set.
3565    *  Both substractions are switched below, as it's faster that way.
3566    */
3567   if (!gst_value_subtract (NULL, value1, value2)) {
3568     if (gst_value_subtract (NULL, value2, value1)) {
3569       return TRUE;
3570     }
3571   }
3572   return FALSE;
3573 }
3574
3575 /*********
3576  * union *
3577  *********/
3578
3579 static gboolean
3580 gst_value_union_int_int_range (GValue * dest, const GValue * src1,
3581     const GValue * src2)
3582 {
3583   gint v = src1->data[0].v_int;
3584
3585   /* check if it's already in the range */
3586   if (INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2) <= v &&
3587       INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2) >= v &&
3588       v % INT_RANGE_STEP (src2) == 0) {
3589     if (dest)
3590       gst_value_init_and_copy (dest, src2);
3591     return TRUE;
3592   }
3593
3594   /* check if it extends the range */
3595   if (v == (INT_RANGE_MIN (src2) - 1) * INT_RANGE_STEP (src2)) {
3596     if (dest) {
3597       guint64 new_min =
3598           (guint) ((INT_RANGE_MIN (src2) - 1) * INT_RANGE_STEP (src2));
3599       guint64 new_max = (guint) (INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2));
3600
3601       gst_value_init_and_copy (dest, src2);
3602       dest->data[0].v_uint64 = (new_min << 32) | (new_max);
3603     }
3604     return TRUE;
3605   }
3606   if (v == (INT_RANGE_MAX (src2) + 1) * INT_RANGE_STEP (src2)) {
3607     if (dest) {
3608       guint64 new_min = (guint) (INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2));
3609       guint64 new_max =
3610           (guint) ((INT_RANGE_MAX (src2) + 1) * INT_RANGE_STEP (src2));
3611
3612       gst_value_init_and_copy (dest, src2);
3613       dest->data[0].v_uint64 = (new_min << 32) | (new_max);
3614     }
3615     return TRUE;
3616   }
3617
3618   return FALSE;
3619 }
3620
3621 static gboolean
3622 gst_value_union_int_range_int_range (GValue * dest, const GValue * src1,
3623     const GValue * src2)
3624 {
3625   /* We can union in several special cases:
3626      1 - one is a subset of another
3627      2 - same step and not disjoint
3628      3 - different step, at least one with one value which matches a 'next' or 'previous'
3629      - anything else ?
3630    */
3631
3632   /* 1 - subset */
3633   if (gst_value_is_subset_int_range_int_range (src1, src2)) {
3634     if (dest)
3635       gst_value_init_and_copy (dest, src2);
3636     return TRUE;
3637   }
3638   if (gst_value_is_subset_int_range_int_range (src2, src1)) {
3639     if (dest)
3640       gst_value_init_and_copy (dest, src1);
3641     return TRUE;
3642   }
3643
3644   /* 2 - same step and not disjoint */
3645   if (INT_RANGE_STEP (src1) == INT_RANGE_STEP (src2)) {
3646     if ((INT_RANGE_MIN (src1) <= INT_RANGE_MAX (src2) + 1 &&
3647             INT_RANGE_MAX (src1) >= INT_RANGE_MIN (src2) - 1) ||
3648         (INT_RANGE_MIN (src2) <= INT_RANGE_MAX (src1) + 1 &&
3649             INT_RANGE_MAX (src2) >= INT_RANGE_MIN (src1) - 1)) {
3650       if (dest) {
3651         gint step = INT_RANGE_STEP (src1);
3652         gint min = step * MIN (INT_RANGE_MIN (src1), INT_RANGE_MIN (src2));
3653         gint max = step * MAX (INT_RANGE_MAX (src1), INT_RANGE_MAX (src2));
3654         g_value_init (dest, GST_TYPE_INT_RANGE);
3655         gst_value_set_int_range_step (dest, min, max, step);
3656       }
3657       return TRUE;
3658     }
3659   }
3660
3661   /* 3 - single value matches next or previous */
3662   if (INT_RANGE_STEP (src1) != INT_RANGE_STEP (src2)) {
3663     gint n1 = INT_RANGE_MAX (src1) - INT_RANGE_MIN (src1) + 1;
3664     gint n2 = INT_RANGE_MAX (src2) - INT_RANGE_MIN (src2) + 1;
3665     if (n1 == 1 || n2 == 1) {
3666       const GValue *range_value = NULL;
3667       gint scalar = 0;
3668       if (n1 == 1) {
3669         range_value = src2;
3670         scalar = INT_RANGE_MIN (src1) * INT_RANGE_STEP (src1);
3671       } else if (n2 == 1) {
3672         range_value = src1;
3673         scalar = INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2);
3674       }
3675
3676       if (scalar ==
3677           (INT_RANGE_MIN (range_value) - 1) * INT_RANGE_STEP (range_value)) {
3678         if (dest) {
3679           guint64 new_min = (guint)
3680               ((INT_RANGE_MIN (range_value) -
3681                   1) * INT_RANGE_STEP (range_value));
3682           guint64 new_max = (guint)
3683               (INT_RANGE_MAX (range_value) * INT_RANGE_STEP (range_value));
3684
3685           gst_value_init_and_copy (dest, range_value);
3686           dest->data[0].v_uint64 = (new_min << 32) | (new_max);
3687         }
3688         return TRUE;
3689       } else if (scalar ==
3690           (INT_RANGE_MAX (range_value) + 1) * INT_RANGE_STEP (range_value)) {
3691         if (dest) {
3692           guint64 new_min = (guint)
3693               (INT_RANGE_MIN (range_value) * INT_RANGE_STEP (range_value));
3694           guint64 new_max = (guint)
3695               ((INT_RANGE_MAX (range_value) +
3696                   1) * INT_RANGE_STEP (range_value));
3697           gst_value_init_and_copy (dest, range_value);
3698           dest->data[0].v_uint64 = (new_min << 32) | (new_max);
3699         }
3700         return TRUE;
3701       }
3702     }
3703   }
3704
3705   /* If we get there, we did not find a way to make a union that can be
3706      represented with our simplistic model. */
3707   return FALSE;
3708 }
3709
3710 static gboolean
3711 gst_value_union_flagset_flagset (GValue * dest, const GValue * src1,
3712     const GValue * src2)
3713 {
3714   /* We can union 2 flag sets where they do not disagree on
3715    * required (masked) flag bits */
3716   guint64 f1, f2;
3717   guint64 m1, m2;
3718
3719   g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (src1), FALSE);
3720   g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (src2), FALSE);
3721
3722   f1 = src1->data[0].v_uint;
3723   f2 = src2->data[0].v_uint;
3724
3725   m1 = src1->data[1].v_uint;
3726   m2 = src2->data[1].v_uint;
3727
3728   /* Can't union if masked bits disagree */
3729   if ((f1 & (m1 & m2)) != (f2 & (m1 & m2)))
3730     return FALSE;
3731
3732   if (dest) {
3733     g_value_init (dest, GST_TYPE_FLAG_SET);
3734     /* Copy masked bits from src2 to src1 */
3735     f1 &= ~m2;
3736     f1 |= (f2 & m2);
3737     m1 |= m2;
3738     gst_value_set_flagset (dest, f1, m1);
3739   }
3740
3741   return TRUE;
3742 }
3743
3744 /****************
3745  * intersection *
3746  ****************/
3747
3748 static gboolean
3749 gst_value_intersect_int_int_range (GValue * dest, const GValue * src1,
3750     const GValue * src2)
3751 {
3752   if (INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2) <= src1->data[0].v_int &&
3753       INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2) >= src1->data[0].v_int &&
3754       src1->data[0].v_int % INT_RANGE_STEP (src2) == 0) {
3755     if (dest)
3756       gst_value_init_and_copy (dest, src1);
3757     return TRUE;
3758   }
3759
3760   return FALSE;
3761 }
3762
3763 static gboolean
3764 gst_value_intersect_int_range_int_range (GValue * dest, const GValue * src1,
3765     const GValue * src2)
3766 {
3767   gint min;
3768   gint max;
3769   gint step;
3770
3771   step =
3772       INT_RANGE_STEP (src1) /
3773       gst_util_greatest_common_divisor (INT_RANGE_STEP (src1),
3774       INT_RANGE_STEP (src2));
3775   if (G_MAXINT32 / INT_RANGE_STEP (src2) < step)
3776     return FALSE;
3777   step *= INT_RANGE_STEP (src2);
3778
3779   min =
3780       MAX (INT_RANGE_MIN (src1) * INT_RANGE_STEP (src1),
3781       INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2));
3782   min = (min + step - 1) / step * step;
3783   max =
3784       MIN (INT_RANGE_MAX (src1) * INT_RANGE_STEP (src1),
3785       INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2));
3786   max = max / step * step;
3787
3788   if (min < max) {
3789     if (dest) {
3790       g_value_init (dest, GST_TYPE_INT_RANGE);
3791       gst_value_set_int_range_step (dest, min, max, step);
3792     }
3793     return TRUE;
3794   }
3795   if (min == max) {
3796     if (dest) {
3797       g_value_init (dest, G_TYPE_INT);
3798       g_value_set_int (dest, min);
3799     }
3800     return TRUE;
3801   }
3802
3803   return FALSE;
3804 }
3805
3806 #define INT64_RANGE_MIN_VAL(v) (INT64_RANGE_MIN (v) * INT64_RANGE_STEP (v))
3807 #define INT64_RANGE_MAX_VAL(v) (INT64_RANGE_MAX (v) * INT64_RANGE_STEP (v))
3808
3809 static gboolean
3810 gst_value_intersect_int64_int64_range (GValue * dest, const GValue * src1,
3811     const GValue * src2)
3812 {
3813   if (INT64_RANGE_MIN_VAL (src2) <= src1->data[0].v_int64 &&
3814       INT64_RANGE_MAX_VAL (src2) >= src1->data[0].v_int64 &&
3815       src1->data[0].v_int64 % INT64_RANGE_STEP (src2) == 0) {
3816     if (dest)
3817       gst_value_init_and_copy (dest, src1);
3818     return TRUE;
3819   }
3820
3821   return FALSE;
3822 }
3823
3824 static gboolean
3825 gst_value_intersect_int64_range_int64_range (GValue * dest, const GValue * src1,
3826     const GValue * src2)
3827 {
3828   gint64 min;
3829   gint64 max;
3830   gint64 step;
3831
3832   step =
3833       INT64_RANGE_STEP (src1) /
3834       gst_util_greatest_common_divisor_int64 (INT64_RANGE_STEP (src1),
3835       INT64_RANGE_STEP (src2));
3836   if (G_MAXINT64 / INT64_RANGE_STEP (src2) < step)
3837     return FALSE;
3838   step *= INT64_RANGE_STEP (src2);
3839
3840   min =
3841       MAX (INT64_RANGE_MIN (src1) * INT64_RANGE_STEP (src1),
3842       INT64_RANGE_MIN (src2) * INT64_RANGE_STEP (src2));
3843   min = (min + step - 1) / step * step;
3844   max =
3845       MIN (INT64_RANGE_MAX (src1) * INT64_RANGE_STEP (src1),
3846       INT64_RANGE_MAX (src2) * INT64_RANGE_STEP (src2));
3847   max = max / step * step;
3848
3849   if (min < max) {
3850     if (dest) {
3851       g_value_init (dest, GST_TYPE_INT64_RANGE);
3852       gst_value_set_int64_range_step (dest, min, max, step);
3853     }
3854     return TRUE;
3855   }
3856   if (min == max) {
3857     if (dest) {
3858       g_value_init (dest, G_TYPE_INT64);
3859       g_value_set_int64 (dest, min);
3860     }
3861     return TRUE;
3862   }
3863
3864   return FALSE;
3865 }
3866
3867 static gboolean
3868 gst_value_intersect_double_double_range (GValue * dest, const GValue * src1,
3869     const GValue * src2)
3870 {
3871   if (src2->data[0].v_double <= src1->data[0].v_double &&
3872       src2->data[1].v_double >= src1->data[0].v_double) {
3873     if (dest)
3874       gst_value_init_and_copy (dest, src1);
3875     return TRUE;
3876   }
3877
3878   return FALSE;
3879 }
3880
3881 static gboolean
3882 gst_value_intersect_double_range_double_range (GValue * dest,
3883     const GValue * src1, const GValue * src2)
3884 {
3885   gdouble min;
3886   gdouble max;
3887
3888   min = MAX (src1->data[0].v_double, src2->data[0].v_double);
3889   max = MIN (src1->data[1].v_double, src2->data[1].v_double);
3890
3891   if (min < max) {
3892     if (dest) {
3893       g_value_init (dest, GST_TYPE_DOUBLE_RANGE);
3894       gst_value_set_double_range (dest, min, max);
3895     }
3896     return TRUE;
3897   }
3898   if (min == max) {
3899     if (dest) {
3900       g_value_init (dest, G_TYPE_DOUBLE);
3901       g_value_set_int (dest, (int) min);
3902     }
3903     return TRUE;
3904   }
3905
3906   return FALSE;
3907 }
3908
3909 static gboolean
3910 gst_value_intersect_list (GValue * dest, const GValue * value1,
3911     const GValue * value2)
3912 {
3913   guint i, size;
3914   GValue intersection = { 0, };
3915   gboolean ret = FALSE;
3916
3917   size = VALUE_LIST_SIZE (value1);
3918   for (i = 0; i < size; i++) {
3919     const GValue *cur = VALUE_LIST_GET_VALUE (value1, i);
3920
3921     /* quicker version when we don't need the resulting set */
3922     if (!dest) {
3923       if (gst_value_intersect (NULL, cur, value2)) {
3924         ret = TRUE;
3925         break;
3926       }
3927       continue;
3928     }
3929
3930     if (gst_value_intersect (&intersection, cur, value2)) {
3931       /* append value */
3932       if (!ret) {
3933         gst_value_move (dest, &intersection);
3934         ret = TRUE;
3935       } else if (GST_VALUE_HOLDS_LIST (dest)) {
3936         _gst_value_list_append_and_take_value (dest, &intersection);
3937       } else {
3938         GValue temp;
3939
3940         gst_value_move (&temp, dest);
3941         gst_value_list_merge (dest, &temp, &intersection);
3942         g_value_unset (&temp);
3943         g_value_unset (&intersection);
3944       }
3945     }
3946   }
3947
3948   return ret;
3949 }
3950
3951 static gboolean
3952 gst_value_intersect_array (GValue * dest, const GValue * src1,
3953     const GValue * src2)
3954 {
3955   guint size;
3956   guint n;
3957   GValue val = { 0 };
3958
3959   /* only works on similar-sized arrays */
3960   size = gst_value_array_get_size (src1);
3961   if (size != gst_value_array_get_size (src2))
3962     return FALSE;
3963
3964   /* quicker value when we don't need the resulting set */
3965   if (!dest) {
3966     for (n = 0; n < size; n++) {
3967       if (!gst_value_intersect (NULL, gst_value_array_get_value (src1, n),
3968               gst_value_array_get_value (src2, n))) {
3969         return FALSE;
3970       }
3971     }
3972     return TRUE;
3973   }
3974
3975   g_value_init (dest, GST_TYPE_ARRAY);
3976
3977   for (n = 0; n < size; n++) {
3978     if (!gst_value_intersect (&val, gst_value_array_get_value (src1, n),
3979             gst_value_array_get_value (src2, n))) {
3980       g_value_unset (dest);
3981       return FALSE;
3982     }
3983     _gst_value_array_append_and_take_value (dest, &val);
3984   }
3985
3986   return TRUE;
3987 }
3988
3989 static gboolean
3990 gst_value_intersect_fraction_fraction_range (GValue * dest, const GValue * src1,
3991     const GValue * src2)
3992 {
3993   gint res1, res2;
3994   GValue *vals;
3995   GstValueCompareFunc compare;
3996
3997   vals = src2->data[0].v_pointer;
3998
3999   if (vals == NULL)
4000     return FALSE;
4001
4002   if ((compare = gst_value_get_compare_func (src1))) {
4003     res1 = gst_value_compare_with_func (&vals[0], src1, compare);
4004     res2 = gst_value_compare_with_func (&vals[1], src1, compare);
4005
4006     if ((res1 == GST_VALUE_EQUAL || res1 == GST_VALUE_LESS_THAN) &&
4007         (res2 == GST_VALUE_EQUAL || res2 == GST_VALUE_GREATER_THAN)) {
4008       if (dest)
4009         gst_value_init_and_copy (dest, src1);
4010       return TRUE;
4011     }
4012   }
4013
4014   return FALSE;
4015 }
4016
4017 static gboolean
4018 gst_value_intersect_fraction_range_fraction_range (GValue * dest,
4019     const GValue * src1, const GValue * src2)
4020 {
4021   GValue *min;
4022   GValue *max;
4023   gint res;
4024   GValue *vals1, *vals2;
4025   GstValueCompareFunc compare;
4026
4027   vals1 = src1->data[0].v_pointer;
4028   vals2 = src2->data[0].v_pointer;
4029   g_return_val_if_fail (vals1 != NULL && vals2 != NULL, FALSE);
4030
4031   if ((compare = gst_value_get_compare_func (&vals1[0]))) {
4032     /* min = MAX (src1.start, src2.start) */
4033     res = gst_value_compare_with_func (&vals1[0], &vals2[0], compare);
4034     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
4035     if (res == GST_VALUE_LESS_THAN)
4036       min = &vals2[0];          /* Take the max of the 2 */
4037     else
4038       min = &vals1[0];
4039
4040     /* max = MIN (src1.end, src2.end) */
4041     res = gst_value_compare_with_func (&vals1[1], &vals2[1], compare);
4042     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
4043     if (res == GST_VALUE_GREATER_THAN)
4044       max = &vals2[1];          /* Take the min of the 2 */
4045     else
4046       max = &vals1[1];
4047
4048     res = gst_value_compare_with_func (min, max, compare);
4049     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
4050     if (res == GST_VALUE_LESS_THAN) {
4051       if (dest) {
4052         g_value_init (dest, GST_TYPE_FRACTION_RANGE);
4053         vals1 = dest->data[0].v_pointer;
4054         g_value_copy (min, &vals1[0]);
4055         g_value_copy (max, &vals1[1]);
4056       }
4057       return TRUE;
4058     }
4059     if (res == GST_VALUE_EQUAL) {
4060       if (dest)
4061         gst_value_init_and_copy (dest, min);
4062       return TRUE;
4063     }
4064   }
4065
4066   return FALSE;
4067 }
4068
4069 /* Two flagsets intersect if the masked bits in both
4070  * flagsets are exactly equal */
4071 static gboolean
4072 gst_value_intersect_flagset_flagset (GValue * dest,
4073     const GValue * src1, const GValue * src2)
4074 {
4075   guint f1, f2;
4076   guint m1, m2;
4077   GType type1, type2, flagset_type;
4078
4079   g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (src1), FALSE);
4080   g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (src2), FALSE);
4081
4082   f1 = src1->data[0].v_uint;
4083   f2 = src2->data[0].v_uint;
4084
4085   m1 = src1->data[1].v_uint;
4086   m2 = src2->data[1].v_uint;
4087
4088   /* Don't intersect if masked bits disagree */
4089   if ((f1 & (m1 & m2)) != (f2 & (m1 & m2)))
4090     return FALSE;
4091
4092   /* Allow intersection with the generic FlagSet type, on one
4093    * side, but not 2 different subtypes - that makes no sense */
4094   type1 = G_VALUE_TYPE (src1);
4095   type2 = G_VALUE_TYPE (src2);
4096   flagset_type = GST_TYPE_FLAG_SET;
4097
4098   if (type1 != type2 && type1 != flagset_type && type2 != flagset_type)
4099     return FALSE;
4100
4101   if (dest) {
4102     GType dest_type;
4103
4104     /* Prefer an output type that matches a sub-type,
4105      * rather than the generic type */
4106     if (type1 != flagset_type)
4107       dest_type = type1;
4108     else
4109       dest_type = type2;
4110
4111     g_value_init (dest, dest_type);
4112
4113     /* The compatible set is all the bits from src1 that it
4114      * cares about and all the bits from src2 that it cares
4115      * about. */
4116     dest->data[0].v_uint = (f1 & m1) | (f2 & m2);
4117     dest->data[1].v_uint = m1 | m2;
4118   }
4119
4120   return TRUE;
4121 }
4122
4123 /***************
4124  * subtraction *
4125  ***************/
4126
4127 static gboolean
4128 gst_value_subtract_int_int_range (GValue * dest, const GValue * minuend,
4129     const GValue * subtrahend)
4130 {
4131   gint min = gst_value_get_int_range_min (subtrahend);
4132   gint max = gst_value_get_int_range_max (subtrahend);
4133   gint step = gst_value_get_int_range_step (subtrahend);
4134   gint val = g_value_get_int (minuend);
4135
4136   if (step == 0)
4137     return FALSE;
4138
4139   /* subtracting a range from an int only works if the int is not in the
4140    * range */
4141   if (val < min || val > max || val % step) {
4142     /* and the result is the int */
4143     if (dest)
4144       gst_value_init_and_copy (dest, minuend);
4145     return TRUE;
4146   }
4147   return FALSE;
4148 }
4149
4150 /* creates a new int range based on input values.
4151  */
4152 static gboolean
4153 gst_value_create_new_range (GValue * dest, gint min1, gint max1, gint min2,
4154     gint max2, gint step)
4155 {
4156   GValue v1 = { 0, };
4157   GValue v2 = { 0, };
4158   GValue *pv1, *pv2;            /* yeah, hungarian! */
4159
4160   g_return_val_if_fail (step > 0, FALSE);
4161   g_return_val_if_fail (min1 % step == 0, FALSE);
4162   g_return_val_if_fail (max1 % step == 0, FALSE);
4163   g_return_val_if_fail (min2 % step == 0, FALSE);
4164   g_return_val_if_fail (max2 % step == 0, FALSE);
4165
4166   if (min1 <= max1 && min2 <= max2) {
4167     pv1 = &v1;
4168     pv2 = &v2;
4169   } else if (min1 <= max1) {
4170     pv1 = dest;
4171     pv2 = NULL;
4172   } else if (min2 <= max2) {
4173     pv1 = NULL;
4174     pv2 = dest;
4175   } else {
4176     return FALSE;
4177   }
4178
4179   if (!dest)
4180     return TRUE;
4181
4182   if (min1 < max1) {
4183     g_value_init (pv1, GST_TYPE_INT_RANGE);
4184     gst_value_set_int_range_step (pv1, min1, max1, step);
4185   } else if (min1 == max1) {
4186     g_value_init (pv1, G_TYPE_INT);
4187     g_value_set_int (pv1, min1);
4188   }
4189   if (min2 < max2) {
4190     g_value_init (pv2, GST_TYPE_INT_RANGE);
4191     gst_value_set_int_range_step (pv2, min2, max2, step);
4192   } else if (min2 == max2) {
4193     g_value_init (pv2, G_TYPE_INT);
4194     g_value_set_int (pv2, min2);
4195   }
4196
4197   if (min1 <= max1 && min2 <= max2) {
4198     gst_value_list_concat_and_take_values (dest, pv1, pv2);
4199   }
4200   return TRUE;
4201 }
4202
4203 static gboolean
4204 gst_value_subtract_int_range_int (GValue * dest, const GValue * minuend,
4205     const GValue * subtrahend)
4206 {
4207   gint min = gst_value_get_int_range_min (minuend);
4208   gint max = gst_value_get_int_range_max (minuend);
4209   gint step = gst_value_get_int_range_step (minuend);
4210   gint val = g_value_get_int (subtrahend);
4211
4212   g_return_val_if_fail (min < max, FALSE);
4213
4214   if (step == 0)
4215     return FALSE;
4216
4217   /* value is outside of the range, return range unchanged */
4218   if (val < min || val > max || val % step) {
4219     if (dest)
4220       gst_value_init_and_copy (dest, minuend);
4221     return TRUE;
4222   } else {
4223     /* max must be MAXINT too as val <= max */
4224     if (val >= G_MAXINT - step + 1) {
4225       max -= step;
4226       val -= step;
4227     }
4228     /* min must be MININT too as val >= max */
4229     if (val <= G_MININT + step - 1) {
4230       min += step;
4231       val += step;
4232     }
4233     if (dest)
4234       gst_value_create_new_range (dest, min, val - step, val + step, max, step);
4235   }
4236   return TRUE;
4237 }
4238
4239 static gboolean
4240 gst_value_subtract_int_range_int_range (GValue * dest, const GValue * minuend,
4241     const GValue * subtrahend)
4242 {
4243   gint min1 = gst_value_get_int_range_min (minuend);
4244   gint max1 = gst_value_get_int_range_max (minuend);
4245   gint step1 = gst_value_get_int_range_step (minuend);
4246   gint min2 = gst_value_get_int_range_min (subtrahend);
4247   gint max2 = gst_value_get_int_range_max (subtrahend);
4248   gint step2 = gst_value_get_int_range_step (subtrahend);
4249   gint step;
4250
4251   if (step1 != step2) {
4252     /* ENOIMPL */
4253     g_assert (FALSE);
4254     return FALSE;
4255   }
4256   step = step1;
4257
4258   if (step == 0)
4259     return FALSE;
4260
4261   if (max2 >= max1 && min2 <= min1) {
4262     return FALSE;
4263   } else if (max2 >= max1) {
4264     return gst_value_create_new_range (dest, min1, MIN (min2 - step, max1),
4265         step, 0, step);
4266   } else if (min2 <= min1) {
4267     return gst_value_create_new_range (dest, MAX (max2 + step, min1), max1,
4268         step, 0, step);
4269   } else {
4270     return gst_value_create_new_range (dest, min1, MIN (min2 - step, max1),
4271         MAX (max2 + step, min1), max1, step);
4272   }
4273 }
4274
4275 static gboolean
4276 gst_value_subtract_int64_int64_range (GValue * dest, const GValue * minuend,
4277     const GValue * subtrahend)
4278 {
4279   gint64 min = gst_value_get_int64_range_min (subtrahend);
4280   gint64 max = gst_value_get_int64_range_max (subtrahend);
4281   gint64 step = gst_value_get_int64_range_step (subtrahend);
4282   gint64 val = g_value_get_int64 (minuend);
4283
4284   if (step == 0)
4285     return FALSE;
4286   /* subtracting a range from an int64 only works if the int64 is not in the
4287    * range */
4288   if (val < min || val > max || val % step) {
4289     /* and the result is the int64 */
4290     if (dest)
4291       gst_value_init_and_copy (dest, minuend);
4292     return TRUE;
4293   }
4294   return FALSE;
4295 }
4296
4297 /* creates a new int64 range based on input values.
4298  */
4299 static gboolean
4300 gst_value_create_new_int64_range (GValue * dest, gint64 min1, gint64 max1,
4301     gint64 min2, gint64 max2, gint64 step)
4302 {
4303   GValue v1 = { 0, };
4304   GValue v2 = { 0, };
4305   GValue *pv1, *pv2;            /* yeah, hungarian! */
4306
4307   g_return_val_if_fail (step > 0, FALSE);
4308   g_return_val_if_fail (min1 % step == 0, FALSE);
4309   g_return_val_if_fail (max1 % step == 0, FALSE);
4310   g_return_val_if_fail (min2 % step == 0, FALSE);
4311   g_return_val_if_fail (max2 % step == 0, FALSE);
4312
4313   if (min1 <= max1 && min2 <= max2) {
4314     pv1 = &v1;
4315     pv2 = &v2;
4316   } else if (min1 <= max1) {
4317     pv1 = dest;
4318     pv2 = NULL;
4319   } else if (min2 <= max2) {
4320     pv1 = NULL;
4321     pv2 = dest;
4322   } else {
4323     return FALSE;
4324   }
4325
4326   if (!dest)
4327     return TRUE;
4328
4329   if (min1 < max1) {
4330     g_value_init (pv1, GST_TYPE_INT64_RANGE);
4331     gst_value_set_int64_range_step (pv1, min1, max1, step);
4332   } else if (min1 == max1) {
4333     g_value_init (pv1, G_TYPE_INT64);
4334     g_value_set_int64 (pv1, min1);
4335   }
4336   if (min2 < max2) {
4337     g_value_init (pv2, GST_TYPE_INT64_RANGE);
4338     gst_value_set_int64_range_step (pv2, min2, max2, step);
4339   } else if (min2 == max2) {
4340     g_value_init (pv2, G_TYPE_INT64);
4341     g_value_set_int64 (pv2, min2);
4342   }
4343
4344   if (min1 <= max1 && min2 <= max2) {
4345     gst_value_list_concat_and_take_values (dest, pv1, pv2);
4346   }
4347   return TRUE;
4348 }
4349
4350 static gboolean
4351 gst_value_subtract_int64_range_int64 (GValue * dest, const GValue * minuend,
4352     const GValue * subtrahend)
4353 {
4354   gint64 min = gst_value_get_int64_range_min (minuend);
4355   gint64 max = gst_value_get_int64_range_max (minuend);
4356   gint64 step = gst_value_get_int64_range_step (minuend);
4357   gint64 val = g_value_get_int64 (subtrahend);
4358
4359   g_return_val_if_fail (min < max, FALSE);
4360
4361   if (step == 0)
4362     return FALSE;
4363
4364   /* value is outside of the range, return range unchanged */
4365   if (val < min || val > max || val % step) {
4366     if (dest)
4367       gst_value_init_and_copy (dest, minuend);
4368     return TRUE;
4369   } else {
4370     /* max must be MAXINT64 too as val <= max */
4371     if (val >= G_MAXINT64 - step + 1) {
4372       max -= step;
4373       val -= step;
4374     }
4375     /* min must be MININT64 too as val >= max */
4376     if (val <= G_MININT64 + step - 1) {
4377       min += step;
4378       val += step;
4379     }
4380     if (dest)
4381       gst_value_create_new_int64_range (dest, min, val - step, val + step, max,
4382           step);
4383   }
4384   return TRUE;
4385 }
4386
4387 static gboolean
4388 gst_value_subtract_int64_range_int64_range (GValue * dest,
4389     const GValue * minuend, const GValue * subtrahend)
4390 {
4391   gint64 min1 = gst_value_get_int64_range_min (minuend);
4392   gint64 max1 = gst_value_get_int64_range_max (minuend);
4393   gint64 step1 = gst_value_get_int64_range_step (minuend);
4394   gint64 min2 = gst_value_get_int64_range_min (subtrahend);
4395   gint64 max2 = gst_value_get_int64_range_max (subtrahend);
4396   gint64 step2 = gst_value_get_int64_range_step (subtrahend);
4397   gint64 step;
4398
4399   if (step1 != step2) {
4400     /* ENOIMPL */
4401     g_assert (FALSE);
4402     return FALSE;
4403   }
4404
4405   if (step1 == 0)
4406     return FALSE;
4407
4408   step = step1;
4409
4410   if (max2 >= max1 && min2 <= min1) {
4411     return FALSE;
4412   } else if (max2 >= max1) {
4413     return gst_value_create_new_int64_range (dest, min1, MIN (min2 - step,
4414             max1), step, 0, step);
4415   } else if (min2 <= min1) {
4416     return gst_value_create_new_int64_range (dest, MAX (max2 + step, min1),
4417         max1, step, 0, step);
4418   } else {
4419     return gst_value_create_new_int64_range (dest, min1, MIN (min2 - step,
4420             max1), MAX (max2 + step, min1), max1, step);
4421   }
4422 }
4423
4424 static gboolean
4425 gst_value_subtract_double_double_range (GValue * dest, const GValue * minuend,
4426     const GValue * subtrahend)
4427 {
4428   gdouble min = gst_value_get_double_range_min (subtrahend);
4429   gdouble max = gst_value_get_double_range_max (subtrahend);
4430   gdouble val = g_value_get_double (minuend);
4431
4432   if (val < min || val > max) {
4433     if (dest)
4434       gst_value_init_and_copy (dest, minuend);
4435     return TRUE;
4436   }
4437   return FALSE;
4438 }
4439
4440 static gboolean
4441 gst_value_subtract_double_range_double (GValue * dest, const GValue * minuend,
4442     const GValue * subtrahend)
4443 {
4444   /* since we don't have open ranges, we cannot create a hole in
4445    * a double range. We return the original range */
4446   if (dest)
4447     gst_value_init_and_copy (dest, minuend);
4448   return TRUE;
4449 }
4450
4451 static gboolean
4452 gst_value_subtract_double_range_double_range (GValue * dest,
4453     const GValue * minuend, const GValue * subtrahend)
4454 {
4455   /* since we don't have open ranges, we have to approximate */
4456   /* done like with ints */
4457   gdouble min1 = gst_value_get_double_range_min (minuend);
4458   gdouble max2 = gst_value_get_double_range_max (minuend);
4459   gdouble max1 = MIN (gst_value_get_double_range_min (subtrahend), max2);
4460   gdouble min2 = MAX (gst_value_get_double_range_max (subtrahend), min1);
4461   GValue v1 = { 0, };
4462   GValue v2 = { 0, };
4463   GValue *pv1, *pv2;            /* yeah, hungarian! */
4464
4465   if (min1 < max1 && min2 < max2) {
4466     pv1 = &v1;
4467     pv2 = &v2;
4468   } else if (min1 < max1) {
4469     pv1 = dest;
4470     pv2 = NULL;
4471   } else if (min2 < max2) {
4472     pv1 = NULL;
4473     pv2 = dest;
4474   } else {
4475     return FALSE;
4476   }
4477
4478   if (!dest)
4479     return TRUE;
4480
4481   if (min1 < max1) {
4482     g_value_init (pv1, GST_TYPE_DOUBLE_RANGE);
4483     gst_value_set_double_range (pv1, min1, max1);
4484   }
4485   if (min2 < max2) {
4486     g_value_init (pv2, GST_TYPE_DOUBLE_RANGE);
4487     gst_value_set_double_range (pv2, min2, max2);
4488   }
4489
4490   if (min1 < max1 && min2 < max2) {
4491     gst_value_list_concat_and_take_values (dest, pv1, pv2);
4492   }
4493   return TRUE;
4494 }
4495
4496 static gboolean
4497 gst_value_subtract_from_list (GValue * dest, const GValue * minuend,
4498     const GValue * subtrahend)
4499 {
4500   guint i, size;
4501   GValue subtraction = { 0, };
4502   gboolean ret = FALSE;
4503
4504   size = VALUE_LIST_SIZE (minuend);
4505   for (i = 0; i < size; i++) {
4506     const GValue *cur = VALUE_LIST_GET_VALUE (minuend, i);
4507
4508     /* quicker version when we can discard the result */
4509     if (!dest) {
4510       if (gst_value_subtract (NULL, cur, subtrahend)) {
4511         ret = TRUE;
4512         break;
4513       }
4514       continue;
4515     }
4516
4517     if (gst_value_subtract (&subtraction, cur, subtrahend)) {
4518       if (!ret) {
4519         gst_value_move (dest, &subtraction);
4520         ret = TRUE;
4521       } else if (G_VALUE_TYPE (dest) == GST_TYPE_LIST
4522           && G_VALUE_TYPE (&subtraction) != GST_TYPE_LIST) {
4523         _gst_value_list_append_and_take_value (dest, &subtraction);
4524       } else {
4525         GValue temp;
4526
4527         gst_value_move (&temp, dest);
4528         gst_value_list_concat_and_take_values (dest, &temp, &subtraction);
4529       }
4530     }
4531   }
4532   return ret;
4533 }
4534
4535 static gboolean
4536 gst_value_subtract_list (GValue * dest, const GValue * minuend,
4537     const GValue * subtrahend)
4538 {
4539   guint i, size;
4540   GValue data[2] = { {0,}, {0,} };
4541   GValue *subtraction = &data[0], *result = &data[1];
4542
4543   gst_value_init_and_copy (result, minuend);
4544   size = VALUE_LIST_SIZE (subtrahend);
4545   for (i = 0; i < size; i++) {
4546     const GValue *cur = VALUE_LIST_GET_VALUE (subtrahend, i);
4547
4548     if (gst_value_subtract (subtraction, result, cur)) {
4549       GValue *temp = result;
4550
4551       result = subtraction;
4552       subtraction = temp;
4553       g_value_unset (subtraction);
4554     } else {
4555       g_value_unset (result);
4556       return FALSE;
4557     }
4558   }
4559   if (dest) {
4560     gst_value_move (dest, result);
4561   } else {
4562     g_value_unset (result);
4563   }
4564   return TRUE;
4565 }
4566
4567 static gboolean
4568 gst_value_subtract_fraction_fraction_range (GValue * dest,
4569     const GValue * minuend, const GValue * subtrahend)
4570 {
4571   const GValue *min = gst_value_get_fraction_range_min (subtrahend);
4572   const GValue *max = gst_value_get_fraction_range_max (subtrahend);
4573   GstValueCompareFunc compare;
4574
4575   if ((compare = gst_value_get_compare_func (minuend))) {
4576     /* subtracting a range from an fraction only works if the fraction
4577      * is not in the range */
4578     if (gst_value_compare_with_func (minuend, min, compare) ==
4579         GST_VALUE_LESS_THAN ||
4580         gst_value_compare_with_func (minuend, max, compare) ==
4581         GST_VALUE_GREATER_THAN) {
4582       /* and the result is the value */
4583       if (dest)
4584         gst_value_init_and_copy (dest, minuend);
4585       return TRUE;
4586     }
4587   }
4588   return FALSE;
4589 }
4590
4591 static gboolean
4592 gst_value_subtract_fraction_range_fraction (GValue * dest,
4593     const GValue * minuend, const GValue * subtrahend)
4594 {
4595   /* since we don't have open ranges, we cannot create a hole in
4596    * a range. We return the original range */
4597   if (dest)
4598     gst_value_init_and_copy (dest, minuend);
4599   return TRUE;
4600 }
4601
4602 static gboolean
4603 gst_value_subtract_fraction_range_fraction_range (GValue * dest,
4604     const GValue * minuend, const GValue * subtrahend)
4605 {
4606   /* since we don't have open ranges, we have to approximate */
4607   /* done like with ints and doubles. Creates a list of 2 fraction ranges */
4608   const GValue *min1 = gst_value_get_fraction_range_min (minuend);
4609   const GValue *max2 = gst_value_get_fraction_range_max (minuend);
4610   const GValue *max1 = gst_value_get_fraction_range_min (subtrahend);
4611   const GValue *min2 = gst_value_get_fraction_range_max (subtrahend);
4612   gint cmp1, cmp2;
4613   GValue v1 = { 0, };
4614   GValue v2 = { 0, };
4615   GValue *pv1, *pv2;            /* yeah, hungarian! */
4616   GstValueCompareFunc compare;
4617
4618   g_return_val_if_fail (min1 != NULL && max1 != NULL, FALSE);
4619   g_return_val_if_fail (min2 != NULL && max2 != NULL, FALSE);
4620
4621   compare = gst_value_get_compare_func (min1);
4622   g_return_val_if_fail (compare, FALSE);
4623
4624   cmp1 = gst_value_compare_with_func (max2, max1, compare);
4625   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
4626   if (cmp1 == GST_VALUE_LESS_THAN)
4627     max1 = max2;
4628   cmp1 = gst_value_compare_with_func (min1, min2, compare);
4629   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
4630   if (cmp1 == GST_VALUE_GREATER_THAN)
4631     min2 = min1;
4632
4633   cmp1 = gst_value_compare_with_func (min1, max1, compare);
4634   cmp2 = gst_value_compare_with_func (min2, max2, compare);
4635
4636   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
4637     pv1 = &v1;
4638     pv2 = &v2;
4639   } else if (cmp1 == GST_VALUE_LESS_THAN) {
4640     pv1 = dest;
4641     pv2 = NULL;
4642   } else if (cmp2 == GST_VALUE_LESS_THAN) {
4643     pv1 = NULL;
4644     pv2 = dest;
4645   } else {
4646     return FALSE;
4647   }
4648
4649   if (!dest)
4650     return TRUE;
4651
4652   if (cmp1 == GST_VALUE_LESS_THAN) {
4653     g_value_init (pv1, GST_TYPE_FRACTION_RANGE);
4654     gst_value_set_fraction_range (pv1, min1, max1);
4655   }
4656   if (cmp2 == GST_VALUE_LESS_THAN) {
4657     g_value_init (pv2, GST_TYPE_FRACTION_RANGE);
4658     gst_value_set_fraction_range (pv2, min2, max2);
4659   }
4660
4661   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
4662     gst_value_list_concat_and_take_values (dest, pv1, pv2);
4663   }
4664   return TRUE;
4665 }
4666
4667
4668 /**************
4669  * comparison *
4670  **************/
4671
4672 /*
4673  * gst_value_get_compare_func:
4674  * @value1: a value to get the compare function for
4675  *
4676  * Determines the compare function to be used with values of the same type as
4677  * @value1. The function can be given to gst_value_compare_with_func().
4678  *
4679  * Returns: A #GstValueCompareFunc value
4680  */
4681 static GstValueCompareFunc
4682 gst_value_get_compare_func (const GValue * value1)
4683 {
4684   GstValueTable *table, *best = NULL;
4685   guint i;
4686   GType type1;
4687
4688   type1 = G_VALUE_TYPE (value1);
4689
4690   /* this is a fast check */
4691   best = gst_value_hash_lookup_type (type1);
4692
4693   /* slower checks */
4694   if (G_UNLIKELY (!best || !best->compare)) {
4695     guint len = gst_value_table->len;
4696
4697     best = NULL;
4698     for (i = 0; i < len; i++) {
4699       table = &g_array_index (gst_value_table, GstValueTable, i);
4700       if (table->compare && g_type_is_a (type1, table->type)) {
4701         if (!best || g_type_is_a (table->type, best->type))
4702           best = table;
4703       }
4704     }
4705   }
4706   if (G_LIKELY (best))
4707     return best->compare;
4708
4709   return NULL;
4710 }
4711
4712 static inline gboolean
4713 gst_value_can_compare_unchecked (const GValue * value1, const GValue * value2)
4714 {
4715   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
4716     return FALSE;
4717
4718   return gst_value_get_compare_func (value1) != NULL;
4719 }
4720
4721 /**
4722  * gst_value_can_compare:
4723  * @value1: a value to compare
4724  * @value2: another value to compare
4725  *
4726  * Determines if @value1 and @value2 can be compared.
4727  *
4728  * Returns: %TRUE if the values can be compared
4729  */
4730 gboolean
4731 gst_value_can_compare (const GValue * value1, const GValue * value2)
4732 {
4733   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4734   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4735
4736   return gst_value_can_compare_unchecked (value1, value2);
4737 }
4738
4739 static gboolean
4740 gst_value_list_equals_range (const GValue * list, const GValue * value)
4741 {
4742   const GValue *first;
4743   guint list_size, n;
4744
4745   g_assert (G_IS_VALUE (list));
4746   g_assert (G_IS_VALUE (value));
4747   g_assert (GST_VALUE_HOLDS_LIST (list));
4748
4749   /* TODO: compare against an empty list ? No type though... */
4750   list_size = VALUE_LIST_SIZE (list);
4751   if (list_size == 0)
4752     return FALSE;
4753
4754   /* compare the basic types - they have to match */
4755   first = VALUE_LIST_GET_VALUE (list, 0);
4756 #define CHECK_TYPES(type,prefix) \
4757   (prefix##_VALUE_HOLDS_##type(first) && GST_VALUE_HOLDS_##type##_RANGE (value))
4758   if (CHECK_TYPES (INT, G)) {
4759     const gint rmin = gst_value_get_int_range_min (value);
4760     const gint rmax = gst_value_get_int_range_max (value);
4761     const gint rstep = gst_value_get_int_range_step (value);
4762     if (rstep == 0)
4763       return FALSE;
4764     /* note: this will overflow for min 0 and max INT_MAX, but this
4765        would only be equal to a list of INT_MAX elements, which seems
4766        very unlikely */
4767     if (list_size != rmax / rstep - rmin / rstep + 1)
4768       return FALSE;
4769     for (n = 0; n < list_size; ++n) {
4770       gint v = g_value_get_int (VALUE_LIST_GET_VALUE (list, n));
4771       if (v < rmin || v > rmax || v % rstep) {
4772         return FALSE;
4773       }
4774     }
4775     return TRUE;
4776   } else if (CHECK_TYPES (INT64, G)) {
4777     const gint64 rmin = gst_value_get_int64_range_min (value);
4778     const gint64 rmax = gst_value_get_int64_range_max (value);
4779     const gint64 rstep = gst_value_get_int64_range_step (value);
4780     GST_DEBUG ("List/range of int64s");
4781     if (rstep == 0)
4782       return FALSE;
4783     if (list_size != rmax / rstep - rmin / rstep + 1)
4784       return FALSE;
4785     for (n = 0; n < list_size; ++n) {
4786       gint64 v = g_value_get_int64 (VALUE_LIST_GET_VALUE (list, n));
4787       if (v < rmin || v > rmax || v % rstep)
4788         return FALSE;
4789     }
4790     return TRUE;
4791   }
4792 #undef CHECK_TYPES
4793
4794   /* other combinations don't make sense for equality */
4795   return FALSE;
4796 }
4797
4798 /* "Pure" variant of gst_value_compare which is guaranteed to
4799  * not have list arguments and therefore does basic comparisions
4800  */
4801 static inline gint
4802 _gst_value_compare_nolist (const GValue * value1, const GValue * value2)
4803 {
4804   GstValueCompareFunc compare;
4805
4806   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
4807     return GST_VALUE_UNORDERED;
4808
4809   compare = gst_value_get_compare_func (value1);
4810   if (compare) {
4811     return compare (value1, value2);
4812   }
4813
4814   g_critical ("unable to compare values of type %s\n",
4815       g_type_name (G_VALUE_TYPE (value1)));
4816   return GST_VALUE_UNORDERED;
4817 }
4818
4819 /**
4820  * gst_value_compare:
4821  * @value1: a value to compare
4822  * @value2: another value to compare
4823  *
4824  * Compares @value1 and @value2.  If @value1 and @value2 cannot be
4825  * compared, the function returns GST_VALUE_UNORDERED.  Otherwise,
4826  * if @value1 is greater than @value2, GST_VALUE_GREATER_THAN is returned.
4827  * If @value1 is less than @value2, GST_VALUE_LESS_THAN is returned.
4828  * If the values are equal, GST_VALUE_EQUAL is returned.
4829  *
4830  * Returns: comparison result
4831  */
4832 gint
4833 gst_value_compare (const GValue * value1, const GValue * value2)
4834 {
4835   gboolean value1_is_list;
4836   gboolean value2_is_list;
4837
4838   g_return_val_if_fail (G_IS_VALUE (value1), GST_VALUE_LESS_THAN);
4839   g_return_val_if_fail (G_IS_VALUE (value2), GST_VALUE_GREATER_THAN);
4840
4841   value1_is_list = G_VALUE_TYPE (value1) == GST_TYPE_LIST;
4842   value2_is_list = G_VALUE_TYPE (value2) == GST_TYPE_LIST;
4843
4844   /* Special cases: lists and scalar values ("{ 1 }" and "1" are equal),
4845      as well as lists and ranges ("{ 1, 2 }" and "[ 1, 2 ]" are equal) */
4846   if (value1_is_list && !value2_is_list) {
4847     gint i, n, ret;
4848
4849     if (gst_value_list_equals_range (value1, value2)) {
4850       return GST_VALUE_EQUAL;
4851     }
4852
4853     n = gst_value_list_get_size (value1);
4854     if (n == 0)
4855       return GST_VALUE_UNORDERED;
4856
4857     for (i = 0; i < n; i++) {
4858       const GValue *elt;
4859
4860       elt = gst_value_list_get_value (value1, i);
4861       ret = gst_value_compare (elt, value2);
4862       if (ret != GST_VALUE_EQUAL && n == 1)
4863         return ret;
4864       else if (ret != GST_VALUE_EQUAL)
4865         return GST_VALUE_UNORDERED;
4866     }
4867
4868     return GST_VALUE_EQUAL;
4869   } else if (value2_is_list && !value1_is_list) {
4870     gint i, n, ret;
4871
4872     if (gst_value_list_equals_range (value2, value1)) {
4873       return GST_VALUE_EQUAL;
4874     }
4875
4876     n = gst_value_list_get_size (value2);
4877     if (n == 0)
4878       return GST_VALUE_UNORDERED;
4879
4880     for (i = 0; i < n; i++) {
4881       const GValue *elt;
4882
4883       elt = gst_value_list_get_value (value2, i);
4884       ret = gst_value_compare (elt, value1);
4885       if (ret != GST_VALUE_EQUAL && n == 1)
4886         return ret;
4887       else if (ret != GST_VALUE_EQUAL)
4888         return GST_VALUE_UNORDERED;
4889     }
4890
4891     return GST_VALUE_EQUAL;
4892   }
4893
4894   /* And now handle the generic case */
4895   return _gst_value_compare_nolist (value1, value2);
4896 }
4897
4898 /*
4899  * gst_value_compare_with_func:
4900  * @value1: a value to compare
4901  * @value2: another value to compare
4902  * @compare: compare function
4903  *
4904  * Compares @value1 and @value2 using the @compare function. Works like
4905  * gst_value_compare() but allows to save time determining the compare function
4906  * a multiple times.
4907  *
4908  * Returns: comparison result
4909  */
4910 static gint
4911 gst_value_compare_with_func (const GValue * value1, const GValue * value2,
4912     GstValueCompareFunc compare)
4913 {
4914   g_assert (compare);
4915
4916   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
4917     return GST_VALUE_UNORDERED;
4918
4919   return compare (value1, value2);
4920 }
4921
4922 /* union */
4923
4924 /**
4925  * gst_value_can_union:
4926  * @value1: a value to union
4927  * @value2: another value to union
4928  *
4929  * Determines if @value1 and @value2 can be non-trivially unioned.
4930  * Any two values can be trivially unioned by adding both of them
4931  * to a GstValueList.  However, certain types have the possibility
4932  * to be unioned in a simpler way.  For example, an integer range
4933  * and an integer can be unioned if the integer is a subset of the
4934  * integer range.  If there is the possibility that two values can
4935  * be unioned, this function returns %TRUE.
4936  *
4937  * Returns: %TRUE if there is a function allowing the two values to
4938  * be unioned.
4939  */
4940 gboolean
4941 gst_value_can_union (const GValue * value1, const GValue * value2)
4942 {
4943   GstValueUnionInfo *union_info;
4944   guint i, len;
4945
4946   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4947   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4948
4949   len = gst_value_union_funcs->len;
4950
4951   for (i = 0; i < len; i++) {
4952     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
4953     if (union_info->type1 == G_VALUE_TYPE (value1) &&
4954         union_info->type2 == G_VALUE_TYPE (value2))
4955       return TRUE;
4956     if (union_info->type1 == G_VALUE_TYPE (value2) &&
4957         union_info->type2 == G_VALUE_TYPE (value1))
4958       return TRUE;
4959   }
4960
4961   return FALSE;
4962 }
4963
4964 /**
4965  * gst_value_union:
4966  * @dest: (out caller-allocates): the destination value
4967  * @value1: a value to union
4968  * @value2: another value to union
4969  *
4970  * Creates a GValue corresponding to the union of @value1 and @value2.
4971  *
4972  * Returns: %TRUE if the union succeeded.
4973  */
4974 gboolean
4975 gst_value_union (GValue * dest, const GValue * value1, const GValue * value2)
4976 {
4977   const GstValueUnionInfo *union_info;
4978   guint i, len;
4979   GType type1, type2;
4980
4981   g_return_val_if_fail (dest != NULL, FALSE);
4982   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
4983   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
4984   g_return_val_if_fail (gst_value_list_or_array_are_compatible (value1, value2),
4985       FALSE);
4986
4987   len = gst_value_union_funcs->len;
4988   type1 = G_VALUE_TYPE (value1);
4989   type2 = G_VALUE_TYPE (value2);
4990
4991   for (i = 0; i < len; i++) {
4992     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
4993     if (union_info->type1 == type1 && union_info->type2 == type2) {
4994       return union_info->func (dest, value1, value2);
4995     }
4996     if (union_info->type1 == type2 && union_info->type2 == type1) {
4997       return union_info->func (dest, value2, value1);
4998     }
4999   }
5000
5001   gst_value_list_concat (dest, value1, value2);
5002   return TRUE;
5003 }
5004
5005 /* gst_value_register_union_func: (skip)
5006  * @type1: a type to union
5007  * @type2: another type to union
5008  * @func: a function that implements creating a union between the two types
5009  *
5010  * Registers a union function that can create a union between #GValue items
5011  * of the type @type1 and @type2.
5012  *
5013  * Union functions should be registered at startup before any pipelines are
5014  * started, as gst_value_register_union_func() is not thread-safe and cannot
5015  * be used at the same time as gst_value_union() or gst_value_can_union().
5016  */
5017 static void
5018 gst_value_register_union_func (GType type1, GType type2, GstValueUnionFunc func)
5019 {
5020   GstValueUnionInfo union_info;
5021
5022   union_info.type1 = type1;
5023   union_info.type2 = type2;
5024   union_info.func = func;
5025
5026   g_array_append_val (gst_value_union_funcs, union_info);
5027 }
5028
5029 /* intersection */
5030
5031 /**
5032  * gst_value_can_intersect:
5033  * @value1: a value to intersect
5034  * @value2: another value to intersect
5035  *
5036  * Determines if intersecting two values will produce a valid result.
5037  * Two values will produce a valid intersection if they have the same
5038  * type.
5039  *
5040  * Returns: %TRUE if the values can intersect
5041  */
5042 gboolean
5043 gst_value_can_intersect (const GValue * value1, const GValue * value2)
5044 {
5045   GstValueIntersectInfo *intersect_info;
5046   guint i, len;
5047   GType type1, type2;
5048
5049   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
5050   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
5051
5052   type1 = G_VALUE_TYPE (value1);
5053   type2 = G_VALUE_TYPE (value2);
5054
5055   /* practically all GstValue types have a compare function (_can_compare=TRUE)
5056    * GstStructure and GstCaps have not, but are intersectable */
5057   if (type1 == type2)
5058     return TRUE;
5059
5060   /* special cases */
5061   if (type1 == GST_TYPE_LIST || type2 == GST_TYPE_LIST)
5062     return TRUE;
5063
5064   if (G_UNLIKELY (GST_VALUE_HOLDS_FLAG_SET (value1) &&
5065           GST_VALUE_HOLDS_FLAG_SET (value2))) {
5066     GType type1, type2, flagset_type;
5067
5068     type1 = G_VALUE_TYPE (value1);
5069     type2 = G_VALUE_TYPE (value2);
5070     flagset_type = GST_TYPE_FLAG_SET;
5071
5072     /* Allow intersection with the generic FlagSet type, on one
5073      * side, but not 2 different subtypes - that makes no sense */
5074     if (type1 == type2 || type1 == flagset_type || type2 == flagset_type)
5075       return TRUE;
5076   }
5077
5078   /* check registered intersect functions */
5079   len = gst_value_intersect_funcs->len;
5080   for (i = 0; i < len; i++) {
5081     intersect_info = &g_array_index (gst_value_intersect_funcs,
5082         GstValueIntersectInfo, i);
5083     if ((intersect_info->type1 == type1 && intersect_info->type2 == type2) ||
5084         (intersect_info->type1 == type2 && intersect_info->type2 == type1))
5085       return TRUE;
5086   }
5087
5088   return gst_value_can_compare_unchecked (value1, value2);
5089 }
5090
5091 /**
5092  * gst_value_intersect:
5093  * @dest: (out caller-allocates) (transfer full) (allow-none):
5094  *   a uninitialized #GValue that will hold the calculated
5095  *   intersection value. May be %NULL if the resulting set if not
5096  *   needed.
5097  * @value1: a value to intersect
5098  * @value2: another value to intersect
5099  *
5100  * Calculates the intersection of two values.  If the values have
5101  * a non-empty intersection, the value representing the intersection
5102  * is placed in @dest, unless %NULL.  If the intersection is non-empty,
5103  * @dest is not modified.
5104  *
5105  * Returns: %TRUE if the intersection is non-empty
5106  */
5107 gboolean
5108 gst_value_intersect (GValue * dest, const GValue * value1,
5109     const GValue * value2)
5110 {
5111   GstValueIntersectInfo *intersect_info;
5112   guint i, len;
5113   GType type1, type2;
5114
5115   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
5116   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
5117
5118   type1 = G_VALUE_TYPE (value1);
5119   type2 = G_VALUE_TYPE (value2);
5120
5121   /* special cases first */
5122   if (type1 == GST_TYPE_LIST)
5123     return gst_value_intersect_list (dest, value1, value2);
5124   if (type2 == GST_TYPE_LIST)
5125     return gst_value_intersect_list (dest, value2, value1);
5126
5127   if (_gst_value_compare_nolist (value1, value2) == GST_VALUE_EQUAL) {
5128     if (dest)
5129       gst_value_init_and_copy (dest, value1);
5130     return TRUE;
5131   }
5132
5133   len = gst_value_intersect_funcs->len;
5134   for (i = 0; i < len; i++) {
5135     intersect_info = &g_array_index (gst_value_intersect_funcs,
5136         GstValueIntersectInfo, i);
5137     if (intersect_info->type1 == type1 && intersect_info->type2 == type2) {
5138       return intersect_info->func (dest, value1, value2);
5139     }
5140     if (intersect_info->type1 == type2 && intersect_info->type2 == type1) {
5141       return intersect_info->func (dest, value2, value1);
5142     }
5143   }
5144
5145   /* Failed to find a direct intersection, check if these are
5146    * GstFlagSet sub-types. */
5147   if (G_UNLIKELY (GST_VALUE_HOLDS_FLAG_SET (value1) &&
5148           GST_VALUE_HOLDS_FLAG_SET (value2))) {
5149     return gst_value_intersect_flagset_flagset (dest, value1, value2);
5150   }
5151
5152   return FALSE;
5153 }
5154
5155
5156
5157 /* gst_value_register_intersect_func: (skip)
5158  * @type1: the first type to intersect
5159  * @type2: the second type to intersect
5160  * @func: the intersection function
5161  *
5162  * Registers a function that is called to calculate the intersection
5163  * of the values having the types @type1 and @type2.
5164  *
5165  * Intersect functions should be registered at startup before any pipelines are
5166  * started, as gst_value_register_intersect_func() is not thread-safe and
5167  * cannot be used at the same time as gst_value_intersect() or
5168  * gst_value_can_intersect().
5169  */
5170 static void
5171 gst_value_register_intersect_func (GType type1, GType type2,
5172     GstValueIntersectFunc func)
5173 {
5174   GstValueIntersectInfo intersect_info;
5175
5176   intersect_info.type1 = type1;
5177   intersect_info.type2 = type2;
5178   intersect_info.func = func;
5179
5180   g_array_append_val (gst_value_intersect_funcs, intersect_info);
5181 }
5182
5183
5184 /* subtraction */
5185
5186 /**
5187  * gst_value_subtract:
5188  * @dest: (out caller-allocates) (allow-none): the destination value
5189  *     for the result if the subtraction is not empty. May be %NULL,
5190  *     in which case the resulting set will not be computed, which can
5191  *     give a fair speedup.
5192  * @minuend: the value to subtract from
5193  * @subtrahend: the value to subtract
5194  *
5195  * Subtracts @subtrahend from @minuend and stores the result in @dest.
5196  * Note that this means subtraction as in sets, not as in mathematics.
5197  *
5198  * Returns: %TRUE if the subtraction is not empty
5199  */
5200 gboolean
5201 gst_value_subtract (GValue * dest, const GValue * minuend,
5202     const GValue * subtrahend)
5203 {
5204   GstValueSubtractInfo *info;
5205   guint i, len;
5206   GType mtype, stype;
5207
5208   g_return_val_if_fail (G_IS_VALUE (minuend), FALSE);
5209   g_return_val_if_fail (G_IS_VALUE (subtrahend), FALSE);
5210
5211   mtype = G_VALUE_TYPE (minuend);
5212   stype = G_VALUE_TYPE (subtrahend);
5213
5214   /* special cases first */
5215   if (mtype == GST_TYPE_LIST)
5216     return gst_value_subtract_from_list (dest, minuend, subtrahend);
5217   if (stype == GST_TYPE_LIST)
5218     return gst_value_subtract_list (dest, minuend, subtrahend);
5219
5220   len = gst_value_subtract_funcs->len;
5221   for (i = 0; i < len; i++) {
5222     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
5223     if (info->minuend == mtype && info->subtrahend == stype) {
5224       return info->func (dest, minuend, subtrahend);
5225     }
5226   }
5227
5228   if (_gst_value_compare_nolist (minuend, subtrahend) != GST_VALUE_EQUAL) {
5229     if (dest)
5230       gst_value_init_and_copy (dest, minuend);
5231     return TRUE;
5232   }
5233
5234   return FALSE;
5235 }
5236
5237 #if 0
5238 gboolean
5239 gst_value_subtract (GValue * dest, const GValue * minuend,
5240     const GValue * subtrahend)
5241 {
5242   gboolean ret = gst_value_subtract2 (dest, minuend, subtrahend);
5243
5244   g_printerr ("\"%s\"  -  \"%s\"  =  \"%s\"\n", gst_value_serialize (minuend),
5245       gst_value_serialize (subtrahend),
5246       ret ? gst_value_serialize (dest) : "---");
5247   return ret;
5248 }
5249 #endif
5250
5251 /**
5252  * gst_value_can_subtract:
5253  * @minuend: the value to subtract from
5254  * @subtrahend: the value to subtract
5255  *
5256  * Checks if it's possible to subtract @subtrahend from @minuend.
5257  *
5258  * Returns: %TRUE if a subtraction is possible
5259  */
5260 gboolean
5261 gst_value_can_subtract (const GValue * minuend, const GValue * subtrahend)
5262 {
5263   GstValueSubtractInfo *info;
5264   guint i, len;
5265   GType mtype, stype;
5266
5267   g_return_val_if_fail (G_IS_VALUE (minuend), FALSE);
5268   g_return_val_if_fail (G_IS_VALUE (subtrahend), FALSE);
5269
5270   mtype = G_VALUE_TYPE (minuend);
5271   stype = G_VALUE_TYPE (subtrahend);
5272
5273   /* special cases */
5274   if (mtype == GST_TYPE_LIST || stype == GST_TYPE_LIST)
5275     return TRUE;
5276
5277   len = gst_value_subtract_funcs->len;
5278   for (i = 0; i < len; i++) {
5279     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
5280     if (info->minuend == mtype && info->subtrahend == stype)
5281       return TRUE;
5282   }
5283
5284   return gst_value_can_compare_unchecked (minuend, subtrahend);
5285 }
5286
5287 /* gst_value_register_subtract_func: (skip)
5288  * @minuend_type: type of the minuend
5289  * @subtrahend_type: type of the subtrahend
5290  * @func: function to use
5291  *
5292  * Registers @func as a function capable of subtracting the values of
5293  * @subtrahend_type from values of @minuend_type.
5294  *
5295  * Subtract functions should be registered at startup before any pipelines are
5296  * started, as gst_value_register_subtract_func() is not thread-safe and
5297  * cannot be used at the same time as gst_value_subtract().
5298  */
5299 static void
5300 gst_value_register_subtract_func (GType minuend_type, GType subtrahend_type,
5301     GstValueSubtractFunc func)
5302 {
5303   GstValueSubtractInfo info;
5304
5305   g_return_if_fail (!gst_type_is_fixed (minuend_type)
5306       || !gst_type_is_fixed (subtrahend_type));
5307
5308   info.minuend = minuend_type;
5309   info.subtrahend = subtrahend_type;
5310   info.func = func;
5311
5312   g_array_append_val (gst_value_subtract_funcs, info);
5313 }
5314
5315 /**
5316  * gst_value_register:
5317  * @table: structure containing functions to register
5318  *
5319  * Registers functions to perform calculations on #GValue items of a given
5320  * type. Each type can only be added once.
5321  */
5322 void
5323 gst_value_register (const GstValueTable * table)
5324 {
5325   GstValueTable *found;
5326
5327   g_return_if_fail (table != NULL);
5328
5329   g_array_append_val (gst_value_table, *table);
5330
5331   found = gst_value_hash_lookup_type (table->type);
5332   if (found)
5333     g_warning ("adding type %s multiple times", g_type_name (table->type));
5334
5335   /* FIXME: we're not really doing the const justice, we assume the table is
5336    * static */
5337   gst_value_hash_add_type (table->type, table);
5338 }
5339
5340 /**
5341  * gst_value_init_and_copy:
5342  * @dest: (out caller-allocates): the target value
5343  * @src: the source value
5344  *
5345  * Initialises the target value to be of the same type as source and then copies
5346  * the contents from source to target.
5347  */
5348 void
5349 gst_value_init_and_copy (GValue * dest, const GValue * src)
5350 {
5351   g_return_if_fail (G_IS_VALUE (src));
5352   g_return_if_fail (dest != NULL);
5353
5354   g_value_init (dest, G_VALUE_TYPE (src));
5355   g_value_copy (src, dest);
5356 }
5357
5358 /* move src into dest and clear src */
5359 static void
5360 gst_value_move (GValue * dest, GValue * src)
5361 {
5362   g_assert (G_IS_VALUE (src));
5363   g_assert (dest != NULL);
5364
5365   *dest = *src;
5366   memset (src, 0, sizeof (GValue));
5367 }
5368
5369 /**
5370  * gst_value_serialize:
5371  * @value: a #GValue to serialize
5372  *
5373  * tries to transform the given @value into a string representation that allows
5374  * getting back this string later on using gst_value_deserialize().
5375  *
5376  * Free-function: g_free
5377  *
5378  * Returns: (transfer full) (nullable): the serialization for @value
5379  * or %NULL if none exists
5380  */
5381 gchar *
5382 gst_value_serialize (const GValue * value)
5383 {
5384   guint i, len;
5385   GValue s_val = { 0 };
5386   GstValueTable *table, *best;
5387   gchar *s;
5388   GType type;
5389
5390   g_return_val_if_fail (G_IS_VALUE (value), NULL);
5391
5392   type = G_VALUE_TYPE (value);
5393
5394   best = gst_value_hash_lookup_type (type);
5395
5396   if (G_UNLIKELY (!best || !best->serialize)) {
5397     len = gst_value_table->len;
5398     best = NULL;
5399     for (i = 0; i < len; i++) {
5400       table = &g_array_index (gst_value_table, GstValueTable, i);
5401       if (table->serialize && g_type_is_a (type, table->type)) {
5402         if (!best || g_type_is_a (table->type, best->type))
5403           best = table;
5404       }
5405     }
5406   }
5407   if (G_LIKELY (best))
5408     return best->serialize (value);
5409
5410   g_value_init (&s_val, G_TYPE_STRING);
5411   if (g_value_transform (value, &s_val)) {
5412     s = gst_string_wrap (g_value_get_string (&s_val));
5413   } else {
5414     s = NULL;
5415   }
5416   g_value_unset (&s_val);
5417
5418   return s;
5419 }
5420
5421 /**
5422  * gst_value_deserialize:
5423  * @dest: (out caller-allocates): #GValue to fill with contents of
5424  *     deserialization
5425  * @src: string to deserialize
5426  *
5427  * Tries to deserialize a string into the type specified by the given GValue.
5428  * If the operation succeeds, %TRUE is returned, %FALSE otherwise.
5429  *
5430  * Returns: %TRUE on success
5431  */
5432 gboolean
5433 gst_value_deserialize (GValue * dest, const gchar * src)
5434 {
5435   GstValueTable *table, *best;
5436   guint i, len;
5437   GType type;
5438
5439   g_return_val_if_fail (src != NULL, FALSE);
5440   g_return_val_if_fail (G_IS_VALUE (dest), FALSE);
5441
5442   type = G_VALUE_TYPE (dest);
5443
5444   best = gst_value_hash_lookup_type (type);
5445   if (G_UNLIKELY (!best || !best->deserialize)) {
5446     len = gst_value_table->len;
5447     best = NULL;
5448     for (i = 0; i < len; i++) {
5449       table = &g_array_index (gst_value_table, GstValueTable, i);
5450       if (table->deserialize && g_type_is_a (type, table->type)) {
5451         if (!best || g_type_is_a (table->type, best->type))
5452           best = table;
5453       }
5454     }
5455   }
5456   if (G_LIKELY (best))
5457     return best->deserialize (dest, src);
5458
5459   return FALSE;
5460 }
5461
5462 /**
5463  * gst_value_is_fixed:
5464  * @value: the #GValue to check
5465  *
5466  * Tests if the given GValue, if available in a GstStructure (or any other
5467  * container) contains a "fixed" (which means: one value) or an "unfixed"
5468  * (which means: multiple possible values, such as data lists or data
5469  * ranges) value.
5470  *
5471  * Returns: true if the value is "fixed".
5472  */
5473
5474 gboolean
5475 gst_value_is_fixed (const GValue * value)
5476 {
5477   GType type;
5478
5479   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
5480
5481   type = G_VALUE_TYPE (value);
5482
5483   /* the most common types are just basic plain glib types */
5484   if (type <= G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
5485     return TRUE;
5486   }
5487
5488   if (type == GST_TYPE_ARRAY) {
5489     gint size, n;
5490     const GValue *kid;
5491
5492     /* check recursively */
5493     size = gst_value_array_get_size (value);
5494     for (n = 0; n < size; n++) {
5495       kid = gst_value_array_get_value (value, n);
5496       if (!gst_value_is_fixed (kid))
5497         return FALSE;
5498     }
5499     return TRUE;
5500   } else if (GST_VALUE_HOLDS_FLAG_SET (value)) {
5501     /* Flagsets are only fixed if there are no 'don't care' bits */
5502     return (gst_value_get_flagset_mask (value) == GST_FLAG_SET_MASK_EXACT);
5503   }
5504   return gst_type_is_fixed (type);
5505 }
5506
5507 /**
5508  * gst_value_fixate:
5509  * @dest: the #GValue destination
5510  * @src: the #GValue to fixate
5511  *
5512  * Fixate @src into a new value @dest.
5513  * For ranges, the first element is taken. For lists and arrays, the
5514  * first item is fixated and returned.
5515  * If @src is already fixed, this function returns %FALSE.
5516  *
5517  * Returns: %TRUE if @dest contains a fixated version of @src.
5518  */
5519 gboolean
5520 gst_value_fixate (GValue * dest, const GValue * src)
5521 {
5522   g_return_val_if_fail (G_IS_VALUE (src), FALSE);
5523   g_return_val_if_fail (dest != NULL, FALSE);
5524
5525   if (G_VALUE_TYPE (src) == GST_TYPE_INT_RANGE) {
5526     g_value_init (dest, G_TYPE_INT);
5527     g_value_set_int (dest, gst_value_get_int_range_min (src));
5528   } else if (G_VALUE_TYPE (src) == GST_TYPE_DOUBLE_RANGE) {
5529     g_value_init (dest, G_TYPE_DOUBLE);
5530     g_value_set_double (dest, gst_value_get_double_range_min (src));
5531   } else if (G_VALUE_TYPE (src) == GST_TYPE_FRACTION_RANGE) {
5532     gst_value_init_and_copy (dest, gst_value_get_fraction_range_min (src));
5533   } else if (G_VALUE_TYPE (src) == GST_TYPE_LIST) {
5534     GValue temp = { 0 };
5535
5536     /* list could be empty */
5537     if (gst_value_list_get_size (src) <= 0)
5538       return FALSE;
5539
5540     gst_value_init_and_copy (&temp, gst_value_list_get_value (src, 0));
5541
5542     if (!gst_value_fixate (dest, &temp)) {
5543       gst_value_move (dest, &temp);
5544     } else {
5545       g_value_unset (&temp);
5546     }
5547   } else if (G_VALUE_TYPE (src) == GST_TYPE_ARRAY) {
5548     gboolean res = FALSE;
5549     guint n, len;
5550
5551     len = gst_value_array_get_size (src);
5552     g_value_init (dest, GST_TYPE_ARRAY);
5553     for (n = 0; n < len; n++) {
5554       GValue kid = { 0 };
5555       const GValue *orig_kid = gst_value_array_get_value (src, n);
5556
5557       if (!gst_value_fixate (&kid, orig_kid))
5558         gst_value_init_and_copy (&kid, orig_kid);
5559       else
5560         res = TRUE;
5561       _gst_value_array_append_and_take_value (dest, &kid);
5562     }
5563
5564     if (!res)
5565       g_value_unset (dest);
5566
5567     return res;
5568   } else if (GST_VALUE_HOLDS_FLAG_SET (src)) {
5569     guint flags;
5570
5571     if (gst_value_get_flagset_mask (src) == GST_FLAG_SET_MASK_EXACT)
5572       return FALSE;             /* Already fixed */
5573
5574     flags = gst_value_get_flagset_flags (src);
5575     g_value_init (dest, G_VALUE_TYPE (src));
5576     gst_value_set_flagset (dest, flags, GST_FLAG_SET_MASK_EXACT);
5577     return TRUE;
5578   } else {
5579     return FALSE;
5580   }
5581   return TRUE;
5582 }
5583
5584
5585 /************
5586  * fraction *
5587  ************/
5588
5589 /* helper functions */
5590 static void
5591 gst_value_init_fraction (GValue * value)
5592 {
5593   value->data[0].v_int = 0;
5594   value->data[1].v_int = 1;
5595 }
5596
5597 static void
5598 gst_value_copy_fraction (const GValue * src_value, GValue * dest_value)
5599 {
5600   dest_value->data[0].v_int = src_value->data[0].v_int;
5601   dest_value->data[1].v_int = src_value->data[1].v_int;
5602 }
5603
5604 static gchar *
5605 gst_value_collect_fraction (GValue * value, guint n_collect_values,
5606     GTypeCValue * collect_values, guint collect_flags)
5607 {
5608   if (n_collect_values != 2)
5609     return g_strdup_printf ("not enough value locations for `%s' passed",
5610         G_VALUE_TYPE_NAME (value));
5611   if (collect_values[1].v_int == 0)
5612     return g_strdup_printf ("passed '0' as denominator for `%s'",
5613         G_VALUE_TYPE_NAME (value));
5614   if (collect_values[0].v_int < -G_MAXINT)
5615     return
5616         g_strdup_printf
5617         ("passed value smaller than -G_MAXINT as numerator for `%s'",
5618         G_VALUE_TYPE_NAME (value));
5619   if (collect_values[1].v_int < -G_MAXINT)
5620     return
5621         g_strdup_printf
5622         ("passed value smaller than -G_MAXINT as denominator for `%s'",
5623         G_VALUE_TYPE_NAME (value));
5624
5625   gst_value_set_fraction (value,
5626       collect_values[0].v_int, collect_values[1].v_int);
5627
5628   return NULL;
5629 }
5630
5631 static gchar *
5632 gst_value_lcopy_fraction (const GValue * value, guint n_collect_values,
5633     GTypeCValue * collect_values, guint collect_flags)
5634 {
5635   gint *numerator = collect_values[0].v_pointer;
5636   gint *denominator = collect_values[1].v_pointer;
5637
5638   if (!numerator)
5639     return g_strdup_printf ("numerator for `%s' passed as NULL",
5640         G_VALUE_TYPE_NAME (value));
5641   if (!denominator)
5642     return g_strdup_printf ("denominator for `%s' passed as NULL",
5643         G_VALUE_TYPE_NAME (value));
5644
5645   *numerator = value->data[0].v_int;
5646   *denominator = value->data[1].v_int;
5647
5648   return NULL;
5649 }
5650
5651 /**
5652  * gst_value_set_fraction:
5653  * @value: a GValue initialized to #GST_TYPE_FRACTION
5654  * @numerator: the numerator of the fraction
5655  * @denominator: the denominator of the fraction
5656  *
5657  * Sets @value to the fraction specified by @numerator over @denominator.
5658  * The fraction gets reduced to the smallest numerator and denominator,
5659  * and if necessary the sign is moved to the numerator.
5660  */
5661 void
5662 gst_value_set_fraction (GValue * value, gint numerator, gint denominator)
5663 {
5664   gint gcd = 0;
5665
5666   g_return_if_fail (GST_VALUE_HOLDS_FRACTION (value));
5667   g_return_if_fail (denominator != 0);
5668   g_return_if_fail (denominator >= -G_MAXINT);
5669   g_return_if_fail (numerator >= -G_MAXINT);
5670
5671   /* normalize sign */
5672   if (denominator < 0) {
5673     numerator = -numerator;
5674     denominator = -denominator;
5675   }
5676
5677   /* check for reduction */
5678   gcd = gst_util_greatest_common_divisor (numerator, denominator);
5679   if (gcd) {
5680     numerator /= gcd;
5681     denominator /= gcd;
5682   }
5683
5684   g_assert (denominator > 0);
5685
5686   value->data[0].v_int = numerator;
5687   value->data[1].v_int = denominator;
5688 }
5689
5690 /**
5691  * gst_value_get_fraction_numerator:
5692  * @value: a GValue initialized to #GST_TYPE_FRACTION
5693  *
5694  * Gets the numerator of the fraction specified by @value.
5695  *
5696  * Returns: the numerator of the fraction.
5697  */
5698 gint
5699 gst_value_get_fraction_numerator (const GValue * value)
5700 {
5701   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 0);
5702
5703   return value->data[0].v_int;
5704 }
5705
5706 /**
5707  * gst_value_get_fraction_denominator:
5708  * @value: a GValue initialized to #GST_TYPE_FRACTION
5709  *
5710  * Gets the denominator of the fraction specified by @value.
5711  *
5712  * Returns: the denominator of the fraction.
5713  */
5714 gint
5715 gst_value_get_fraction_denominator (const GValue * value)
5716 {
5717   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 1);
5718
5719   return value->data[1].v_int;
5720 }
5721
5722 /**
5723  * gst_value_fraction_multiply:
5724  * @product: a GValue initialized to #GST_TYPE_FRACTION
5725  * @factor1: a GValue initialized to #GST_TYPE_FRACTION
5726  * @factor2: a GValue initialized to #GST_TYPE_FRACTION
5727  *
5728  * Multiplies the two #GValue items containing a #GST_TYPE_FRACTION and sets
5729  * @product to the product of the two fractions.
5730  *
5731  * Returns: %FALSE in case of an error (like integer overflow), %TRUE otherwise.
5732  */
5733 gboolean
5734 gst_value_fraction_multiply (GValue * product, const GValue * factor1,
5735     const GValue * factor2)
5736 {
5737   gint n1, n2, d1, d2;
5738   gint res_n, res_d;
5739
5740   g_return_val_if_fail (product != NULL, FALSE);
5741   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor1), FALSE);
5742   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor2), FALSE);
5743
5744   n1 = factor1->data[0].v_int;
5745   n2 = factor2->data[0].v_int;
5746   d1 = factor1->data[1].v_int;
5747   d2 = factor2->data[1].v_int;
5748
5749   if (!gst_util_fraction_multiply (n1, d1, n2, d2, &res_n, &res_d))
5750     return FALSE;
5751
5752   gst_value_set_fraction (product, res_n, res_d);
5753
5754   return TRUE;
5755 }
5756
5757 /**
5758  * gst_value_fraction_subtract:
5759  * @dest: a GValue initialized to #GST_TYPE_FRACTION
5760  * @minuend: a GValue initialized to #GST_TYPE_FRACTION
5761  * @subtrahend: a GValue initialized to #GST_TYPE_FRACTION
5762  *
5763  * Subtracts the @subtrahend from the @minuend and sets @dest to the result.
5764  *
5765  * Returns: %FALSE in case of an error (like integer overflow), %TRUE otherwise.
5766  */
5767 gboolean
5768 gst_value_fraction_subtract (GValue * dest,
5769     const GValue * minuend, const GValue * subtrahend)
5770 {
5771   gint n1, n2, d1, d2;
5772   gint res_n, res_d;
5773
5774   g_return_val_if_fail (dest != NULL, FALSE);
5775   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (minuend), FALSE);
5776   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (subtrahend), FALSE);
5777
5778   n1 = minuend->data[0].v_int;
5779   n2 = subtrahend->data[0].v_int;
5780   d1 = minuend->data[1].v_int;
5781   d2 = subtrahend->data[1].v_int;
5782
5783   if (!gst_util_fraction_add (n1, d1, -n2, d2, &res_n, &res_d))
5784     return FALSE;
5785   gst_value_set_fraction (dest, res_n, res_d);
5786
5787   return TRUE;
5788 }
5789
5790 static gchar *
5791 gst_value_serialize_fraction (const GValue * value)
5792 {
5793   gint32 numerator = value->data[0].v_int;
5794   gint32 denominator = value->data[1].v_int;
5795   gboolean positive = TRUE;
5796
5797   /* get the sign and make components absolute */
5798   if (numerator < 0) {
5799     numerator = -numerator;
5800     positive = !positive;
5801   }
5802   if (denominator < 0) {
5803     denominator = -denominator;
5804     positive = !positive;
5805   }
5806
5807   return g_strdup_printf ("%s%d/%d",
5808       positive ? "" : "-", numerator, denominator);
5809 }
5810
5811 static gboolean
5812 gst_value_deserialize_fraction (GValue * dest, const gchar * s)
5813 {
5814   gint num, den;
5815   gint num_chars;
5816
5817   if (G_UNLIKELY (s == NULL))
5818     return FALSE;
5819
5820   if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_FRACTION (dest)))
5821     return FALSE;
5822
5823   if (sscanf (s, "%d/%d%n", &num, &den, &num_chars) >= 2) {
5824     if (s[num_chars] != 0)
5825       return FALSE;
5826     if (den == 0)
5827       return FALSE;
5828
5829     gst_value_set_fraction (dest, num, den);
5830     return TRUE;
5831   } else if (g_ascii_strcasecmp (s, "1/max") == 0) {
5832     gst_value_set_fraction (dest, 1, G_MAXINT);
5833     return TRUE;
5834   } else if (sscanf (s, "%d%n", &num, &num_chars) >= 1) {
5835     if (s[num_chars] != 0)
5836       return FALSE;
5837     gst_value_set_fraction (dest, num, 1);
5838     return TRUE;
5839   } else if (g_ascii_strcasecmp (s, "min") == 0) {
5840     gst_value_set_fraction (dest, -G_MAXINT, 1);
5841     return TRUE;
5842   } else if (g_ascii_strcasecmp (s, "max") == 0) {
5843     gst_value_set_fraction (dest, G_MAXINT, 1);
5844     return TRUE;
5845   }
5846
5847   return FALSE;
5848 }
5849
5850 static void
5851 gst_value_transform_fraction_string (const GValue * src_value,
5852     GValue * dest_value)
5853 {
5854   dest_value->data[0].v_pointer = gst_value_serialize_fraction (src_value);
5855 }
5856
5857 static void
5858 gst_value_transform_string_fraction (const GValue * src_value,
5859     GValue * dest_value)
5860 {
5861   if (!gst_value_deserialize_fraction (dest_value,
5862           src_value->data[0].v_pointer))
5863     /* If the deserialize fails, ensure we leave the fraction in a
5864      * valid, if incorrect, state */
5865     gst_value_set_fraction (dest_value, 0, 1);
5866 }
5867
5868 static void
5869 gst_value_transform_double_fraction (const GValue * src_value,
5870     GValue * dest_value)
5871 {
5872   gdouble src = g_value_get_double (src_value);
5873   gint n, d;
5874
5875   gst_util_double_to_fraction (src, &n, &d);
5876   gst_value_set_fraction (dest_value, n, d);
5877 }
5878
5879 static void
5880 gst_value_transform_float_fraction (const GValue * src_value,
5881     GValue * dest_value)
5882 {
5883   gfloat src = g_value_get_float (src_value);
5884   gint n, d;
5885
5886   gst_util_double_to_fraction (src, &n, &d);
5887   gst_value_set_fraction (dest_value, n, d);
5888 }
5889
5890 static void
5891 gst_value_transform_fraction_double (const GValue * src_value,
5892     GValue * dest_value)
5893 {
5894   dest_value->data[0].v_double = ((double) src_value->data[0].v_int) /
5895       ((double) src_value->data[1].v_int);
5896 }
5897
5898 static void
5899 gst_value_transform_fraction_float (const GValue * src_value,
5900     GValue * dest_value)
5901 {
5902   dest_value->data[0].v_float = ((float) src_value->data[0].v_int) /
5903       ((float) src_value->data[1].v_int);
5904 }
5905
5906 static gint
5907 gst_value_compare_fraction (const GValue * value1, const GValue * value2)
5908 {
5909   gint n1, n2;
5910   gint d1, d2;
5911   gint ret;
5912
5913   n1 = value1->data[0].v_int;
5914   n2 = value2->data[0].v_int;
5915   d1 = value1->data[1].v_int;
5916   d2 = value2->data[1].v_int;
5917
5918   /* fractions are reduced when set, so we can quickly see if they're equal */
5919   if (n1 == n2 && d1 == d2)
5920     return GST_VALUE_EQUAL;
5921
5922   if (d1 == 0 && d2 == 0)
5923     return GST_VALUE_UNORDERED;
5924   else if (d1 == 0)
5925     return GST_VALUE_GREATER_THAN;
5926   else if (d2 == 0)
5927     return GST_VALUE_LESS_THAN;
5928
5929   ret = gst_util_fraction_compare (n1, d1, n2, d2);
5930   if (ret == -1)
5931     return GST_VALUE_LESS_THAN;
5932   else if (ret == 1)
5933     return GST_VALUE_GREATER_THAN;
5934
5935   /* Equality can't happen here because we check for that
5936    * first already */
5937   g_return_val_if_reached (GST_VALUE_UNORDERED);
5938 }
5939
5940 /*********
5941  * GDate *
5942  *********/
5943
5944 static gint
5945 gst_value_compare_date (const GValue * value1, const GValue * value2)
5946 {
5947   const GDate *date1 = (const GDate *) g_value_get_boxed (value1);
5948   const GDate *date2 = (const GDate *) g_value_get_boxed (value2);
5949   guint32 j1, j2;
5950
5951   if (date1 == date2)
5952     return GST_VALUE_EQUAL;
5953
5954   if ((date1 == NULL || !g_date_valid (date1))
5955       && (date2 != NULL && g_date_valid (date2))) {
5956     return GST_VALUE_LESS_THAN;
5957   }
5958
5959   if ((date2 == NULL || !g_date_valid (date2))
5960       && (date1 != NULL && g_date_valid (date1))) {
5961     return GST_VALUE_GREATER_THAN;
5962   }
5963
5964   if (date1 == NULL || date2 == NULL || !g_date_valid (date1)
5965       || !g_date_valid (date2)) {
5966     return GST_VALUE_UNORDERED;
5967   }
5968
5969   j1 = g_date_get_julian (date1);
5970   j2 = g_date_get_julian (date2);
5971
5972   if (j1 == j2)
5973     return GST_VALUE_EQUAL;
5974   else if (j1 < j2)
5975     return GST_VALUE_LESS_THAN;
5976   else
5977     return GST_VALUE_GREATER_THAN;
5978 }
5979
5980 static gchar *
5981 gst_value_serialize_date (const GValue * val)
5982 {
5983   const GDate *date = (const GDate *) g_value_get_boxed (val);
5984
5985   if (date == NULL || !g_date_valid (date))
5986     return g_strdup ("9999-99-99");
5987
5988   return g_strdup_printf ("%04u-%02u-%02u", g_date_get_year (date),
5989       g_date_get_month (date), g_date_get_day (date));
5990 }
5991
5992 static gboolean
5993 gst_value_deserialize_date (GValue * dest, const gchar * s)
5994 {
5995   guint year, month, day;
5996
5997   if (!s || sscanf (s, "%04u-%02u-%02u", &year, &month, &day) != 3)
5998     return FALSE;
5999
6000   if (!g_date_valid_dmy (day, month, year))
6001     return FALSE;
6002
6003   g_value_take_boxed (dest, g_date_new_dmy (day, month, year));
6004   return TRUE;
6005 }
6006
6007 /*************
6008  * GstDateTime *
6009  *************/
6010
6011 static gint
6012 gst_value_compare_date_time (const GValue * value1, const GValue * value2)
6013 {
6014   const GstDateTime *date1 = (const GstDateTime *) g_value_get_boxed (value1);
6015   const GstDateTime *date2 = (const GstDateTime *) g_value_get_boxed (value2);
6016
6017   if (date1 == date2)
6018     return GST_VALUE_EQUAL;
6019
6020   if ((date1 == NULL) && (date2 != NULL)) {
6021     return GST_VALUE_LESS_THAN;
6022   }
6023   if ((date2 == NULL) && (date1 != NULL)) {
6024     return GST_VALUE_LESS_THAN;
6025   }
6026
6027   /* returns GST_VALUE_* */
6028   return __gst_date_time_compare (date1, date2);
6029 }
6030
6031 static gchar *
6032 gst_value_serialize_date_time (const GValue * val)
6033 {
6034   GstDateTime *date = (GstDateTime *) g_value_get_boxed (val);
6035
6036   if (date == NULL)
6037     return g_strdup ("null");
6038
6039   return __gst_date_time_serialize (date, TRUE);
6040 }
6041
6042 static gboolean
6043 gst_value_deserialize_date_time (GValue * dest, const gchar * s)
6044 {
6045   GstDateTime *datetime;
6046
6047   if (!s || strcmp (s, "null") == 0) {
6048     return FALSE;
6049   }
6050
6051   datetime = gst_date_time_new_from_iso8601_string (s);
6052   if (datetime != NULL) {
6053     g_value_take_boxed (dest, datetime);
6054     return TRUE;
6055   }
6056   GST_WARNING ("Failed to deserialize date time string '%s'", s);
6057   return FALSE;
6058 }
6059
6060 static void
6061 gst_value_transform_date_string (const GValue * src_value, GValue * dest_value)
6062 {
6063   dest_value->data[0].v_pointer = gst_value_serialize_date (src_value);
6064 }
6065
6066 static void
6067 gst_value_transform_string_date (const GValue * src_value, GValue * dest_value)
6068 {
6069   gst_value_deserialize_date (dest_value, src_value->data[0].v_pointer);
6070 }
6071
6072
6073 /************
6074  * bitmask *
6075  ************/
6076
6077 /* helper functions */
6078 static void
6079 gst_value_init_bitmask (GValue * value)
6080 {
6081   value->data[0].v_uint64 = 0;
6082 }
6083
6084 static void
6085 gst_value_copy_bitmask (const GValue * src_value, GValue * dest_value)
6086 {
6087   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
6088 }
6089
6090 static gchar *
6091 gst_value_collect_bitmask (GValue * value, guint n_collect_values,
6092     GTypeCValue * collect_values, guint collect_flags)
6093 {
6094   if (n_collect_values != 1)
6095     return g_strdup_printf ("not enough value locations for `%s' passed",
6096         G_VALUE_TYPE_NAME (value));
6097
6098   gst_value_set_bitmask (value, (guint64) collect_values[0].v_int64);
6099
6100   return NULL;
6101 }
6102
6103 static gchar *
6104 gst_value_lcopy_bitmask (const GValue * value, guint n_collect_values,
6105     GTypeCValue * collect_values, guint collect_flags)
6106 {
6107   guint64 *bitmask = collect_values[0].v_pointer;
6108
6109   if (!bitmask)
6110     return g_strdup_printf ("value for `%s' passed as NULL",
6111         G_VALUE_TYPE_NAME (value));
6112
6113   *bitmask = value->data[0].v_uint64;
6114
6115   return NULL;
6116 }
6117
6118 /**
6119  * gst_value_set_bitmask:
6120  * @value: a GValue initialized to #GST_TYPE_BITMASK
6121  * @bitmask: the bitmask
6122  *
6123  * Sets @value to the bitmask specified by @bitmask.
6124  */
6125 void
6126 gst_value_set_bitmask (GValue * value, guint64 bitmask)
6127 {
6128   g_return_if_fail (GST_VALUE_HOLDS_BITMASK (value));
6129
6130   value->data[0].v_uint64 = bitmask;
6131 }
6132
6133 /**
6134  * gst_value_get_bitmask:
6135  * @value: a GValue initialized to #GST_TYPE_BITMASK
6136  *
6137  * Gets the bitmask specified by @value.
6138  *
6139  * Returns: the bitmask.
6140  */
6141 guint64
6142 gst_value_get_bitmask (const GValue * value)
6143 {
6144   g_return_val_if_fail (GST_VALUE_HOLDS_BITMASK (value), 0);
6145
6146   return value->data[0].v_uint64;
6147 }
6148
6149 static gchar *
6150 gst_value_serialize_bitmask (const GValue * value)
6151 {
6152   guint64 bitmask = value->data[0].v_uint64;
6153
6154   return g_strdup_printf ("0x%016" G_GINT64_MODIFIER "x", bitmask);
6155 }
6156
6157 static gboolean
6158 gst_value_deserialize_bitmask (GValue * dest, const gchar * s)
6159 {
6160   gchar *endptr = NULL;
6161   guint64 val;
6162
6163   if (G_UNLIKELY (s == NULL))
6164     return FALSE;
6165
6166   if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_BITMASK (dest)))
6167     return FALSE;
6168
6169   errno = 0;
6170   val = g_ascii_strtoull (s, &endptr, 16);
6171   if (val == G_MAXUINT64 && (errno == ERANGE || errno == EINVAL))
6172     return FALSE;
6173   if (val == 0 && endptr == s)
6174     return FALSE;
6175
6176   gst_value_set_bitmask (dest, val);
6177
6178   return TRUE;
6179 }
6180
6181 static void
6182 gst_value_transform_bitmask_string (const GValue * src_value,
6183     GValue * dest_value)
6184 {
6185   dest_value->data[0].v_pointer = gst_value_serialize_bitmask (src_value);
6186 }
6187
6188 static void
6189 gst_value_transform_string_bitmask (const GValue * src_value,
6190     GValue * dest_value)
6191 {
6192   if (!gst_value_deserialize_bitmask (dest_value, src_value->data[0].v_pointer))
6193     gst_value_set_bitmask (dest_value, 0);
6194 }
6195
6196 static void
6197 gst_value_transform_uint64_bitmask (const GValue * src_value,
6198     GValue * dest_value)
6199 {
6200   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
6201 }
6202
6203 static void
6204 gst_value_transform_bitmask_uint64 (const GValue * src_value,
6205     GValue * dest_value)
6206 {
6207   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
6208 }
6209
6210 static gint
6211 gst_value_compare_bitmask (const GValue * value1, const GValue * value2)
6212 {
6213   guint64 v1, v2;
6214
6215   v1 = value1->data[0].v_uint64;
6216   v2 = value2->data[0].v_uint64;
6217
6218   if (v1 == v2)
6219     return GST_VALUE_EQUAL;
6220
6221   return GST_VALUE_UNORDERED;
6222 }
6223
6224 /************
6225  * flagset *
6226  ************/
6227
6228 /* helper functions */
6229 static void
6230 gst_value_init_flagset (GValue * value)
6231 {
6232   value->data[0].v_uint = 0;
6233   value->data[1].v_uint = 0;
6234 }
6235
6236 static void
6237 gst_value_copy_flagset (const GValue * src_value, GValue * dest_value)
6238 {
6239   dest_value->data[0].v_uint = src_value->data[0].v_uint;
6240   dest_value->data[1].v_uint = src_value->data[1].v_uint;
6241 }
6242
6243 static gchar *
6244 gst_value_collect_flagset (GValue * value, guint n_collect_values,
6245     GTypeCValue * collect_values, guint collect_flags)
6246 {
6247   if (n_collect_values != 2)
6248     return g_strdup_printf ("not enough value locations for `%s' passed",
6249         G_VALUE_TYPE_NAME (value));
6250
6251   gst_value_set_flagset (value,
6252       (guint) collect_values[0].v_int, (guint) collect_values[1].v_int);
6253
6254   return NULL;
6255 }
6256
6257 static gchar *
6258 gst_value_lcopy_flagset (const GValue * value, guint n_collect_values,
6259     GTypeCValue * collect_values, guint collect_flags)
6260 {
6261   guint *flags = collect_values[0].v_pointer;
6262   guint *mask = collect_values[1].v_pointer;
6263
6264   *flags = value->data[0].v_uint;
6265   *mask = value->data[1].v_uint;
6266
6267   return NULL;
6268 }
6269
6270 /**
6271  * gst_value_set_flagset:
6272  * @value: a GValue initialized to %GST_TYPE_FLAG_SET
6273  * @flags: The value of the flags set or unset
6274  * @mask: The mask indicate which flags bits must match for comparisons
6275  *
6276  * Sets @value to the flags and mask values provided in @flags and @mask.
6277  * The @flags value indicates the values of flags, the @mask represents
6278  * which bits in the flag value have been set, and which are "don't care"
6279  *
6280  * Since: 1.6
6281  */
6282 void
6283 gst_value_set_flagset (GValue * value, guint flags, guint mask)
6284 {
6285   g_return_if_fail (GST_VALUE_HOLDS_FLAG_SET (value));
6286
6287   /* Normalise and only keep flags mentioned in the mask */
6288   value->data[0].v_uint = flags & mask;
6289   value->data[1].v_uint = mask;
6290 }
6291
6292 /**
6293  * gst_value_get_flagset_flags:
6294  * @value: a GValue initialized to #GST_TYPE_FLAG_SET
6295  *
6296  * Retrieve the flags field of a GstFlagSet @value.
6297  *
6298  * Returns: the flags field of the flagset instance.
6299  *
6300  * Since: 1.6
6301  */
6302 guint
6303 gst_value_get_flagset_flags (const GValue * value)
6304 {
6305   g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (value), 0);
6306
6307   return value->data[0].v_uint;
6308 }
6309
6310 /**
6311  * gst_value_get_flagset_mask:
6312  * @value: a GValue initialized to #GST_TYPE_FLAG_SET
6313  *
6314  * Retrieve the mask field of a GstFlagSet @value.
6315  *
6316  * Returns: the mask field of the flagset instance.
6317  *
6318  * Since: 1.6
6319  */
6320 guint
6321 gst_value_get_flagset_mask (const GValue * value)
6322 {
6323   g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (value), 1);
6324
6325   return value->data[1].v_uint;
6326 }
6327
6328 static gchar *
6329 gst_value_serialize_flagset (const GValue * value)
6330 {
6331   guint flags = value->data[0].v_uint;
6332   guint mask = value->data[1].v_uint;
6333   GstFlagSetClass *set_klass =
6334       (GstFlagSetClass *) g_type_class_ref (G_VALUE_TYPE (value));
6335   gchar *result;
6336
6337   result = g_strdup_printf ("%x:%x", flags, mask);
6338
6339   /* If this flag set class has an associated GFlags GType, and some
6340    * bits in the mask, serialize the bits in human-readable form to
6341    * aid debugging */
6342   if (mask && set_klass->flags_type) {
6343     GFlagsClass *flags_klass =
6344         (GFlagsClass *) (g_type_class_ref (set_klass->flags_type));
6345     GFlagsValue *fl;
6346     gchar *tmp;
6347     gboolean first = TRUE;
6348
6349     g_return_val_if_fail (flags_klass, NULL);
6350
6351     /* some bits in the mask are set, so serialize one by one, according
6352      * to whether that bit is set or cleared in the flags value */
6353     while (mask) {
6354       fl = g_flags_get_first_value (flags_klass, mask);
6355       if (fl == NULL) {
6356         /* No more bits match in the flags mask - time to stop */
6357         mask = 0;
6358         break;
6359       }
6360
6361       tmp = g_strconcat (result,
6362           first ? ":" : "",
6363           (flags & fl->value) ? "+" : "/", fl->value_nick, NULL);
6364       g_free (result);
6365       result = tmp;
6366       first = FALSE;
6367
6368       /* clear flag */
6369       mask &= ~fl->value;
6370     }
6371     g_type_class_unref (flags_klass);
6372
6373   }
6374   g_type_class_unref (set_klass);
6375
6376   return result;
6377 }
6378
6379 static gboolean
6380 gst_value_deserialize_flagset (GValue * dest, const gchar * s)
6381 {
6382   gboolean res = FALSE;
6383   guint flags, mask;
6384   gchar *cur, *next;
6385
6386   if (G_UNLIKELY (s == NULL))
6387     return FALSE;
6388
6389   if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_FLAG_SET (dest)))
6390     return FALSE;
6391
6392   /* Flagset strings look like %x:%x - hex flags : hex bitmask,
6393    * 32-bit each, or like a concatenated list of flag nicks,
6394    * with either '+' or '/' in front. The first form
6395    * may optionally be followed by ':' and a set of text flag descriptions
6396    * for easier debugging */
6397
6398   /* Try and interpret as hex form first, as it's the most efficient */
6399   /* Read the flags first */
6400   flags = strtoul (s, &next, 16);
6401   if (G_UNLIKELY ((flags == 0 && errno == EINVAL) || s == next))
6402     goto try_as_flags_string;
6403   /* Next char should be a colon */
6404   if (next[0] == ':')
6405     next++;
6406
6407   /* Read the mask */
6408   cur = next;
6409   mask = strtoul (cur, &next, 16);
6410   if (G_UNLIKELY ((mask == 0 && errno == EINVAL) || cur == next))
6411     goto try_as_flags_string;
6412
6413   /* Next char should be NULL terminator, or a ':' */
6414   if (G_UNLIKELY (next[0] != 0 && next[0] != ':'))
6415     goto try_as_flags_string;
6416
6417   res = TRUE;
6418
6419 try_as_flags_string:
6420
6421   if (!res) {
6422     const gchar *set_class = g_type_name (G_VALUE_TYPE (dest));
6423     GFlagsClass *flags_klass = NULL;
6424     const gchar *end;
6425
6426     if (g_str_equal (set_class, "GstFlagSet"))
6427       goto done;                /* There's no hope to parse a generic flag set */
6428
6429     /* Flags class is the FlagSet class with 'Set' removed from the end */
6430     end = g_strrstr (set_class, "Set");
6431
6432     if (end != NULL) {
6433       gchar *class_name = g_strndup (set_class, end - set_class);
6434       GType flags_type = g_type_from_name (class_name);
6435       if (flags_type == 0) {
6436         GST_TRACE ("Looking for dynamic type %s", class_name);
6437         gst_dynamic_type_factory_load (class_name);
6438       }
6439
6440       if (flags_type != 0) {
6441         flags_klass = g_type_class_ref (flags_type);
6442         GST_TRACE ("Going to parse %s as %s", s, class_name);
6443       }
6444       g_free (class_name);
6445     }
6446
6447     if (flags_klass) {
6448       res = gst_value_gflags_str_to_flags (flags_klass, s, &flags, &mask);
6449       g_type_class_unref (flags_klass);
6450     }
6451   }
6452
6453   if (res)
6454     gst_value_set_flagset (dest, flags, mask);
6455 done:
6456   return res;
6457
6458 }
6459
6460 static void
6461 gst_value_transform_flagset_string (const GValue * src_value,
6462     GValue * dest_value)
6463 {
6464   dest_value->data[0].v_pointer = gst_value_serialize_flagset (src_value);
6465 }
6466
6467 static void
6468 gst_value_transform_string_flagset (const GValue * src_value,
6469     GValue * dest_value)
6470 {
6471   if (!gst_value_deserialize_flagset (dest_value, src_value->data[0].v_pointer)) {
6472     /* If the deserialize fails, ensure we leave the flags in a
6473      * valid, if incorrect, state */
6474     gst_value_set_flagset (dest_value, 0, 0);
6475   }
6476 }
6477
6478 static gint
6479 gst_value_compare_flagset (const GValue * value1, const GValue * value2)
6480 {
6481   guint v1, v2;
6482   guint m1, m2;
6483
6484   v1 = value1->data[0].v_uint;
6485   v2 = value2->data[0].v_uint;
6486
6487   m1 = value1->data[1].v_uint;
6488   m2 = value2->data[1].v_uint;
6489
6490   if (v1 == v2 && m1 == m2)
6491     return GST_VALUE_EQUAL;
6492
6493   return GST_VALUE_UNORDERED;
6494 }
6495
6496 /***********************
6497  * GstAllocationParams *
6498  ***********************/
6499 static gint
6500 gst_value_compare_allocation_params (const GValue * value1,
6501     const GValue * value2)
6502 {
6503   GstAllocationParams *v1, *v2;
6504
6505   v1 = value1->data[0].v_pointer;
6506   v2 = value2->data[0].v_pointer;
6507
6508   if (v1 == NULL && v1 == v2)
6509     return GST_VALUE_EQUAL;
6510
6511   if (v1 == NULL || v2 == NULL)
6512     return GST_VALUE_UNORDERED;
6513
6514   if (v1->flags == v2->flags && v1->align == v2->align &&
6515       v1->prefix == v2->prefix && v1->padding == v2->padding)
6516     return GST_VALUE_EQUAL;
6517
6518   return GST_VALUE_UNORDERED;
6519 }
6520
6521
6522 /************
6523  * GObject *
6524  ************/
6525
6526 static gint
6527 gst_value_compare_object (const GValue * value1, const GValue * value2)
6528 {
6529   gpointer v1, v2;
6530
6531   v1 = value1->data[0].v_pointer;
6532   v2 = value2->data[0].v_pointer;
6533
6534   if (v1 == v2)
6535     return GST_VALUE_EQUAL;
6536
6537   return GST_VALUE_UNORDERED;
6538 }
6539
6540 static void
6541 gst_value_transform_object_string (const GValue * src_value,
6542     GValue * dest_value)
6543 {
6544   GstObject *obj;
6545   gchar *str;
6546
6547   obj = g_value_get_object (src_value);
6548   if (obj) {
6549     str =
6550         g_strdup_printf ("(%s) %s", G_OBJECT_TYPE_NAME (obj),
6551         GST_OBJECT_NAME (obj));
6552   } else {
6553     str = g_strdup ("NULL");
6554   }
6555
6556   dest_value->data[0].v_pointer = str;
6557 }
6558
6559 static GTypeInfo _info = {
6560   0, NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, NULL,
6561 };
6562
6563 static GTypeFundamentalInfo _finfo = {
6564   0
6565 };
6566
6567 #define FUNC_VALUE_GET_TYPE_CLASSED(type, name, csize, flags)   \
6568 GType _gst_ ## type ## _type = 0;                               \
6569                                                                 \
6570 GType gst_ ## type ## _get_type (void)                          \
6571 {                                                               \
6572   static volatile GType gst_ ## type ## _type = 0;              \
6573                                                                 \
6574   if (g_once_init_enter (&gst_ ## type ## _type)) {             \
6575     GType _type;                                                \
6576     _info.class_size = csize;                                   \
6577     _finfo.type_flags = flags;                                  \
6578     _info.value_table = & _gst_ ## type ## _value_table;        \
6579     _type = g_type_register_fundamental (                       \
6580         g_type_fundamental_next (),                             \
6581         name, &_info, &_finfo, 0);                              \
6582     _gst_ ## type ## _type = _type;                             \
6583     g_once_init_leave(&gst_ ## type ## _type, _type);           \
6584   }                                                             \
6585                                                                 \
6586   return gst_ ## type ## _type;                                 \
6587 }
6588
6589 #define FUNC_VALUE_GET_TYPE(type, name) \
6590   FUNC_VALUE_GET_TYPE_CLASSED(type, name, 0, 0)
6591
6592 static const GTypeValueTable _gst_int_range_value_table = {
6593   gst_value_init_int_range,
6594   NULL,
6595   gst_value_copy_int_range,
6596   NULL,
6597   (char *) "ii",
6598   gst_value_collect_int_range, (char *) "pp", gst_value_lcopy_int_range
6599 };
6600
6601 FUNC_VALUE_GET_TYPE (int_range, "GstIntRange");
6602
6603 static const GTypeValueTable _gst_int64_range_value_table = {
6604   gst_value_init_int64_range,
6605   gst_value_free_int64_range,
6606   gst_value_copy_int64_range,
6607   NULL,
6608   (char *) "qq",
6609   gst_value_collect_int64_range,
6610   (char *) "pp", gst_value_lcopy_int64_range
6611 };
6612
6613 FUNC_VALUE_GET_TYPE (int64_range, "GstInt64Range");
6614
6615 static const GTypeValueTable _gst_double_range_value_table = {
6616   gst_value_init_double_range,
6617   NULL,
6618   gst_value_copy_double_range,
6619   NULL,
6620   (char *) "dd",
6621   gst_value_collect_double_range,
6622   (char *) "pp", gst_value_lcopy_double_range
6623 };
6624
6625 FUNC_VALUE_GET_TYPE (double_range, "GstDoubleRange");
6626
6627 static const GTypeValueTable _gst_fraction_range_value_table = {
6628   gst_value_init_fraction_range,
6629   gst_value_free_fraction_range,
6630   gst_value_copy_fraction_range,
6631   NULL,
6632   (char *) "iiii",
6633   gst_value_collect_fraction_range,
6634   (char *) "pppp", gst_value_lcopy_fraction_range
6635 };
6636
6637 FUNC_VALUE_GET_TYPE (fraction_range, "GstFractionRange");
6638
6639 static const GTypeValueTable _gst_value_list_value_table = {
6640   gst_value_init_list_or_array,
6641   gst_value_free_list_or_array,
6642   gst_value_copy_list_or_array,
6643   gst_value_list_or_array_peek_pointer,
6644   (char *) "p",
6645   gst_value_collect_list_or_array,
6646   (char *) "p", gst_value_lcopy_list_or_array
6647 };
6648
6649 FUNC_VALUE_GET_TYPE (value_list, "GstValueList");
6650
6651 static const GTypeValueTable _gst_value_array_value_table = {
6652   gst_value_init_list_or_array,
6653   gst_value_free_list_or_array,
6654   gst_value_copy_list_or_array,
6655   gst_value_list_or_array_peek_pointer,
6656   (char *) "p",
6657   gst_value_collect_list_or_array,
6658   (char *) "p", gst_value_lcopy_list_or_array
6659 };
6660
6661 FUNC_VALUE_GET_TYPE (value_array, "GstValueArray");
6662
6663 static const GTypeValueTable _gst_fraction_value_table = {
6664   gst_value_init_fraction,
6665   NULL,
6666   gst_value_copy_fraction,
6667   NULL,
6668   (char *) "ii",
6669   gst_value_collect_fraction, (char *) "pp", gst_value_lcopy_fraction
6670 };
6671
6672 FUNC_VALUE_GET_TYPE (fraction, "GstFraction");
6673
6674 static const GTypeValueTable _gst_bitmask_value_table = {
6675   gst_value_init_bitmask,
6676   NULL,
6677   gst_value_copy_bitmask,
6678   NULL,
6679   (char *) "q",
6680   gst_value_collect_bitmask, (char *) "p", gst_value_lcopy_bitmask
6681 };
6682
6683 FUNC_VALUE_GET_TYPE (bitmask, "GstBitmask");
6684
6685 static const GTypeValueTable _gst_flagset_value_table = {
6686   gst_value_init_flagset,
6687   NULL,
6688   gst_value_copy_flagset,
6689   NULL,
6690   (char *) "ii",
6691   gst_value_collect_flagset, (char *) "pp", gst_value_lcopy_flagset
6692 };
6693
6694 FUNC_VALUE_GET_TYPE_CLASSED (flagset, "GstFlagSet",
6695     sizeof (GstFlagSetClass), G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_DERIVABLE);
6696
6697 GType
6698 gst_g_thread_get_type (void)
6699 {
6700   return G_TYPE_THREAD;
6701 }
6702
6703 #define SERIAL_VTABLE(t,c,s,d) { t, c, s, d }
6704
6705 #define REGISTER_SERIALIZATION_CONST(_gtype, _type)                     \
6706 G_STMT_START {                                                          \
6707   static const GstValueTable gst_value =                                \
6708     SERIAL_VTABLE (_gtype, gst_value_compare_ ## _type,                 \
6709     gst_value_serialize_ ## _type, gst_value_deserialize_ ## _type);    \
6710   gst_value_register (&gst_value);                                      \
6711 } G_STMT_END
6712
6713 #define REGISTER_SERIALIZATION(_gtype, _type)                           \
6714 G_STMT_START {                                                          \
6715   static GstValueTable gst_value =                                      \
6716     SERIAL_VTABLE (0, gst_value_compare_ ## _type,                      \
6717     gst_value_serialize_ ## _type, gst_value_deserialize_ ## _type);    \
6718   gst_value.type = _gtype;                                              \
6719   gst_value_register (&gst_value);                                      \
6720 } G_STMT_END
6721
6722 #define REGISTER_SERIALIZATION_NO_COMPARE(_gtype, _type)                \
6723 G_STMT_START {                                                          \
6724   static GstValueTable gst_value =                                      \
6725     SERIAL_VTABLE (0, NULL,                                             \
6726     gst_value_serialize_ ## _type, gst_value_deserialize_ ## _type);    \
6727   gst_value.type = _gtype;                                              \
6728   gst_value_register (&gst_value);                                      \
6729 } G_STMT_END
6730
6731 #define REGISTER_SERIALIZATION_COMPARE_ONLY(_gtype, _type)              \
6732 G_STMT_START {                                                          \
6733   static GstValueTable gst_value =                                      \
6734     SERIAL_VTABLE (0, gst_value_compare_ ## _type,                      \
6735         NULL, NULL);                                                    \
6736   gst_value.type = _gtype;                                              \
6737   gst_value_register (&gst_value);                                      \
6738 } G_STMT_END
6739
6740 /* These initial sizes are used for the tables
6741  * below, and save a couple of reallocs at startup */
6742 static const gint GST_VALUE_TABLE_DEFAULT_SIZE = 34;
6743 static const gint GST_VALUE_UNION_TABLE_DEFAULT_SIZE = 3;
6744 static const gint GST_VALUE_INTERSECT_TABLE_DEFAULT_SIZE = 10;
6745 static const gint GST_VALUE_SUBTRACT_TABLE_DEFAULT_SIZE = 12;
6746
6747 void
6748 _priv_gst_value_initialize (void)
6749 {
6750   gst_value_table =
6751       g_array_sized_new (FALSE, FALSE, sizeof (GstValueTable),
6752       GST_VALUE_TABLE_DEFAULT_SIZE);
6753   gst_value_hash = g_hash_table_new (NULL, NULL);
6754   gst_value_union_funcs = g_array_sized_new (FALSE, FALSE,
6755       sizeof (GstValueUnionInfo), GST_VALUE_UNION_TABLE_DEFAULT_SIZE);
6756   gst_value_intersect_funcs = g_array_sized_new (FALSE, FALSE,
6757       sizeof (GstValueIntersectInfo), GST_VALUE_INTERSECT_TABLE_DEFAULT_SIZE);
6758   gst_value_subtract_funcs = g_array_sized_new (FALSE, FALSE,
6759       sizeof (GstValueSubtractInfo), GST_VALUE_SUBTRACT_TABLE_DEFAULT_SIZE);
6760
6761   REGISTER_SERIALIZATION (gst_int_range_get_type (), int_range);
6762   REGISTER_SERIALIZATION (gst_int64_range_get_type (), int64_range);
6763   REGISTER_SERIALIZATION (gst_double_range_get_type (), double_range);
6764   REGISTER_SERIALIZATION (gst_fraction_range_get_type (), fraction_range);
6765   REGISTER_SERIALIZATION (gst_value_list_get_type (), value_list);
6766   REGISTER_SERIALIZATION (gst_value_array_get_type (), value_array);
6767   REGISTER_SERIALIZATION (g_value_array_get_type (), g_value_array);
6768   REGISTER_SERIALIZATION (gst_buffer_get_type (), buffer);
6769   REGISTER_SERIALIZATION (gst_sample_get_type (), sample);
6770   REGISTER_SERIALIZATION (gst_fraction_get_type (), fraction);
6771   REGISTER_SERIALIZATION (gst_caps_get_type (), caps);
6772   REGISTER_SERIALIZATION (gst_tag_list_get_type (), tag_list);
6773   REGISTER_SERIALIZATION (G_TYPE_DATE, date);
6774   REGISTER_SERIALIZATION (gst_date_time_get_type (), date_time);
6775   REGISTER_SERIALIZATION (gst_bitmask_get_type (), bitmask);
6776   REGISTER_SERIALIZATION (gst_structure_get_type (), structure);
6777   REGISTER_SERIALIZATION (gst_flagset_get_type (), flagset);
6778
6779   REGISTER_SERIALIZATION_NO_COMPARE (gst_segment_get_type (), segment);
6780   REGISTER_SERIALIZATION_NO_COMPARE (gst_caps_features_get_type (),
6781       caps_features);
6782
6783   REGISTER_SERIALIZATION_COMPARE_ONLY (gst_allocation_params_get_type (),
6784       allocation_params);
6785   REGISTER_SERIALIZATION_COMPARE_ONLY (G_TYPE_OBJECT, object);
6786
6787   REGISTER_SERIALIZATION_CONST (G_TYPE_DOUBLE, double);
6788   REGISTER_SERIALIZATION_CONST (G_TYPE_FLOAT, float);
6789
6790   REGISTER_SERIALIZATION_CONST (G_TYPE_STRING, string);
6791   REGISTER_SERIALIZATION_CONST (G_TYPE_BOOLEAN, boolean);
6792   REGISTER_SERIALIZATION_CONST (G_TYPE_ENUM, enum);
6793
6794   REGISTER_SERIALIZATION_CONST (G_TYPE_FLAGS, gflags);
6795
6796   REGISTER_SERIALIZATION_CONST (G_TYPE_INT, int);
6797
6798   REGISTER_SERIALIZATION_CONST (G_TYPE_INT64, int64);
6799   REGISTER_SERIALIZATION_CONST (G_TYPE_LONG, long);
6800
6801   REGISTER_SERIALIZATION_CONST (G_TYPE_UINT, uint);
6802   REGISTER_SERIALIZATION_CONST (G_TYPE_UINT64, uint64);
6803   REGISTER_SERIALIZATION_CONST (G_TYPE_ULONG, ulong);
6804
6805   REGISTER_SERIALIZATION_CONST (G_TYPE_UCHAR, uchar);
6806
6807   g_value_register_transform_func (GST_TYPE_INT_RANGE, G_TYPE_STRING,
6808       gst_value_transform_int_range_string);
6809   g_value_register_transform_func (GST_TYPE_INT64_RANGE, G_TYPE_STRING,
6810       gst_value_transform_int64_range_string);
6811   g_value_register_transform_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_STRING,
6812       gst_value_transform_double_range_string);
6813   g_value_register_transform_func (GST_TYPE_FRACTION_RANGE, G_TYPE_STRING,
6814       gst_value_transform_fraction_range_string);
6815   g_value_register_transform_func (GST_TYPE_LIST, G_TYPE_STRING,
6816       gst_value_transform_list_string);
6817   g_value_register_transform_func (GST_TYPE_ARRAY, G_TYPE_STRING,
6818       gst_value_transform_array_string);
6819   g_value_register_transform_func (G_TYPE_VALUE_ARRAY, G_TYPE_STRING,
6820       gst_value_transform_g_value_array_string);
6821   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_STRING,
6822       gst_value_transform_fraction_string);
6823   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_FRACTION,
6824       gst_value_transform_string_fraction);
6825   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_DOUBLE,
6826       gst_value_transform_fraction_double);
6827   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_FLOAT,
6828       gst_value_transform_fraction_float);
6829   g_value_register_transform_func (G_TYPE_DOUBLE, GST_TYPE_FRACTION,
6830       gst_value_transform_double_fraction);
6831   g_value_register_transform_func (G_TYPE_FLOAT, GST_TYPE_FRACTION,
6832       gst_value_transform_float_fraction);
6833   g_value_register_transform_func (G_TYPE_DATE, G_TYPE_STRING,
6834       gst_value_transform_date_string);
6835   g_value_register_transform_func (G_TYPE_STRING, G_TYPE_DATE,
6836       gst_value_transform_string_date);
6837   g_value_register_transform_func (GST_TYPE_OBJECT, G_TYPE_STRING,
6838       gst_value_transform_object_string);
6839   g_value_register_transform_func (GST_TYPE_BITMASK, G_TYPE_UINT64,
6840       gst_value_transform_bitmask_uint64);
6841   g_value_register_transform_func (GST_TYPE_BITMASK, G_TYPE_STRING,
6842       gst_value_transform_bitmask_string);
6843   g_value_register_transform_func (G_TYPE_UINT64, GST_TYPE_BITMASK,
6844       gst_value_transform_uint64_bitmask);
6845   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_BITMASK,
6846       gst_value_transform_string_bitmask);
6847
6848   g_value_register_transform_func (GST_TYPE_FLAG_SET, G_TYPE_STRING,
6849       gst_value_transform_flagset_string);
6850   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_FLAG_SET,
6851       gst_value_transform_string_flagset);
6852
6853   gst_value_register_intersect_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
6854       gst_value_intersect_int_int_range);
6855   gst_value_register_intersect_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
6856       gst_value_intersect_int_range_int_range);
6857   gst_value_register_intersect_func (G_TYPE_INT64, GST_TYPE_INT64_RANGE,
6858       gst_value_intersect_int64_int64_range);
6859   gst_value_register_intersect_func (GST_TYPE_INT64_RANGE,
6860       GST_TYPE_INT64_RANGE, gst_value_intersect_int64_range_int64_range);
6861   gst_value_register_intersect_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
6862       gst_value_intersect_double_double_range);
6863   gst_value_register_intersect_func (GST_TYPE_DOUBLE_RANGE,
6864       GST_TYPE_DOUBLE_RANGE, gst_value_intersect_double_range_double_range);
6865   gst_value_register_intersect_func (GST_TYPE_ARRAY, GST_TYPE_ARRAY,
6866       gst_value_intersect_array);
6867   gst_value_register_intersect_func (GST_TYPE_FRACTION,
6868       GST_TYPE_FRACTION_RANGE, gst_value_intersect_fraction_fraction_range);
6869   gst_value_register_intersect_func (GST_TYPE_FRACTION_RANGE,
6870       GST_TYPE_FRACTION_RANGE,
6871       gst_value_intersect_fraction_range_fraction_range);
6872   gst_value_register_intersect_func (GST_TYPE_FLAG_SET, GST_TYPE_FLAG_SET,
6873       gst_value_intersect_flagset_flagset);
6874
6875   gst_value_register_subtract_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
6876       gst_value_subtract_int_int_range);
6877   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, G_TYPE_INT,
6878       gst_value_subtract_int_range_int);
6879   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
6880       gst_value_subtract_int_range_int_range);
6881   gst_value_register_subtract_func (G_TYPE_INT64, GST_TYPE_INT64_RANGE,
6882       gst_value_subtract_int64_int64_range);
6883   gst_value_register_subtract_func (GST_TYPE_INT64_RANGE, G_TYPE_INT64,
6884       gst_value_subtract_int64_range_int64);
6885   gst_value_register_subtract_func (GST_TYPE_INT64_RANGE,
6886       GST_TYPE_INT64_RANGE, gst_value_subtract_int64_range_int64_range);
6887   gst_value_register_subtract_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
6888       gst_value_subtract_double_double_range);
6889   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_DOUBLE,
6890       gst_value_subtract_double_range_double);
6891   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE,
6892       GST_TYPE_DOUBLE_RANGE, gst_value_subtract_double_range_double_range);
6893   gst_value_register_subtract_func (GST_TYPE_FRACTION,
6894       GST_TYPE_FRACTION_RANGE, gst_value_subtract_fraction_fraction_range);
6895   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE,
6896       GST_TYPE_FRACTION, gst_value_subtract_fraction_range_fraction);
6897   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE,
6898       GST_TYPE_FRACTION_RANGE,
6899       gst_value_subtract_fraction_range_fraction_range);
6900
6901   /* see bug #317246, #64994, #65041 */
6902   {
6903     volatile GType date_type = G_TYPE_DATE;
6904
6905     g_type_name (date_type);
6906   }
6907
6908   gst_value_register_union_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
6909       gst_value_union_int_int_range);
6910   gst_value_register_union_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
6911       gst_value_union_int_range_int_range);
6912   gst_value_register_union_func (GST_TYPE_FLAG_SET, GST_TYPE_FLAG_SET,
6913       gst_value_union_flagset_flagset);
6914
6915 #if GST_VERSION_NANO == 1
6916   /* If building from git master, check starting array sizes matched actual size
6917    * so we can keep the defines in sync and save a few reallocs on startup */
6918   if (gst_value_table->len != GST_VALUE_TABLE_DEFAULT_SIZE) {
6919     GST_ERROR ("Wrong initial gst_value_table size. "
6920         "Please set GST_VALUE_TABLE_DEFAULT_SIZE to %u in gstvalue.c",
6921         gst_value_table->len);
6922   }
6923   if (gst_value_union_funcs->len != GST_VALUE_UNION_TABLE_DEFAULT_SIZE) {
6924     GST_ERROR ("Wrong initial gst_value_union_funcs table size. "
6925         "Please set GST_VALUE_UNION_TABLE_DEFAULT_SIZE to %u in gstvalue.c",
6926         gst_value_union_funcs->len);
6927   }
6928   if (gst_value_intersect_funcs->len != GST_VALUE_INTERSECT_TABLE_DEFAULT_SIZE) {
6929     GST_ERROR ("Wrong initial gst_value_intersect_funcs table size. "
6930         "Please set GST_VALUE_INTERSECT_TABLE_DEFAULT_SIZE to %u in gstvalue.c",
6931         gst_value_intersect_funcs->len);
6932   }
6933   if (gst_value_subtract_funcs->len != GST_VALUE_SUBTRACT_TABLE_DEFAULT_SIZE) {
6934     GST_ERROR ("Wrong initial gst_value_subtract_funcs table size. "
6935         "Please set GST_VALUE_SUBTRACT_TABLE_DEFAULT_SIZE to %u in gstvalue.c",
6936         gst_value_subtract_funcs->len);
6937   }
6938 #endif
6939
6940 #if 0
6941   /* Implement these if needed */
6942   gst_value_register_union_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
6943       gst_value_union_fraction_fraction_range);
6944   gst_value_register_union_func (GST_TYPE_FRACTION_RANGE,
6945       GST_TYPE_FRACTION_RANGE, gst_value_union_fraction_range_fraction_range);
6946 #endif
6947 }
6948
6949 static void
6950 gst_flagset_class_init (gpointer g_class, gpointer class_data)
6951 {
6952   GstFlagSetClass *f_class = (GstFlagSetClass *) (g_class);
6953   f_class->flags_type = (GType) GPOINTER_TO_SIZE (class_data);
6954 }
6955
6956 /**
6957  * gst_flagset_register:
6958  * @flags_type: a #GType of a #G_TYPE_FLAGS type.
6959  *
6960  * Create a new sub-class of #GST_TYPE_FLAG_SET
6961  * which will pretty-print the human-readable flags
6962  * when serializing, for easier debugging.
6963  *
6964  * Since: 1.6
6965  */
6966 GType
6967 gst_flagset_register (GType flags_type)
6968 {
6969   GTypeInfo info = {
6970     sizeof (GstFlagSetClass),
6971     NULL, NULL,
6972     (GClassInitFunc) gst_flagset_class_init,
6973     NULL, GSIZE_TO_POINTER (flags_type), 0, 0, NULL, NULL
6974   };
6975   GType t;
6976   gchar *class_name;
6977
6978   g_return_val_if_fail (G_TYPE_IS_FLAGS (flags_type), 0);
6979
6980   class_name = g_strdup_printf ("%sSet", g_type_name (flags_type));
6981
6982   t = g_type_register_static (GST_TYPE_FLAG_SET,
6983       g_intern_string (class_name), &info, 0);
6984   g_free (class_name);
6985
6986   return t;
6987 }