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