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