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