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