gst/gstbin.c: Help the compiler a bit with type registration.
[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 to GStreamer
23  *
24  * GValue implementations specific to GStreamer.
25  *
26  * Last reviewed on 2005-11-23 (0.9.5)
27  */
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 #include <math.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <ctype.h>
36
37 #include "gst_private.h"
38 #include "glib-compat-private.h"
39 #include <gst/gst.h>
40 #include <gobject/gvaluecollector.h>
41
42 typedef struct _GstValueUnionInfo GstValueUnionInfo;
43 struct _GstValueUnionInfo
44 {
45   GType type1;
46   GType type2;
47   GstValueUnionFunc func;
48 };
49
50 typedef struct _GstValueIntersectInfo GstValueIntersectInfo;
51 struct _GstValueIntersectInfo
52 {
53   GType type1;
54   GType type2;
55   GstValueIntersectFunc func;
56 };
57
58 typedef struct _GstValueSubtractInfo GstValueSubtractInfo;
59 struct _GstValueSubtractInfo
60 {
61   GType minuend;
62   GType subtrahend;
63   GstValueSubtractFunc func;
64 };
65
66 GType gst_type_double_range;
67 GType gst_type_fraction_range;
68 GType gst_type_list;
69 GType gst_type_array;
70 GType gst_type_fraction;
71 GType gst_type_date;
72
73 static GArray *gst_value_table;
74 static GArray *gst_value_union_funcs;
75 static GArray *gst_value_intersect_funcs;
76 static GArray *gst_value_subtract_funcs;
77
78 /* Forward declarations */
79 static gint gst_greatest_common_divisor (gint a, gint b);
80 static gchar *gst_value_serialize_fraction (const GValue * value);
81
82 /********
83  * list *
84  ********/
85
86 /* two helper functions to serialize/stringify any type of list
87  * regular lists are done with { }, arrays with < >
88  */
89 static gchar *
90 gst_value_serialize_any_list (const GValue * value, const gchar * begin,
91     const gchar * end)
92 {
93   guint i;
94   GArray *array = value->data[0].v_pointer;
95   GString *s;
96   GValue *v;
97   gchar *s_val;
98
99   s = g_string_new (begin);
100   for (i = 0; i < array->len; i++) {
101     v = &g_array_index (array, GValue, i);
102     s_val = gst_value_serialize (v);
103     g_string_append (s, s_val);
104     g_free (s_val);
105     if (i < array->len - 1) {
106       g_string_append (s, ", ");
107     }
108   }
109   g_string_append (s, end);
110   return g_string_free (s, FALSE);
111 }
112
113 static void
114 gst_value_transform_any_list_string (const GValue * src_value,
115     GValue * dest_value, const gchar * begin, const gchar * end)
116 {
117   GValue *list_value;
118   GArray *array;
119   GString *s;
120   guint i;
121   gchar *list_s;
122
123   array = src_value->data[0].v_pointer;
124
125   s = g_string_new (begin);
126   for (i = 0; i < array->len; i++) {
127     list_value = &g_array_index (array, GValue, i);
128
129     if (i != 0) {
130       g_string_append (s, ", ");
131     }
132     list_s = g_strdup_value_contents (list_value);
133     g_string_append (s, list_s);
134     g_free (list_s);
135   }
136   g_string_append (s, end);
137
138   dest_value->data[0].v_pointer = g_string_free (s, FALSE);
139 }
140
141 /*
142  * helper function to see if a type is fixed. Is used internally here and
143  * there. Do not export, since it doesn't work for types where the content
144  * decides the fixedness (e.g. GST_TYPE_ARRAY).
145  */
146
147 static gboolean
148 gst_type_is_fixed (GType type)
149 {
150   if (type == GST_TYPE_INT_RANGE || type == GST_TYPE_DOUBLE_RANGE ||
151       type == GST_TYPE_LIST) {
152     return FALSE;
153   }
154   if (G_TYPE_FUNDAMENTAL (type) <=
155       G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
156     return TRUE;
157   }
158   if (type == GST_TYPE_BUFFER || type == GST_TYPE_FOURCC
159       || type == GST_TYPE_ARRAY || type == GST_TYPE_FRACTION) {
160     return TRUE;
161   }
162
163   return FALSE;
164 }
165
166 /* GValue functions usable for both regular lists and arrays */
167 static void
168 gst_value_init_list_or_array (GValue * value)
169 {
170   value->data[0].v_pointer = g_array_new (FALSE, TRUE, sizeof (GValue));
171 }
172
173 static GArray *
174 copy_garray_of_gstvalue (const GArray * src)
175 {
176   GArray *dest;
177   guint i;
178
179   dest = g_array_sized_new (FALSE, TRUE, sizeof (GValue), src->len);
180   g_array_set_size (dest, src->len);
181   for (i = 0; i < src->len; i++) {
182     gst_value_init_and_copy (&g_array_index (dest, GValue, i),
183         &g_array_index (src, GValue, i));
184   }
185
186   return dest;
187 }
188
189 static void
190 gst_value_copy_list_or_array (const GValue * src_value, GValue * dest_value)
191 {
192   dest_value->data[0].v_pointer =
193       copy_garray_of_gstvalue ((GArray *) src_value->data[0].v_pointer);
194 }
195
196 static void
197 gst_value_free_list_or_array (GValue * value)
198 {
199   guint i;
200   GArray *src = (GArray *) value->data[0].v_pointer;
201
202   if ((value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS) == 0) {
203     for (i = 0; i < src->len; i++) {
204       g_value_unset (&g_array_index (src, GValue, i));
205     }
206     g_array_free (src, TRUE);
207   }
208 }
209
210 static gpointer
211 gst_value_list_or_array_peek_pointer (const GValue * value)
212 {
213   return value->data[0].v_pointer;
214 }
215
216 static gchar *
217 gst_value_collect_list_or_array (GValue * value, guint n_collect_values,
218     GTypeCValue * collect_values, guint collect_flags)
219 {
220   if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
221     value->data[0].v_pointer = collect_values[0].v_pointer;
222     value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
223   } else {
224     value->data[0].v_pointer =
225         copy_garray_of_gstvalue ((GArray *) collect_values[0].v_pointer);
226   }
227   return NULL;
228 }
229
230 static gchar *
231 gst_value_lcopy_list_or_array (const GValue * value, guint n_collect_values,
232     GTypeCValue * collect_values, guint collect_flags)
233 {
234   GArray **dest = collect_values[0].v_pointer;
235
236   if (!dest)
237     return g_strdup_printf ("value location for `%s' passed as NULL",
238         G_VALUE_TYPE_NAME (value));
239   if (!value->data[0].v_pointer)
240     return g_strdup_printf ("invalid value given for `%s'",
241         G_VALUE_TYPE_NAME (value));
242   if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
243     *dest = (GArray *) value->data[0].v_pointer;
244   } else {
245     *dest = copy_garray_of_gstvalue ((GArray *) value->data[0].v_pointer);
246   }
247   return NULL;
248 }
249
250 /**
251  * gst_value_list_append_value:
252  * @value: a #GValue of type #GST_TYPE_LIST
253  * @append_value: the value to append
254  *
255  * Appends @append_value to the GstValueList in @value.
256  */
257 void
258 gst_value_list_append_value (GValue * value, const GValue * append_value)
259 {
260   GValue val = { 0, };
261
262   g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
263
264   gst_value_init_and_copy (&val, append_value);
265   g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1);
266 }
267
268 /**
269  * gst_value_list_prepend_value:
270  * @value: a #GValue of type #GST_TYPE_LIST
271  * @prepend_value: the value to prepend
272  *
273  * Prepends @prepend_value to the GstValueList in @value.
274  */
275 void
276 gst_value_list_prepend_value (GValue * value, const GValue * prepend_value)
277 {
278   GValue val = { 0, };
279
280   g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
281
282   gst_value_init_and_copy (&val, prepend_value);
283   g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1);
284 }
285
286 /**
287  * gst_value_list_concat:
288  * @dest: an uninitialized #GValue to take the result
289  * @value1: a #GValue
290  * @value2: a #GValue
291  *
292  * Concatenates copies of @value1 and @value2 into a list.  Values that are not
293  * of type #GST_TYPE_LIST are treated as if they were lists of length 1.
294  * @dest will be initialized to the type #GST_TYPE_LIST.
295  */
296 void
297 gst_value_list_concat (GValue * dest, const GValue * value1,
298     const GValue * value2)
299 {
300   guint i, value1_length, value2_length;
301   GArray *array;
302
303   g_return_if_fail (dest != NULL);
304   g_return_if_fail (G_VALUE_TYPE (dest) == 0);
305   g_return_if_fail (G_IS_VALUE (value1));
306   g_return_if_fail (G_IS_VALUE (value2));
307
308   value1_length =
309       (GST_VALUE_HOLDS_LIST (value1) ? gst_value_list_get_size (value1) : 1);
310   value2_length =
311       (GST_VALUE_HOLDS_LIST (value2) ? gst_value_list_get_size (value2) : 1);
312   g_value_init (dest, GST_TYPE_LIST);
313   array = (GArray *) dest->data[0].v_pointer;
314   g_array_set_size (array, value1_length + value2_length);
315
316   if (GST_VALUE_HOLDS_LIST (value1)) {
317     for (i = 0; i < value1_length; i++) {
318       gst_value_init_and_copy (&g_array_index (array, GValue, i),
319           gst_value_list_get_value (value1, i));
320     }
321   } else {
322     gst_value_init_and_copy (&g_array_index (array, GValue, 0), value1);
323   }
324
325   if (GST_VALUE_HOLDS_LIST (value2)) {
326     for (i = 0; i < value2_length; i++) {
327       gst_value_init_and_copy (&g_array_index (array, GValue,
328               i + value1_length), gst_value_list_get_value (value2, i));
329     }
330   } else {
331     gst_value_init_and_copy (&g_array_index (array, GValue, value1_length),
332         value2);
333   }
334 }
335
336 /**
337  * gst_value_list_get_size:
338  * @value: a #GValue of type #GST_TYPE_LIST
339  *
340  * Gets the number of values contained in @value.
341  *
342  * Returns: the number of values
343  */
344 guint
345 gst_value_list_get_size (const GValue * value)
346 {
347   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), 0);
348
349   return ((GArray *) value->data[0].v_pointer)->len;
350 }
351
352 /**
353  * gst_value_list_get_value:
354  * @value: a #GValue of type #GST_TYPE_LIST
355  * @index: index of value to get from the list
356  *
357  * Gets the value that is a member of the list contained in @value and
358  * has the index @index.
359  *
360  * Returns: the value at the given index
361  */
362 const GValue *
363 gst_value_list_get_value (const GValue * value, guint index)
364 {
365   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), NULL);
366   g_return_val_if_fail (index < gst_value_list_get_size (value), NULL);
367
368   return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer,
369       GValue, index);
370 }
371
372 /**
373  * gst_value_array_append_value:
374  * @value: a #GValue of type #GST_TYPE_ARRAY
375  * @append_value: the value to append
376  *
377  * Appends @append_value to the GstValueArray in @value.
378  */
379 void
380 gst_value_array_append_value (GValue * value, const GValue * append_value)
381 {
382   GValue val = { 0, };
383
384   g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value));
385
386   gst_value_init_and_copy (&val, append_value);
387   g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1);
388 }
389
390 /**
391  * gst_value_array_prepend_value:
392  * @value: a #GValue of type #GST_TYPE_ARRAY
393  * @prepend_value: the value to prepend
394  *
395  * Prepends @prepend_value to the GstValueArray in @value.
396  */
397 void
398 gst_value_array_prepend_value (GValue * value, const GValue * prepend_value)
399 {
400   GValue val = { 0, };
401
402   g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value));
403
404   gst_value_init_and_copy (&val, prepend_value);
405   g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1);
406 }
407
408 /**
409  * gst_value_array_get_size:
410  * @value: a #GValue of type #GST_TYPE_ARRAY
411  *
412  * Gets the number of values contained in @value.
413  *
414  * Returns: the number of values
415  */
416 guint
417 gst_value_array_get_size (const GValue * value)
418 {
419   g_return_val_if_fail (GST_VALUE_HOLDS_ARRAY (value), 0);
420
421   return ((GArray *) value->data[0].v_pointer)->len;
422 }
423
424 /**
425  * gst_value_array_get_value:
426  * @value: a #GValue of type #GST_TYPE_ARRAY
427  * @index: index of value to get from the array
428  *
429  * Gets the value that is a member of the array contained in @value and
430  * has the index @index.
431  *
432  * Returns: the value at the given index
433  */
434 const GValue *
435 gst_value_array_get_value (const GValue * value, guint index)
436 {
437   g_return_val_if_fail (GST_VALUE_HOLDS_ARRAY (value), NULL);
438   g_return_val_if_fail (index < gst_value_array_get_size (value), NULL);
439
440   return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer,
441       GValue, index);
442 }
443
444 static void
445 gst_value_transform_list_string (const GValue * src_value, GValue * dest_value)
446 {
447   gst_value_transform_any_list_string (src_value, dest_value, "{ ", " }");
448 }
449
450 static void
451 gst_value_transform_array_string (const GValue * src_value, GValue * dest_value)
452 {
453   gst_value_transform_any_list_string (src_value, dest_value, "< ", " >");
454 }
455
456 static int
457 gst_value_compare_list_or_array (const GValue * value1, const GValue * value2)
458 {
459   guint i, j;
460   GArray *array1 = value1->data[0].v_pointer;
461   GArray *array2 = value2->data[0].v_pointer;
462   GValue *v1;
463   GValue *v2;
464
465   if (array1->len != array2->len)
466     return GST_VALUE_UNORDERED;
467
468   for (i = 0; i < array1->len; i++) {
469     v1 = &g_array_index (array1, GValue, i);
470     for (j = 0; j < array1->len; j++) {
471       v2 = &g_array_index (array2, GValue, j);
472       if (gst_value_compare (v1, v2) == GST_VALUE_EQUAL)
473         break;
474     }
475     if (j == array1->len) {
476       return GST_VALUE_UNORDERED;
477     }
478   }
479
480   return GST_VALUE_EQUAL;
481 }
482
483 static gchar *
484 gst_value_serialize_list (const GValue * value)
485 {
486   return gst_value_serialize_any_list (value, "{ ", " }");
487 }
488
489 static gboolean
490 gst_value_deserialize_list (GValue * dest, const gchar * s)
491 {
492   g_warning ("unimplemented");
493   return FALSE;
494 }
495
496 static gchar *
497 gst_value_serialize_array (const GValue * value)
498 {
499   return gst_value_serialize_any_list (value, "< ", " >");
500 }
501
502 static gboolean
503 gst_value_deserialize_array (GValue * dest, const gchar * s)
504 {
505   g_warning ("unimplemented");
506   return FALSE;
507 }
508
509 /**********
510  * fourcc *
511  **********/
512
513 static void
514 gst_value_init_fourcc (GValue * value)
515 {
516   value->data[0].v_int = 0;
517 }
518
519 static void
520 gst_value_copy_fourcc (const GValue * src_value, GValue * dest_value)
521 {
522   dest_value->data[0].v_int = src_value->data[0].v_int;
523 }
524
525 static gchar *
526 gst_value_collect_fourcc (GValue * value, guint n_collect_values,
527     GTypeCValue * collect_values, guint collect_flags)
528 {
529   value->data[0].v_int = collect_values[0].v_int;
530
531   return NULL;
532 }
533
534 static gchar *
535 gst_value_lcopy_fourcc (const GValue * value, guint n_collect_values,
536     GTypeCValue * collect_values, guint collect_flags)
537 {
538   guint32 *fourcc_p = collect_values[0].v_pointer;
539
540   if (!fourcc_p)
541     return g_strdup_printf ("value location for `%s' passed as NULL",
542         G_VALUE_TYPE_NAME (value));
543
544   *fourcc_p = value->data[0].v_int;
545
546   return NULL;
547 }
548
549 /**
550  * gst_value_set_fourcc:
551  * @value: a GValue initialized to #GST_TYPE_FOURCC
552  * @fourcc: the #guint32 fourcc to set
553  *
554  * Sets @value to @fourcc.
555  */
556 void
557 gst_value_set_fourcc (GValue * value, guint32 fourcc)
558 {
559   g_return_if_fail (GST_VALUE_HOLDS_FOURCC (value));
560
561   value->data[0].v_int = fourcc;
562 }
563
564 /**
565  * gst_value_get_fourcc:
566  * @value: a GValue initialized to #GST_TYPE_FOURCC
567  *
568  * Gets the #guint32 fourcc contained in @value.
569  *
570  * Returns: the #guint32 fourcc contained in @value.
571  */
572 guint32
573 gst_value_get_fourcc (const GValue * value)
574 {
575   g_return_val_if_fail (GST_VALUE_HOLDS_FOURCC (value), 0);
576
577   return value->data[0].v_int;
578 }
579
580 static void
581 gst_value_transform_fourcc_string (const GValue * src_value,
582     GValue * dest_value)
583 {
584   guint32 fourcc = src_value->data[0].v_int;
585
586   if (g_ascii_isprint ((fourcc >> 0) & 0xff) &&
587       g_ascii_isprint ((fourcc >> 8) & 0xff) &&
588       g_ascii_isprint ((fourcc >> 16) & 0xff) &&
589       g_ascii_isprint ((fourcc >> 24) & 0xff)) {
590     dest_value->data[0].v_pointer =
591         g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
592   } else {
593     dest_value->data[0].v_pointer = g_strdup_printf ("0x%08x", fourcc);
594   }
595 }
596
597 static gint
598 gst_value_compare_fourcc (const GValue * value1, const GValue * value2)
599 {
600   if (value2->data[0].v_int == value1->data[0].v_int)
601     return GST_VALUE_EQUAL;
602   return GST_VALUE_UNORDERED;
603 }
604
605 static gchar *
606 gst_value_serialize_fourcc (const GValue * value)
607 {
608   guint32 fourcc = value->data[0].v_int;
609
610   if (g_ascii_isalnum ((fourcc >> 0) & 0xff) &&
611       g_ascii_isalnum ((fourcc >> 8) & 0xff) &&
612       g_ascii_isalnum ((fourcc >> 16) & 0xff) &&
613       g_ascii_isalnum ((fourcc >> 24) & 0xff)) {
614     return g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
615   } else {
616     return g_strdup_printf ("0x%08x", fourcc);
617   }
618 }
619
620 static gboolean
621 gst_value_deserialize_fourcc (GValue * dest, const char *s)
622 {
623   gboolean ret = FALSE;
624   guint32 fourcc = 0;
625   char *end;
626
627   if (strlen (s) == 4) {
628     fourcc = GST_MAKE_FOURCC (s[0], s[1], s[2], s[3]);
629     ret = TRUE;
630   } else if (g_ascii_isdigit (*s)) {
631     fourcc = strtoul (s, &end, 0);
632     if (*end == 0) {
633       ret = TRUE;
634     }
635   }
636   gst_value_set_fourcc (dest, fourcc);
637
638   return ret;
639 }
640
641 /*************
642  * int range *
643  *************/
644
645 static void
646 gst_value_init_int_range (GValue * value)
647 {
648   value->data[0].v_int = 0;
649   value->data[1].v_int = 0;
650 }
651
652 static void
653 gst_value_copy_int_range (const GValue * src_value, GValue * dest_value)
654 {
655   dest_value->data[0].v_int = src_value->data[0].v_int;
656   dest_value->data[1].v_int = src_value->data[1].v_int;
657 }
658
659 static gchar *
660 gst_value_collect_int_range (GValue * value, guint n_collect_values,
661     GTypeCValue * collect_values, guint collect_flags)
662 {
663   value->data[0].v_int = collect_values[0].v_int;
664   value->data[1].v_int = collect_values[1].v_int;
665
666   return NULL;
667 }
668
669 static gchar *
670 gst_value_lcopy_int_range (const GValue * value, guint n_collect_values,
671     GTypeCValue * collect_values, guint collect_flags)
672 {
673   guint32 *int_range_start = collect_values[0].v_pointer;
674   guint32 *int_range_end = collect_values[1].v_pointer;
675
676   if (!int_range_start)
677     return g_strdup_printf ("start value location for `%s' passed as NULL",
678         G_VALUE_TYPE_NAME (value));
679   if (!int_range_end)
680     return g_strdup_printf ("end value location for `%s' passed as NULL",
681         G_VALUE_TYPE_NAME (value));
682
683   *int_range_start = value->data[0].v_int;
684   *int_range_end = value->data[1].v_int;
685
686   return NULL;
687 }
688
689 /**
690  * gst_value_set_int_range:
691  * @value: a GValue initialized to GST_TYPE_INT_RANGE
692  * @start: the start of the range
693  * @end: the end of the range
694  *
695  * Sets @value to the range specified by @start and @end.
696  */
697 void
698 gst_value_set_int_range (GValue * value, gint start, gint end)
699 {
700   g_return_if_fail (GST_VALUE_HOLDS_INT_RANGE (value));
701   g_return_if_fail (start < end);
702
703   value->data[0].v_int = start;
704   value->data[1].v_int = end;
705 }
706
707 /**
708  * gst_value_get_int_range_min:
709  * @value: a GValue initialized to GST_TYPE_INT_RANGE
710  *
711  * Gets the minimum of the range specified by @value.
712  *
713  * Returns: the minimum of the range
714  */
715 gint
716 gst_value_get_int_range_min (const GValue * value)
717 {
718   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
719
720   return value->data[0].v_int;
721 }
722
723 /**
724  * gst_value_get_int_range_max:
725  * @value: a GValue initialized to GST_TYPE_INT_RANGE
726  *
727  * Gets the maximum of the range specified by @value.
728  *
729  * Returns: the maxumum of the range
730  */
731 gint
732 gst_value_get_int_range_max (const GValue * value)
733 {
734   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
735
736   return value->data[1].v_int;
737 }
738
739 static void
740 gst_value_transform_int_range_string (const GValue * src_value,
741     GValue * dest_value)
742 {
743   dest_value->data[0].v_pointer = g_strdup_printf ("[%d,%d]",
744       (int) src_value->data[0].v_int, (int) src_value->data[1].v_int);
745 }
746
747 static gint
748 gst_value_compare_int_range (const GValue * value1, const GValue * value2)
749 {
750   if (value2->data[0].v_int == value1->data[0].v_int &&
751       value2->data[1].v_int == value1->data[1].v_int)
752     return GST_VALUE_EQUAL;
753   return GST_VALUE_UNORDERED;
754 }
755
756 static gchar *
757 gst_value_serialize_int_range (const GValue * value)
758 {
759   return g_strdup_printf ("[ %d, %d ]", value->data[0].v_int,
760       value->data[1].v_int);
761 }
762
763 static gboolean
764 gst_value_deserialize_int_range (GValue * dest, const gchar * s)
765 {
766   g_warning ("unimplemented");
767   return FALSE;
768 }
769
770 /****************
771  * double range *
772  ****************/
773
774 static void
775 gst_value_init_double_range (GValue * value)
776 {
777   value->data[0].v_double = 0;
778   value->data[1].v_double = 0;
779 }
780
781 static void
782 gst_value_copy_double_range (const GValue * src_value, GValue * dest_value)
783 {
784   dest_value->data[0].v_double = src_value->data[0].v_double;
785   dest_value->data[1].v_double = src_value->data[1].v_double;
786 }
787
788 static gchar *
789 gst_value_collect_double_range (GValue * value, guint n_collect_values,
790     GTypeCValue * collect_values, guint collect_flags)
791 {
792   value->data[0].v_double = collect_values[0].v_double;
793   value->data[1].v_double = collect_values[1].v_double;
794
795   return NULL;
796 }
797
798 static gchar *
799 gst_value_lcopy_double_range (const GValue * value, guint n_collect_values,
800     GTypeCValue * collect_values, guint collect_flags)
801 {
802   gdouble *double_range_start = collect_values[0].v_pointer;
803   gdouble *double_range_end = collect_values[1].v_pointer;
804
805   if (!double_range_start)
806     return g_strdup_printf ("start value location for `%s' passed as NULL",
807         G_VALUE_TYPE_NAME (value));
808   if (!double_range_end)
809     return g_strdup_printf ("end value location for `%s' passed as NULL",
810         G_VALUE_TYPE_NAME (value));
811
812   *double_range_start = value->data[0].v_double;
813   *double_range_end = value->data[1].v_double;
814
815   return NULL;
816 }
817
818 /**
819  * gst_value_set_double_range:
820  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
821  * @start: the start of the range
822  * @end: the end of the range
823  *
824  * Sets @value to the range specified by @start and @end.
825  */
826 void
827 gst_value_set_double_range (GValue * value, gdouble start, gdouble end)
828 {
829   g_return_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value));
830
831   value->data[0].v_double = start;
832   value->data[1].v_double = end;
833 }
834
835 /**
836  * gst_value_get_double_range_min:
837  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
838  *
839  * Gets the minimum of the range specified by @value.
840  *
841  * Returns: the minumum of the range
842  */
843 gdouble
844 gst_value_get_double_range_min (const GValue * value)
845 {
846   g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
847
848   return value->data[0].v_double;
849 }
850
851 /**
852  * gst_value_get_double_range_max:
853  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
854  *
855  * Gets the maximum of the range specified by @value.
856  *
857  * Returns: the maxumum of the range
858  */
859 gdouble
860 gst_value_get_double_range_max (const GValue * value)
861 {
862   g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
863
864   return value->data[1].v_double;
865 }
866
867 static void
868 gst_value_transform_double_range_string (const GValue * src_value,
869     GValue * dest_value)
870 {
871   char s1[G_ASCII_DTOSTR_BUF_SIZE], s2[G_ASCII_DTOSTR_BUF_SIZE];
872
873   dest_value->data[0].v_pointer = g_strdup_printf ("[%s,%s]",
874       g_ascii_dtostr (s1, G_ASCII_DTOSTR_BUF_SIZE,
875           src_value->data[0].v_double),
876       g_ascii_dtostr (s2, G_ASCII_DTOSTR_BUF_SIZE,
877           src_value->data[1].v_double));
878 }
879
880 static gint
881 gst_value_compare_double_range (const GValue * value1, const GValue * value2)
882 {
883   if (value2->data[0].v_double == value1->data[0].v_double &&
884       value2->data[0].v_double == value1->data[0].v_double)
885     return GST_VALUE_EQUAL;
886   return GST_VALUE_UNORDERED;
887 }
888
889 static gchar *
890 gst_value_serialize_double_range (const GValue * value)
891 {
892   char d1[G_ASCII_DTOSTR_BUF_SIZE];
893   char d2[G_ASCII_DTOSTR_BUF_SIZE];
894
895   g_ascii_dtostr (d1, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
896   g_ascii_dtostr (d2, G_ASCII_DTOSTR_BUF_SIZE, value->data[1].v_double);
897   return g_strdup_printf ("[ %s, %s ]", d1, d2);
898 }
899
900 static gboolean
901 gst_value_deserialize_double_range (GValue * dest, const gchar * s)
902 {
903   g_warning ("unimplemented");
904   return FALSE;
905 }
906
907 /****************
908  * fraction range *
909  ****************/
910
911 static void
912 gst_value_init_fraction_range (GValue * value)
913 {
914   GValue *vals;
915
916   value->data[0].v_pointer = vals = g_new0 (GValue, 2);
917   g_value_init (&vals[0], GST_TYPE_FRACTION);
918   g_value_init (&vals[1], GST_TYPE_FRACTION);
919 }
920
921 static void
922 gst_value_free_fraction_range (GValue * value)
923 {
924   GValue *vals = (GValue *) value->data[0].v_pointer;
925
926   if (vals != NULL) {
927     g_value_unset (&vals[0]);
928     g_value_unset (&vals[1]);
929     g_free (vals);
930     value->data[0].v_pointer = NULL;
931   }
932 }
933
934 static void
935 gst_value_copy_fraction_range (const GValue * src_value, GValue * dest_value)
936 {
937   GValue *vals = (GValue *) dest_value->data[0].v_pointer;
938   GValue *src_vals = (GValue *) src_value->data[0].v_pointer;
939
940   if (vals == NULL) {
941     dest_value->data[0].v_pointer = vals = g_new0 (GValue, 2);
942     g_return_if_fail (vals != NULL);
943     g_value_init (&vals[0], GST_TYPE_FRACTION);
944     g_value_init (&vals[1], GST_TYPE_FRACTION);
945   }
946
947   if (src_vals != NULL) {
948     g_value_copy (&src_vals[0], &vals[0]);
949     g_value_copy (&src_vals[1], &vals[1]);
950   }
951 }
952
953 static gchar *
954 gst_value_collect_fraction_range (GValue * value, guint n_collect_values,
955     GTypeCValue * collect_values, guint collect_flags)
956 {
957   GValue *vals = (GValue *) value->data[0].v_pointer;
958
959   if (n_collect_values != 4)
960     return g_strdup_printf ("not enough value locations for `%s' passed",
961         G_VALUE_TYPE_NAME (value));
962   if (vals == NULL) {
963     value->data[0].v_pointer = vals = g_new0 (GValue, 2);
964     if (vals == NULL)
965       return g_strdup_printf ("Could not initialise`%s' during collect",
966           G_VALUE_TYPE_NAME (value));
967     g_value_init (&vals[0], GST_TYPE_FRACTION);
968     g_value_init (&vals[1], GST_TYPE_FRACTION);
969   }
970
971   gst_value_set_fraction (&vals[0], collect_values[0].v_int,
972       collect_values[1].v_int);
973   gst_value_set_fraction (&vals[1], collect_values[2].v_int,
974       collect_values[3].v_int);
975
976   return NULL;
977 }
978
979 static gchar *
980 gst_value_lcopy_fraction_range (const GValue * value, guint n_collect_values,
981     GTypeCValue * collect_values, guint collect_flags)
982 {
983   int i;
984   int *dest_values[4];
985   GValue *vals = (GValue *) value->data[0].v_pointer;
986
987   if (n_collect_values != 4)
988     return g_strdup_printf ("not enough value locations for `%s' passed",
989         G_VALUE_TYPE_NAME (value));
990
991   for (i = 0; i < 4; i++) {
992     if (collect_values[i].v_pointer == NULL) {
993       return g_strdup_printf ("value location for `%s' passed as NULL",
994           G_VALUE_TYPE_NAME (value));
995     }
996     dest_values[i] = collect_values[i].v_pointer;
997   }
998
999   if (vals == NULL) {
1000     return g_strdup_printf ("Uninitialised `%s' passed",
1001         G_VALUE_TYPE_NAME (value));
1002   }
1003
1004   dest_values[0][0] = gst_value_get_fraction_numerator (&vals[0]);
1005   dest_values[1][0] = gst_value_get_fraction_denominator (&vals[0]);
1006   dest_values[2][0] = gst_value_get_fraction_denominator (&vals[1]);
1007   dest_values[3][0] = gst_value_get_fraction_denominator (&vals[1]);
1008   return NULL;
1009 }
1010
1011 /**
1012  * gst_value_set_fraction_range:
1013  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1014  * @start: the start of the range (a GST_TYPE_FRACTION GValue)
1015  * @end: the end of the range (a GST_TYPE_FRACTION GValue)
1016  *
1017  * Sets @value to the range specified by @start and @end.
1018  */
1019 void
1020 gst_value_set_fraction_range (GValue * value, const GValue * start,
1021     const GValue * end)
1022 {
1023   GValue *vals;
1024
1025   g_return_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value));
1026
1027   vals = (GValue *) value->data[0].v_pointer;
1028   if (vals == NULL) {
1029     value->data[0].v_pointer = vals = g_new0 (GValue, 2);
1030     g_value_init (&vals[0], GST_TYPE_FRACTION);
1031     g_value_init (&vals[1], GST_TYPE_FRACTION);
1032   }
1033
1034   g_value_copy (start, &vals[0]);
1035   g_value_copy (end, &vals[1]);
1036 }
1037
1038 /**
1039  * gst_value_set_fraction_range_full:
1040  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1041  * @numerator_start: the numerator start of the range
1042  * @denominator_start: the denominator start of the range
1043  * @numerator_end: the numerator end of the range
1044  * @denominator_end: the denominator end of the range
1045  *
1046  * Sets @value to the range specified by @numerator_start/@denominator_start
1047  * and @numerator_end/@denominator_end.
1048  */
1049 void
1050 gst_value_set_fraction_range_full (GValue * value,
1051     gint numerator_start, gint denominator_start,
1052     gint numerator_end, gint denominator_end)
1053 {
1054   GValue start = { 0 };
1055   GValue end = { 0 };
1056
1057   g_value_init (&start, GST_TYPE_FRACTION);
1058   g_value_init (&end, GST_TYPE_FRACTION);
1059
1060   gst_value_set_fraction (&start, numerator_start, denominator_start);
1061   gst_value_set_fraction (&end, numerator_end, denominator_end);
1062   gst_value_set_fraction_range (value, &start, &end);
1063
1064   g_value_unset (&start);
1065   g_value_unset (&end);
1066 }
1067
1068 /**
1069  * gst_value_get_fraction_range_min:
1070  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1071  *
1072  * Gets the minimum of the range specified by @value.
1073  *
1074  * Returns: the minumum of the range
1075  */
1076 const GValue *
1077 gst_value_get_fraction_range_min (const GValue * value)
1078 {
1079   GValue *vals;
1080
1081   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value), FALSE);
1082
1083   vals = (GValue *) value->data[0].v_pointer;
1084   if (vals != NULL) {
1085     return &vals[0];
1086   }
1087
1088   return NULL;
1089 }
1090
1091 /**
1092  * gst_value_get_fraction_range_max:
1093  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1094  *
1095  * Gets the maximum of the range specified by @value.
1096  *
1097  * Returns: the maximum of the range
1098  */
1099 const GValue *
1100 gst_value_get_fraction_range_max (const GValue * value)
1101 {
1102   GValue *vals;
1103
1104   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value), FALSE);
1105
1106   vals = (GValue *) value->data[0].v_pointer;
1107   if (vals != NULL) {
1108     return &vals[1];
1109   }
1110
1111   return NULL;
1112 }
1113
1114 static char *
1115 gst_value_serialize_fraction_range (const GValue * value)
1116 {
1117   GValue *vals = (GValue *) value->data[0].v_pointer;
1118   gchar *retval;
1119
1120   if (vals == NULL) {
1121     retval = g_strdup ("[ 0/1, 0/1 ]");
1122   } else {
1123     gchar *start, *end;
1124
1125     start = gst_value_serialize_fraction (&vals[0]);
1126     end = gst_value_serialize_fraction (&vals[1]);
1127
1128     retval = g_strdup_printf ("[ %s, %s ]", start, end);
1129     g_free (start);
1130     g_free (end);
1131   }
1132
1133   return retval;
1134 }
1135
1136 static void
1137 gst_value_transform_fraction_range_string (const GValue * src_value,
1138     GValue * dest_value)
1139 {
1140   dest_value->data[0].v_pointer =
1141       gst_value_serialize_fraction_range (src_value);
1142 }
1143
1144 static gint
1145 gst_value_compare_fraction_range (const GValue * value1, const GValue * value2)
1146 {
1147   GValue *vals1, *vals2;
1148
1149   if (value2->data[0].v_pointer == value1->data[0].v_pointer)
1150     return GST_VALUE_EQUAL;     /* Only possible if both are NULL */
1151
1152   if (value2->data[0].v_pointer == NULL || value1->data[0].v_pointer == NULL)
1153     return GST_VALUE_UNORDERED;
1154
1155   vals1 = (GValue *) value1->data[0].v_pointer;
1156   vals2 = (GValue *) value2->data[0].v_pointer;
1157   if (gst_value_compare (&vals1[0], &vals2[0]) == GST_VALUE_EQUAL &&
1158       gst_value_compare (&vals1[1], &vals2[1]) == GST_VALUE_EQUAL)
1159     return GST_VALUE_EQUAL;
1160
1161   return GST_VALUE_UNORDERED;
1162 }
1163
1164 static gboolean
1165 gst_value_deserialize_fraction_range (GValue * dest, const gchar * s)
1166 {
1167   g_warning ("unimplemented");
1168   return FALSE;
1169 }
1170
1171 /***********
1172  * GstCaps *
1173  ***********/
1174
1175 /**
1176  * gst_value_set_caps:
1177  * @value: a GValue initialized to GST_TYPE_CAPS
1178  * @caps: the caps to set the value to
1179  *
1180  * Sets the contents of @value to coorespond to @caps.  The actual
1181  * #GstCaps structure is copied before it is used.
1182  */
1183 void
1184 gst_value_set_caps (GValue * value, const GstCaps * caps)
1185 {
1186   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS);
1187
1188   g_value_set_boxed (value, caps);
1189 }
1190
1191 /**
1192  * gst_value_get_caps:
1193  * @value: a GValue initialized to GST_TYPE_CAPS
1194  *
1195  * Gets the contents of @value.
1196  *
1197  * Returns: the contents of @value
1198  */
1199 const GstCaps *
1200 gst_value_get_caps (const GValue * value)
1201 {
1202   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS, NULL);
1203
1204   return (GstCaps *) g_value_get_boxed (value);
1205 }
1206
1207 static char *
1208 gst_value_serialize_caps (const GValue * value)
1209 {
1210   GstCaps *caps = g_value_get_boxed (value);
1211
1212   return gst_caps_to_string (caps);
1213 }
1214
1215 static gboolean
1216 gst_value_deserialize_caps (GValue * dest, const gchar * s)
1217 {
1218   GstCaps *caps;
1219
1220   caps = gst_caps_from_string (s);
1221
1222   if (caps) {
1223     g_value_set_boxed (dest, caps);
1224     return TRUE;
1225   }
1226   return FALSE;
1227 }
1228
1229
1230 /*************
1231  * GstBuffer *
1232  *************/
1233
1234 static int
1235 gst_value_compare_buffer (const GValue * value1, const GValue * value2)
1236 {
1237   GstBuffer *buf1 = GST_BUFFER (gst_value_get_mini_object (value1));
1238   GstBuffer *buf2 = GST_BUFFER (gst_value_get_mini_object (value2));
1239
1240   if (GST_BUFFER_SIZE (buf1) != GST_BUFFER_SIZE (buf2))
1241     return GST_VALUE_UNORDERED;
1242   if (GST_BUFFER_SIZE (buf1) == 0)
1243     return GST_VALUE_EQUAL;
1244   g_assert (GST_BUFFER_DATA (buf1));
1245   g_assert (GST_BUFFER_DATA (buf2));
1246   if (memcmp (GST_BUFFER_DATA (buf1), GST_BUFFER_DATA (buf2),
1247           GST_BUFFER_SIZE (buf1)) == 0)
1248     return GST_VALUE_EQUAL;
1249
1250   return GST_VALUE_UNORDERED;
1251 }
1252
1253 static char *
1254 gst_value_serialize_buffer (const GValue * value)
1255 {
1256   guint8 *data;
1257   int i;
1258   int size;
1259   char *string;
1260   GstBuffer *buffer = GST_BUFFER (gst_value_get_mini_object (value));
1261
1262   data = GST_BUFFER_DATA (buffer);
1263   size = GST_BUFFER_SIZE (buffer);
1264
1265   string = g_malloc (size * 2 + 1);
1266   for (i = 0; i < size; i++) {
1267     sprintf (string + i * 2, "%02x", data[i]);
1268   }
1269   string[size * 2] = 0;
1270
1271   return string;
1272 }
1273
1274 static gboolean
1275 gst_value_deserialize_buffer (GValue * dest, const gchar * s)
1276 {
1277   GstBuffer *buffer;
1278   gboolean ret = TRUE;
1279   int len;
1280   char ts[3];
1281   guint8 *data;
1282   int i;
1283
1284   len = strlen (s);
1285   if (len & 1)
1286     return FALSE;
1287   buffer = gst_buffer_new_and_alloc (len / 2);
1288   data = GST_BUFFER_DATA (buffer);
1289   for (i = 0; i < len / 2; i++) {
1290     if (!isxdigit ((int) s[i * 2]) || !isxdigit ((int) s[i * 2 + 1])) {
1291       ret = FALSE;
1292       break;
1293     }
1294     ts[0] = s[i * 2 + 0];
1295     ts[1] = s[i * 2 + 1];
1296     ts[2] = 0;
1297
1298     data[i] = (guint8) strtoul (ts, NULL, 16);
1299   }
1300
1301   if (ret) {
1302     gst_value_take_mini_object (dest, GST_MINI_OBJECT (buffer));
1303     return TRUE;
1304   } else {
1305     gst_buffer_unref (buffer);
1306     return FALSE;
1307   }
1308 }
1309
1310
1311 /***********
1312  * boolean *
1313  ***********/
1314
1315 static int
1316 gst_value_compare_boolean (const GValue * value1, const GValue * value2)
1317 {
1318   if ((value1->data[0].v_int != 0) == (value2->data[0].v_int != 0))
1319     return GST_VALUE_EQUAL;
1320   return GST_VALUE_UNORDERED;
1321 }
1322
1323 static char *
1324 gst_value_serialize_boolean (const GValue * value)
1325 {
1326   if (value->data[0].v_int) {
1327     return g_strdup ("true");
1328   }
1329   return g_strdup ("false");
1330 }
1331
1332 static gboolean
1333 gst_value_deserialize_boolean (GValue * dest, const gchar * s)
1334 {
1335   gboolean ret = FALSE;
1336
1337   if (g_ascii_strcasecmp (s, "true") == 0 ||
1338       g_ascii_strcasecmp (s, "yes") == 0 ||
1339       g_ascii_strcasecmp (s, "t") == 0 || strcmp (s, "1") == 0) {
1340     g_value_set_boolean (dest, TRUE);
1341     ret = TRUE;
1342   } else if (g_ascii_strcasecmp (s, "false") == 0 ||
1343       g_ascii_strcasecmp (s, "no") == 0 ||
1344       g_ascii_strcasecmp (s, "f") == 0 || strcmp (s, "0") == 0) {
1345     g_value_set_boolean (dest, FALSE);
1346     ret = TRUE;
1347   }
1348
1349   return ret;
1350 }
1351
1352 #define CREATE_SERIALIZATION_START(_type,_macro)                        \
1353 static gint                                                             \
1354 gst_value_compare_ ## _type                                             \
1355 (const GValue * value1, const GValue * value2)                          \
1356 {                                                                       \
1357   g ## _type val1 = g_value_get_ ## _type (value1);                     \
1358   g ## _type val2 = g_value_get_ ## _type (value2);                     \
1359   if (val1 > val2)                                                      \
1360     return GST_VALUE_GREATER_THAN;                                      \
1361   if (val1 < val2)                                                      \
1362     return GST_VALUE_LESS_THAN;                                         \
1363   return GST_VALUE_EQUAL;                                               \
1364 }                                                                       \
1365                                                                         \
1366 static char *                                                           \
1367 gst_value_serialize_ ## _type (const GValue * value)                    \
1368 {                                                                       \
1369   GValue val = { 0, };                                                  \
1370   g_value_init (&val, G_TYPE_STRING);                                   \
1371   if (!g_value_transform (value, &val))                                 \
1372     g_assert_not_reached ();                                            \
1373   /* NO_COPY_MADNESS!!! */                                              \
1374   return (char *) g_value_get_string (&val);                            \
1375 }
1376
1377 /* deserialize the given s into to as a gint64.
1378  * check if the result is actually storeable in the given size number of
1379  * bytes.
1380  */
1381 static gboolean
1382 gst_value_deserialize_int_helper (gint64 * to, const gchar * s,
1383     gint64 min, gint64 max, gint size)
1384 {
1385   gboolean ret = FALSE;
1386   char *end;
1387   gint64 mask = -1;
1388
1389   errno = 0;
1390   *to = g_ascii_strtoull (s, &end, 0);
1391   /* a range error is a definitive no-no */
1392   if (errno == ERANGE) {
1393     return FALSE;
1394   }
1395
1396   if (*end == 0) {
1397     ret = TRUE;
1398   } else {
1399     if (g_ascii_strcasecmp (s, "little_endian") == 0) {
1400       *to = G_LITTLE_ENDIAN;
1401       ret = TRUE;
1402     } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {
1403       *to = G_BIG_ENDIAN;
1404       ret = TRUE;
1405     } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {
1406       *to = G_BYTE_ORDER;
1407       ret = TRUE;
1408     } else if (g_ascii_strcasecmp (s, "min") == 0) {
1409       *to = min;
1410       ret = TRUE;
1411     } else if (g_ascii_strcasecmp (s, "max") == 0) {
1412       *to = max;
1413       ret = TRUE;
1414     }
1415   }
1416   if (ret) {
1417     /* by definition, a gint64 fits into a gint64; so ignore those */
1418     if (size != sizeof (mask)) {
1419       if (*to >= 0) {
1420         /* for positive numbers, we create a mask of 1's outside of the range
1421          * and 0's inside the range.  An and will thus keep only 1 bits
1422          * outside of the range */
1423         mask <<= (size * 8);
1424         if ((mask & *to) != 0) {
1425           ret = FALSE;
1426         }
1427       } else {
1428         /* for negative numbers, we do a 2's complement version */
1429         mask <<= ((size * 8) - 1);
1430         if ((mask & *to) != mask) {
1431           ret = FALSE;
1432         }
1433       }
1434     }
1435   }
1436   return ret;
1437 }
1438
1439 #define CREATE_SERIALIZATION(_type,_macro)                              \
1440 CREATE_SERIALIZATION_START(_type,_macro)                                \
1441                                                                         \
1442 static gboolean                                                         \
1443 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s)         \
1444 {                                                                       \
1445   gint64 x;                                                             \
1446                                                                         \
1447   if (gst_value_deserialize_int_helper (&x, s, G_MIN ## _macro,         \
1448       G_MAX ## _macro, sizeof (g ## _type))) {                          \
1449     g_value_set_ ## _type (dest, /*(g ## _type)*/ x);                   \
1450     return TRUE;                                                        \
1451   } else {                                                              \
1452     return FALSE;                                                       \
1453   }                                                                     \
1454 }
1455
1456 #define CREATE_USERIALIZATION(_type,_macro)                             \
1457 CREATE_SERIALIZATION_START(_type,_macro)                                \
1458                                                                         \
1459 static gboolean                                                         \
1460 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s)         \
1461 {                                                                       \
1462   gint64 x;                                                             \
1463   char *end;                                                            \
1464   gboolean ret = FALSE;                                                 \
1465                                                                         \
1466   errno = 0;                                                            \
1467   x = g_ascii_strtoull (s, &end, 0);                                    \
1468   /* a range error is a definitive no-no */                             \
1469   if (errno == ERANGE) {                                                \
1470     return FALSE;                                                       \
1471   }                                                                     \
1472   /* the cast ensures the range check later on makes sense */           \
1473   x = (g ## _type) x;                                                   \
1474   if (*end == 0) {                                                      \
1475     ret = TRUE;                                                         \
1476   } else {                                                              \
1477     if (g_ascii_strcasecmp (s, "little_endian") == 0) {                 \
1478       x = G_LITTLE_ENDIAN;                                              \
1479       ret = TRUE;                                                       \
1480     } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {             \
1481       x = G_BIG_ENDIAN;                                                 \
1482       ret = TRUE;                                                       \
1483     } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {             \
1484       x = G_BYTE_ORDER;                                                 \
1485       ret = TRUE;                                                       \
1486     } else if (g_ascii_strcasecmp (s, "min") == 0) {                    \
1487       x = 0;                                                            \
1488       ret = TRUE;                                                       \
1489     } else if (g_ascii_strcasecmp (s, "max") == 0) {                    \
1490       x = G_MAX ## _macro;                                              \
1491       ret = TRUE;                                                       \
1492     }                                                                   \
1493   }                                                                     \
1494   if (ret) {                                                            \
1495     if (x > G_MAX ## _macro) {                                          \
1496       ret = FALSE;                                                      \
1497     } else {                                                            \
1498       g_value_set_ ## _type (dest, x);                                  \
1499     }                                                                   \
1500   }                                                                     \
1501   return ret;                                                           \
1502 }
1503
1504 #define REGISTER_SERIALIZATION(_gtype, _type)                           \
1505 G_STMT_START {                                                          \
1506   static const GstValueTable gst_value = {                              \
1507     _gtype,                                                             \
1508     gst_value_compare_ ## _type,                                        \
1509     gst_value_serialize_ ## _type,                                      \
1510     gst_value_deserialize_ ## _type,                                    \
1511   };                                                                    \
1512                                                                         \
1513   gst_value_register (&gst_value);                                      \
1514 } G_STMT_END
1515
1516 CREATE_SERIALIZATION (int, INT);
1517 CREATE_SERIALIZATION (int64, INT64);
1518 CREATE_SERIALIZATION (long, LONG);
1519
1520 CREATE_USERIALIZATION (uint, UINT);
1521 CREATE_USERIALIZATION (uint64, UINT64);
1522 CREATE_USERIALIZATION (ulong, ULONG);
1523
1524 /**********
1525  * double *
1526  **********/
1527 static int
1528 gst_value_compare_double (const GValue * value1, const GValue * value2)
1529 {
1530   if (value1->data[0].v_double > value2->data[0].v_double)
1531     return GST_VALUE_GREATER_THAN;
1532   if (value1->data[0].v_double < value2->data[0].v_double)
1533     return GST_VALUE_LESS_THAN;
1534   if (value1->data[0].v_double == value2->data[0].v_double)
1535     return GST_VALUE_EQUAL;
1536   return GST_VALUE_UNORDERED;
1537 }
1538
1539 static char *
1540 gst_value_serialize_double (const GValue * value)
1541 {
1542   char d[G_ASCII_DTOSTR_BUF_SIZE];
1543
1544   g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
1545   return g_strdup (d);
1546 }
1547
1548 static gboolean
1549 gst_value_deserialize_double (GValue * dest, const gchar * s)
1550 {
1551   double x;
1552   gboolean ret = FALSE;
1553   char *end;
1554
1555   x = g_ascii_strtod (s, &end);
1556   if (*end == 0) {
1557     ret = TRUE;
1558   } else {
1559     if (g_ascii_strcasecmp (s, "min") == 0) {
1560       x = -G_MAXDOUBLE;
1561       ret = TRUE;
1562     } else if (g_ascii_strcasecmp (s, "max") == 0) {
1563       x = G_MAXDOUBLE;
1564       ret = TRUE;
1565     }
1566   }
1567   if (ret) {
1568     g_value_set_double (dest, x);
1569   }
1570   return ret;
1571 }
1572
1573 /*********
1574  * float *
1575  *********/
1576
1577 static gint
1578 gst_value_compare_float (const GValue * value1, const GValue * value2)
1579 {
1580   if (value1->data[0].v_float > value2->data[0].v_float)
1581     return GST_VALUE_GREATER_THAN;
1582   if (value1->data[0].v_float < value2->data[0].v_float)
1583     return GST_VALUE_LESS_THAN;
1584   if (value1->data[0].v_float == value2->data[0].v_float)
1585     return GST_VALUE_EQUAL;
1586   return GST_VALUE_UNORDERED;
1587 }
1588
1589 static gchar *
1590 gst_value_serialize_float (const GValue * value)
1591 {
1592   gchar d[G_ASCII_DTOSTR_BUF_SIZE];
1593
1594   g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_float);
1595   return g_strdup (d);
1596 }
1597
1598 static gboolean
1599 gst_value_deserialize_float (GValue * dest, const gchar * s)
1600 {
1601   double x;
1602   gboolean ret = FALSE;
1603   char *end;
1604
1605   x = g_ascii_strtod (s, &end);
1606   if (*end == 0) {
1607     ret = TRUE;
1608   } else {
1609     if (g_ascii_strcasecmp (s, "min") == 0) {
1610       x = -G_MAXFLOAT;
1611       ret = TRUE;
1612     } else if (g_ascii_strcasecmp (s, "max") == 0) {
1613       x = G_MAXFLOAT;
1614       ret = TRUE;
1615     }
1616   }
1617   if (x > G_MAXFLOAT || x < -G_MAXFLOAT)
1618     ret = FALSE;
1619   if (ret) {
1620     g_value_set_float (dest, (float) x);
1621   }
1622   return ret;
1623 }
1624
1625 /**********
1626  * string *
1627  **********/
1628
1629 static gint
1630 gst_value_compare_string (const GValue * value1, const GValue * value2)
1631 {
1632   int x = strcmp (value1->data[0].v_pointer, value2->data[0].v_pointer);
1633
1634   if (x < 0)
1635     return GST_VALUE_LESS_THAN;
1636   if (x > 0)
1637     return GST_VALUE_GREATER_THAN;
1638   return GST_VALUE_EQUAL;
1639 }
1640
1641 #define GST_ASCII_IS_STRING(c) (g_ascii_isalnum((c)) || ((c) == '_') || \
1642     ((c) == '-') || ((c) == '+') || ((c) == '/') || ((c) == ':') || \
1643     ((c) == '.'))
1644
1645 static gchar *
1646 gst_string_wrap (const gchar * s)
1647 {
1648   const gchar *t;
1649   int len;
1650   gchar *d, *e;
1651   gboolean wrap = FALSE;
1652
1653   len = 0;
1654   t = s;
1655   if (!s)
1656     return NULL;
1657   while (*t) {
1658     if (GST_ASCII_IS_STRING (*t)) {
1659       len++;
1660     } else if (*t < 0x20 || *t >= 0x7f) {
1661       wrap = TRUE;
1662       len += 4;
1663     } else {
1664       wrap = TRUE;
1665       len += 2;
1666     }
1667     t++;
1668   }
1669
1670   if (!wrap)
1671     return g_strdup (s);
1672
1673   e = d = g_malloc (len + 3);
1674
1675   *e++ = '\"';
1676   t = s;
1677   while (*t) {
1678     if (GST_ASCII_IS_STRING (*t)) {
1679       *e++ = *t++;
1680     } else if (*t < 0x20 || *t >= 0x7f) {
1681       *e++ = '\\';
1682       *e++ = '0' + ((*(guchar *) t) >> 6);
1683       *e++ = '0' + (((*t) >> 3) & 0x7);
1684       *e++ = '0' + ((*t++) & 0x7);
1685     } else {
1686       *e++ = '\\';
1687       *e++ = *t++;
1688     }
1689   }
1690   *e++ = '\"';
1691   *e = 0;
1692
1693   return d;
1694 }
1695
1696 /*
1697  * This function takes a string delimited with double quotes (")
1698  * and unescapes any \xxx octal numbers.
1699  *
1700  * If sequences of \y are found where y is not in the range of
1701  * 0->3, y is copied unescaped.
1702  *
1703  * If \xyy is found where x is an octal number but y is not, an
1704  * error is encountered and NULL is returned.
1705  *
1706  * the input string must be \0 terminated.
1707  */
1708 static gchar *
1709 gst_string_unwrap (const gchar * s)
1710 {
1711   gchar *ret;
1712   gchar *read, *write;
1713
1714   /* NULL string returns NULL */
1715   if (s == NULL)
1716     return NULL;
1717
1718   /* strings not starting with " are invalid */
1719   if (*s != '"')
1720     return NULL;
1721
1722   /* make copy of original string to hold the result. This
1723    * string will always be smaller than the original */
1724   ret = g_strdup (s);
1725   read = ret;
1726   write = ret;
1727
1728   /* need to move to the next position as we parsed the " */
1729   read++;
1730
1731   while (*read) {
1732     if (GST_ASCII_IS_STRING (*read)) {
1733       /* normal chars are just copied */
1734       *write++ = *read++;
1735     } else if (*read == '"') {
1736       /* quote marks end of string */
1737       break;
1738     } else if (*read == '\\') {
1739       /* got an escape char, move to next position to read a tripplet
1740        * of octal numbers */
1741       read++;
1742       /* is the next char a possible first octal number? */
1743       if (*read >= '0' && *read <= '3') {
1744         /* parse other 2 numbers, if one of them is not in the range of
1745          * an octal number, we error. We also catch the case where a zero
1746          * byte is found here. */
1747         if (read[1] < '0' || read[1] > '7' || read[2] < '0' || read[2] > '7')
1748           goto beach;
1749
1750         /* now convert the octal number to a byte again. */
1751         *write++ = ((read[0] - '0') << 6) +
1752             ((read[1] - '0') << 3) + (read[2] - '0');
1753
1754         read += 3;
1755       } else {
1756         /* if we run into a \0 here, we definately won't get a quote later */
1757         if (*read == 0)
1758           goto beach;
1759
1760         /* else copy \X sequence */
1761         *write++ = *read++;
1762       }
1763     } else {
1764       /* weird character, error */
1765       goto beach;
1766     }
1767   }
1768   /* if the string is not ending in " and zero terminated, we error */
1769   if (*read != '"' || read[1] != '\0')
1770     goto beach;
1771
1772   /* null terminate result string and return */
1773   *write++ = '\0';
1774   return ret;
1775
1776 beach:
1777   g_free (ret);
1778   return NULL;
1779 }
1780
1781 static gchar *
1782 gst_value_serialize_string (const GValue * value)
1783 {
1784   return gst_string_wrap (value->data[0].v_pointer);
1785 }
1786
1787 static gboolean
1788 gst_value_deserialize_string (GValue * dest, const gchar * s)
1789 {
1790   if (*s != '"') {
1791     if (!g_utf8_validate (s, -1, NULL))
1792       return FALSE;
1793     g_value_set_string (dest, s);
1794     return TRUE;
1795   } else {
1796     gchar *str = gst_string_unwrap (s);
1797
1798     if (!str)
1799       return FALSE;
1800     g_value_take_string (dest, str);
1801   }
1802
1803   return TRUE;
1804 }
1805
1806 /********
1807  * enum *
1808  ********/
1809
1810 static gint
1811 gst_value_compare_enum (const GValue * value1, const GValue * value2)
1812 {
1813   GEnumValue *en1, *en2;
1814   GEnumClass *klass1 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value1));
1815   GEnumClass *klass2 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value2));
1816
1817   g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
1818   g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
1819   en1 = g_enum_get_value (klass1, g_value_get_enum (value1));
1820   en2 = g_enum_get_value (klass2, g_value_get_enum (value2));
1821   g_type_class_unref (klass1);
1822   g_type_class_unref (klass2);
1823   g_return_val_if_fail (en1, GST_VALUE_UNORDERED);
1824   g_return_val_if_fail (en2, GST_VALUE_UNORDERED);
1825   if (en1->value < en2->value)
1826     return GST_VALUE_LESS_THAN;
1827   if (en1->value > en2->value)
1828     return GST_VALUE_GREATER_THAN;
1829
1830   return GST_VALUE_EQUAL;
1831 }
1832
1833 static gchar *
1834 gst_value_serialize_enum (const GValue * value)
1835 {
1836   GEnumValue *en;
1837   GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value));
1838
1839   g_return_val_if_fail (klass, NULL);
1840   en = g_enum_get_value (klass, g_value_get_enum (value));
1841   g_type_class_unref (klass);
1842   g_return_val_if_fail (en, NULL);
1843   return g_strdup (en->value_name);
1844 }
1845
1846 static gboolean
1847 gst_value_deserialize_enum (GValue * dest, const gchar * s)
1848 {
1849   GEnumValue *en;
1850   gchar *endptr = NULL;
1851   GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (dest));
1852
1853   g_return_val_if_fail (klass, FALSE);
1854   if (!(en = g_enum_get_value_by_name (klass, s))) {
1855     if (!(en = g_enum_get_value_by_nick (klass, s))) {
1856       gint i = strtol (s, &endptr, 0);
1857
1858       if (endptr && *endptr == '\0') {
1859         en = g_enum_get_value (klass, i);
1860       }
1861     }
1862   }
1863   g_type_class_unref (klass);
1864   g_return_val_if_fail (en, FALSE);
1865   g_value_set_enum (dest, en->value);
1866   return TRUE;
1867 }
1868
1869 /********
1870  * flags *
1871  ********/
1872
1873 /* we just compare the value here */
1874 static gint
1875 gst_value_compare_flags (const GValue * value1, const GValue * value2)
1876 {
1877   guint fl1, fl2;
1878   GFlagsClass *klass1 =
1879       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value1));
1880   GFlagsClass *klass2 =
1881       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value2));
1882
1883   g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
1884   g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
1885   fl1 = g_value_get_flags (value1);
1886   fl2 = g_value_get_flags (value2);
1887   g_type_class_unref (klass1);
1888   g_type_class_unref (klass2);
1889   if (fl1 < fl2)
1890     return GST_VALUE_LESS_THAN;
1891   if (fl1 > fl2)
1892     return GST_VALUE_GREATER_THAN;
1893
1894   return GST_VALUE_EQUAL;
1895 }
1896
1897 /* the different flags are serialized separated with a + */
1898 static gchar *
1899 gst_value_serialize_flags (const GValue * value)
1900 {
1901   guint flags;
1902   GFlagsValue *fl;
1903   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value));
1904   gchar *result, *tmp;
1905   gboolean first = TRUE;
1906
1907   g_return_val_if_fail (klass, NULL);
1908
1909   result = g_strdup ("");
1910   flags = g_value_get_flags (value);
1911   while (flags) {
1912     fl = gst_flags_get_first_value (klass, flags);
1913     if (fl != NULL) {
1914       tmp = g_strconcat (result, (first ? "" : "+"), fl->value_name, NULL);
1915       g_free (result);
1916       result = tmp;
1917       first = FALSE;
1918     }
1919     /* clear flag */
1920     flags &= ~fl->value;
1921   }
1922   g_type_class_unref (klass);
1923
1924   return result;
1925 }
1926
1927 static gboolean
1928 gst_value_deserialize_flags (GValue * dest, const gchar * s)
1929 {
1930   GFlagsValue *fl;
1931   gchar *endptr = NULL;
1932   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (dest));
1933   gchar **split;
1934   guint flags;
1935   gint i;
1936
1937   g_return_val_if_fail (klass, FALSE);
1938
1939   /* split into parts delimited with + */
1940   split = g_strsplit (s, "+", 0);
1941
1942   flags = 0;
1943   i = 0;
1944   /* loop over each part */
1945   while (split[i]) {
1946     if (!(fl = g_flags_get_value_by_name (klass, split[i]))) {
1947       if (!(fl = g_flags_get_value_by_nick (klass, split[i]))) {
1948         gint val = strtol (split[i], &endptr, 0);
1949
1950         /* just or numeric value */
1951         if (endptr && *endptr == '\0') {
1952           flags |= val;
1953         }
1954       }
1955     }
1956     if (fl) {
1957       flags |= fl->value;
1958     }
1959     i++;
1960   }
1961   g_strfreev (split);
1962   g_type_class_unref (klass);
1963   g_value_set_flags (dest, flags);
1964
1965   return TRUE;
1966 }
1967
1968 /*********
1969  * union *
1970  *********/
1971
1972 static gboolean
1973 gst_value_union_int_int_range (GValue * dest, const GValue * src1,
1974     const GValue * src2)
1975 {
1976   if (src2->data[0].v_int <= src1->data[0].v_int &&
1977       src2->data[1].v_int >= src1->data[0].v_int) {
1978     gst_value_init_and_copy (dest, src2);
1979     return TRUE;
1980   }
1981   return FALSE;
1982 }
1983
1984 static gboolean
1985 gst_value_union_int_range_int_range (GValue * dest, const GValue * src1,
1986     const GValue * src2)
1987 {
1988   gint min;
1989   gint max;
1990
1991   min = MAX (src1->data[0].v_int, src2->data[0].v_int);
1992   max = MIN (src1->data[1].v_int, src2->data[1].v_int);
1993
1994   if (min <= max) {
1995     g_value_init (dest, GST_TYPE_INT_RANGE);
1996     gst_value_set_int_range (dest,
1997         MIN (src1->data[0].v_int, src2->data[0].v_int),
1998         MAX (src1->data[1].v_int, src2->data[1].v_int));
1999     return TRUE;
2000   }
2001
2002   return FALSE;
2003 }
2004
2005 /****************
2006  * intersection *
2007  ****************/
2008
2009 static gboolean
2010 gst_value_intersect_int_int_range (GValue * dest, const GValue * src1,
2011     const GValue * src2)
2012 {
2013   if (src2->data[0].v_int <= src1->data[0].v_int &&
2014       src2->data[1].v_int >= src1->data[0].v_int) {
2015     gst_value_init_and_copy (dest, src1);
2016     return TRUE;
2017   }
2018
2019   return FALSE;
2020 }
2021
2022 static gboolean
2023 gst_value_intersect_int_range_int_range (GValue * dest, const GValue * src1,
2024     const GValue * src2)
2025 {
2026   gint min;
2027   gint max;
2028
2029   min = MAX (src1->data[0].v_int, src2->data[0].v_int);
2030   max = MIN (src1->data[1].v_int, src2->data[1].v_int);
2031
2032   if (min < max) {
2033     g_value_init (dest, GST_TYPE_INT_RANGE);
2034     gst_value_set_int_range (dest, min, max);
2035     return TRUE;
2036   }
2037   if (min == max) {
2038     g_value_init (dest, G_TYPE_INT);
2039     g_value_set_int (dest, min);
2040     return TRUE;
2041   }
2042
2043   return FALSE;
2044 }
2045
2046 static gboolean
2047 gst_value_intersect_double_double_range (GValue * dest, const GValue * src1,
2048     const GValue * src2)
2049 {
2050   if (src2->data[0].v_double <= src1->data[0].v_double &&
2051       src2->data[1].v_double >= src1->data[0].v_double) {
2052     gst_value_init_and_copy (dest, src1);
2053     return TRUE;
2054   }
2055
2056   return FALSE;
2057 }
2058
2059 static gboolean
2060 gst_value_intersect_double_range_double_range (GValue * dest,
2061     const GValue * src1, const GValue * src2)
2062 {
2063   gdouble min;
2064   gdouble max;
2065
2066   min = MAX (src1->data[0].v_double, src2->data[0].v_double);
2067   max = MIN (src1->data[1].v_double, src2->data[1].v_double);
2068
2069   if (min < max) {
2070     g_value_init (dest, GST_TYPE_DOUBLE_RANGE);
2071     gst_value_set_double_range (dest, min, max);
2072     return TRUE;
2073   }
2074   if (min == max) {
2075     g_value_init (dest, G_TYPE_DOUBLE);
2076     g_value_set_int (dest, (int) min);
2077     return TRUE;
2078   }
2079
2080   return FALSE;
2081 }
2082
2083 static gboolean
2084 gst_value_intersect_list (GValue * dest, const GValue * value1,
2085     const GValue * value2)
2086 {
2087   guint i, size;
2088   GValue intersection = { 0, };
2089   gboolean ret = FALSE;
2090
2091   size = gst_value_list_get_size (value1);
2092   for (i = 0; i < size; i++) {
2093     const GValue *cur = gst_value_list_get_value (value1, i);
2094
2095     if (gst_value_intersect (&intersection, cur, value2)) {
2096       /* append value */
2097       if (!ret) {
2098         gst_value_init_and_copy (dest, &intersection);
2099         ret = TRUE;
2100       } else if (GST_VALUE_HOLDS_LIST (dest)) {
2101         gst_value_list_append_value (dest, &intersection);
2102       } else {
2103         GValue temp = { 0, };
2104
2105         gst_value_init_and_copy (&temp, dest);
2106         g_value_unset (dest);
2107         gst_value_list_concat (dest, &temp, &intersection);
2108         g_value_unset (&temp);
2109       }
2110       g_value_unset (&intersection);
2111     }
2112   }
2113
2114   return ret;
2115 }
2116
2117 static gboolean
2118 gst_value_intersect_array (GValue * dest, const GValue * src1,
2119     const GValue * src2)
2120 {
2121   guint size;
2122   guint n;
2123   GValue val = { 0 };
2124
2125   /* only works on similar-sized arrays */
2126   size = gst_value_array_get_size (src1);
2127   if (size != gst_value_array_get_size (src2))
2128     return FALSE;
2129   g_value_init (dest, GST_TYPE_ARRAY);
2130
2131   for (n = 0; n < size; n++) {
2132     if (!gst_value_intersect (&val, gst_value_array_get_value (src1, n),
2133             gst_value_array_get_value (src2, n))) {
2134       g_value_unset (dest);
2135       return FALSE;
2136     }
2137     gst_value_array_append_value (dest, &val);
2138     g_value_unset (&val);
2139   }
2140
2141   return TRUE;
2142 }
2143
2144 static gboolean
2145 gst_value_intersect_fraction_fraction_range (GValue * dest, const GValue * src1,
2146     const GValue * src2)
2147 {
2148   int res1, res2;
2149   GValue *vals;
2150
2151   vals = src2->data[0].v_pointer;
2152
2153   if (vals == NULL)
2154     return FALSE;
2155
2156   res1 = gst_value_compare (&vals[0], src1);
2157   res2 = gst_value_compare (&vals[1], src1);
2158
2159   if ((res1 == GST_VALUE_EQUAL || res1 == GST_VALUE_LESS_THAN) &&
2160       (res2 == GST_VALUE_EQUAL || res2 == GST_VALUE_GREATER_THAN)) {
2161     gst_value_init_and_copy (dest, src1);
2162     return TRUE;
2163   }
2164
2165   return FALSE;
2166 }
2167
2168 static gboolean
2169     gst_value_intersect_fraction_range_fraction_range
2170     (GValue * dest, const GValue * src1, const GValue * src2)
2171 {
2172   GValue *min;
2173   GValue *max;
2174   int res;
2175   GValue *vals1, *vals2;
2176
2177   vals1 = src1->data[0].v_pointer;
2178   vals2 = src2->data[0].v_pointer;
2179   g_return_val_if_fail (vals1 != NULL && vals2 != NULL, FALSE);
2180
2181   /* min = MAX (src1.start, src2.start) */
2182   res = gst_value_compare (&vals1[0], &vals2[0]);
2183   g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
2184   if (res == GST_VALUE_LESS_THAN)
2185     min = &vals2[0];            /* Take the max of the 2 */
2186   else
2187     min = &vals1[0];
2188
2189   /* max = MIN (src1.end, src2.end) */
2190   res = gst_value_compare (&vals1[1], &vals2[1]);
2191   g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
2192   if (res == GST_VALUE_GREATER_THAN)
2193     max = &vals2[1];            /* Take the min of the 2 */
2194   else
2195     max = &vals1[1];
2196
2197   res = gst_value_compare (min, max);
2198   g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
2199   if (res == GST_VALUE_LESS_THAN) {
2200     g_value_init (dest, GST_TYPE_FRACTION_RANGE);
2201     vals1 = dest->data[0].v_pointer;
2202     g_value_copy (min, &vals1[0]);
2203     g_value_copy (max, &vals1[1]);
2204     return TRUE;
2205   }
2206   if (res == GST_VALUE_EQUAL) {
2207     gst_value_init_and_copy (dest, min);
2208     return TRUE;
2209   }
2210
2211   return FALSE;
2212 }
2213
2214 /***************
2215  * subtraction *
2216  ***************/
2217
2218 static gboolean
2219 gst_value_subtract_int_int_range (GValue * dest, const GValue * minuend,
2220     const GValue * subtrahend)
2221 {
2222   int min = gst_value_get_int_range_min (subtrahend);
2223   int max = gst_value_get_int_range_max (subtrahend);
2224   int val = g_value_get_int (minuend);
2225
2226   /* subtracting a range from an int only works if the int is not in the
2227    * range */
2228   if (val < min || val > max) {
2229     /* and the result is the int */
2230     gst_value_init_and_copy (dest, minuend);
2231     return TRUE;
2232   }
2233   return FALSE;
2234 }
2235
2236 /* creates a new int range based on input values.
2237  */
2238 static gboolean
2239 gst_value_create_new_range (GValue * dest, gint min1, gint max1, gint min2,
2240     gint max2)
2241 {
2242   GValue v1 = { 0, };
2243   GValue v2 = { 0, };
2244   GValue *pv1, *pv2;            /* yeah, hungarian! */
2245
2246   if (min1 <= max1 && min2 <= max2) {
2247     pv1 = &v1;
2248     pv2 = &v2;
2249   } else if (min1 <= max1) {
2250     pv1 = dest;
2251     pv2 = NULL;
2252   } else if (min2 <= max2) {
2253     pv1 = NULL;
2254     pv2 = dest;
2255   } else {
2256     return FALSE;
2257   }
2258
2259   if (min1 < max1) {
2260     g_value_init (pv1, GST_TYPE_INT_RANGE);
2261     gst_value_set_int_range (pv1, min1, max1);
2262   } else if (min1 == max1) {
2263     g_value_init (pv1, G_TYPE_INT);
2264     g_value_set_int (pv1, min1);
2265   }
2266   if (min2 < max2) {
2267     g_value_init (pv2, GST_TYPE_INT_RANGE);
2268     gst_value_set_int_range (pv2, min2, max2);
2269   } else if (min2 == max2) {
2270     g_value_init (pv2, G_TYPE_INT);
2271     g_value_set_int (pv2, min2);
2272   }
2273
2274   if (min1 <= max1 && min2 <= max2) {
2275     gst_value_list_concat (dest, pv1, pv2);
2276     g_value_unset (pv1);
2277     g_value_unset (pv2);
2278   }
2279   return TRUE;
2280 }
2281
2282 static gboolean
2283 gst_value_subtract_int_range_int (GValue * dest, const GValue * minuend,
2284     const GValue * subtrahend)
2285 {
2286   gint min = gst_value_get_int_range_min (minuend);
2287   gint max = gst_value_get_int_range_max (minuend);
2288   gint val = g_value_get_int (subtrahend);
2289
2290   g_return_val_if_fail (min < max, FALSE);
2291
2292   /* value is outside of the range, return range unchanged */
2293   if (val < min || val > max) {
2294     gst_value_init_and_copy (dest, minuend);
2295     return TRUE;
2296   } else {
2297     /* max must be MAXINT too as val <= max */
2298     if (val == G_MAXINT) {
2299       max--;
2300       val--;
2301     }
2302     /* min must be MININT too as val >= max */
2303     if (val == G_MININT) {
2304       min++;
2305       val++;
2306     }
2307     gst_value_create_new_range (dest, min, val - 1, val + 1, max);
2308   }
2309   return TRUE;
2310 }
2311
2312 static gboolean
2313 gst_value_subtract_int_range_int_range (GValue * dest, const GValue * minuend,
2314     const GValue * subtrahend)
2315 {
2316   gint min1 = gst_value_get_int_range_min (minuend);
2317   gint max1 = gst_value_get_int_range_max (minuend);
2318   gint min2 = gst_value_get_int_range_min (subtrahend);
2319   gint max2 = gst_value_get_int_range_max (subtrahend);
2320
2321   if (max2 == G_MAXINT && min2 == G_MININT) {
2322     return FALSE;
2323   } else if (max2 == G_MAXINT) {
2324     return gst_value_create_new_range (dest, min1, MIN (min2 - 1, max1), 1, 0);
2325   } else if (min2 == G_MININT) {
2326     return gst_value_create_new_range (dest, MAX (max2 + 1, min1), max1, 1, 0);
2327   } else {
2328     return gst_value_create_new_range (dest, min1, MIN (min2 - 1, max1),
2329         MAX (max2 + 1, min1), max1);
2330   }
2331 }
2332
2333 static gboolean
2334 gst_value_subtract_double_double_range (GValue * dest, const GValue * minuend,
2335     const GValue * subtrahend)
2336 {
2337   gdouble min = gst_value_get_double_range_min (subtrahend);
2338   gdouble max = gst_value_get_double_range_max (subtrahend);
2339   gdouble val = g_value_get_double (minuend);
2340
2341   if (val < min || val > max) {
2342     gst_value_init_and_copy (dest, minuend);
2343     return TRUE;
2344   }
2345   return FALSE;
2346 }
2347
2348 static gboolean
2349 gst_value_subtract_double_range_double (GValue * dest, const GValue * minuend,
2350     const GValue * subtrahend)
2351 {
2352   /* since we don't have open ranges, we cannot create a hole in
2353    * a double range. We return the original range */
2354   gst_value_init_and_copy (dest, minuend);
2355   return TRUE;
2356 }
2357
2358 static gboolean
2359 gst_value_subtract_double_range_double_range (GValue * dest,
2360     const GValue * minuend, const GValue * subtrahend)
2361 {
2362   /* since we don't have open ranges, we have to approximate */
2363   /* done like with ints */
2364   gdouble min1 = gst_value_get_double_range_min (minuend);
2365   gdouble max2 = gst_value_get_double_range_max (minuend);
2366   gdouble max1 = MIN (gst_value_get_double_range_min (subtrahend), max2);
2367   gdouble min2 = MAX (gst_value_get_double_range_max (subtrahend), min1);
2368   GValue v1 = { 0, };
2369   GValue v2 = { 0, };
2370   GValue *pv1, *pv2;            /* yeah, hungarian! */
2371
2372   if (min1 < max1 && min2 < max2) {
2373     pv1 = &v1;
2374     pv2 = &v2;
2375   } else if (min1 < max1) {
2376     pv1 = dest;
2377     pv2 = NULL;
2378   } else if (min2 < max2) {
2379     pv1 = NULL;
2380     pv2 = dest;
2381   } else {
2382     return FALSE;
2383   }
2384
2385   if (min1 < max1) {
2386     g_value_init (pv1, GST_TYPE_DOUBLE_RANGE);
2387     gst_value_set_double_range (pv1, min1, max1);
2388   }
2389   if (min2 < max2) {
2390     g_value_init (pv2, GST_TYPE_DOUBLE_RANGE);
2391     gst_value_set_double_range (pv2, min2, max2);
2392   }
2393
2394   if (min1 < max1 && min2 < max2) {
2395     gst_value_list_concat (dest, pv1, pv2);
2396     g_value_unset (pv1);
2397     g_value_unset (pv2);
2398   }
2399   return TRUE;
2400 }
2401
2402 static gboolean
2403 gst_value_subtract_from_list (GValue * dest, const GValue * minuend,
2404     const GValue * subtrahend)
2405 {
2406   guint i, size;
2407   GValue subtraction = { 0, };
2408   gboolean ret = FALSE;
2409
2410   size = gst_value_list_get_size (minuend);
2411   for (i = 0; i < size; i++) {
2412     const GValue *cur = gst_value_list_get_value (minuend, i);
2413
2414     if (gst_value_subtract (&subtraction, cur, subtrahend)) {
2415       if (!ret) {
2416         gst_value_init_and_copy (dest, &subtraction);
2417         ret = TRUE;
2418       } else if (GST_VALUE_HOLDS_LIST (dest)
2419           && GST_VALUE_HOLDS_LIST (&subtraction)) {
2420         /* unroll */
2421         GValue unroll = { 0, };
2422
2423         gst_value_init_and_copy (&unroll, dest);
2424         g_value_unset (dest);
2425         gst_value_list_concat (dest, &unroll, &subtraction);
2426       } else if (GST_VALUE_HOLDS_LIST (dest)) {
2427         gst_value_list_append_value (dest, &subtraction);
2428       } else {
2429         GValue temp = { 0, };
2430
2431         gst_value_init_and_copy (&temp, dest);
2432         g_value_unset (dest);
2433         gst_value_list_concat (dest, &temp, &subtraction);
2434         g_value_unset (&temp);
2435       }
2436       g_value_unset (&subtraction);
2437     }
2438   }
2439   return ret;
2440 }
2441
2442 static gboolean
2443 gst_value_subtract_list (GValue * dest, const GValue * minuend,
2444     const GValue * subtrahend)
2445 {
2446   guint i, size;
2447   GValue data[2] = { {0,}, {0,} };
2448   GValue *subtraction = &data[0], *result = &data[1];
2449
2450   gst_value_init_and_copy (result, minuend);
2451   size = gst_value_list_get_size (subtrahend);
2452   for (i = 0; i < size; i++) {
2453     const GValue *cur = gst_value_list_get_value (subtrahend, i);
2454
2455     if (gst_value_subtract (subtraction, result, cur)) {
2456       GValue *temp = result;
2457
2458       result = subtraction;
2459       subtraction = temp;
2460       g_value_unset (subtraction);
2461     } else {
2462       g_value_unset (result);
2463       return FALSE;
2464     }
2465   }
2466   gst_value_init_and_copy (dest, result);
2467   g_value_unset (result);
2468   return TRUE;
2469 }
2470
2471 static gboolean
2472 gst_value_subtract_fraction_fraction_range (GValue * dest,
2473     const GValue * minuend, const GValue * subtrahend)
2474 {
2475   const GValue *min = gst_value_get_fraction_range_min (subtrahend);
2476   const GValue *max = gst_value_get_fraction_range_max (subtrahend);
2477
2478   /* subtracting a range from an fraction only works if the fraction
2479    * is not in the range */
2480   if (gst_value_compare (minuend, min) == GST_VALUE_LESS_THAN ||
2481       gst_value_compare (minuend, max) == GST_VALUE_GREATER_THAN) {
2482     /* and the result is the value */
2483     gst_value_init_and_copy (dest, minuend);
2484     return TRUE;
2485   }
2486   return FALSE;
2487 }
2488
2489 static gboolean
2490 gst_value_subtract_fraction_range_fraction (GValue * dest,
2491     const GValue * minuend, const GValue * subtrahend)
2492 {
2493   /* since we don't have open ranges, we cannot create a hole in
2494    * a range. We return the original range */
2495   gst_value_init_and_copy (dest, minuend);
2496   return TRUE;
2497 }
2498
2499 static gboolean
2500 gst_value_subtract_fraction_range_fraction_range (GValue * dest,
2501     const GValue * minuend, const GValue * subtrahend)
2502 {
2503   /* since we don't have open ranges, we have to approximate */
2504   /* done like with ints and doubles. Creates a list of 2 fraction ranges */
2505   const GValue *min1 = gst_value_get_fraction_range_min (minuend);
2506   const GValue *max2 = gst_value_get_fraction_range_max (minuend);
2507   const GValue *max1 = gst_value_get_fraction_range_min (subtrahend);
2508   const GValue *min2 = gst_value_get_fraction_range_max (subtrahend);
2509   int cmp1, cmp2;
2510   GValue v1 = { 0, };
2511   GValue v2 = { 0, };
2512   GValue *pv1, *pv2;            /* yeah, hungarian! */
2513
2514   g_return_val_if_fail (min1 != NULL && max1 != NULL, FALSE);
2515   g_return_val_if_fail (min2 != NULL && max2 != NULL, FALSE);
2516
2517   cmp1 = gst_value_compare (max2, max1);
2518   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
2519   if (cmp1 == GST_VALUE_LESS_THAN)
2520     max1 = max2;
2521   cmp1 = gst_value_compare (min1, min2);
2522   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
2523   if (cmp1 == GST_VALUE_GREATER_THAN)
2524     min2 = min1;
2525
2526   cmp1 = gst_value_compare (min1, max1);
2527   cmp2 = gst_value_compare (min2, max2);
2528
2529   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
2530     pv1 = &v1;
2531     pv2 = &v2;
2532   } else if (cmp1 == GST_VALUE_LESS_THAN) {
2533     pv1 = dest;
2534     pv2 = NULL;
2535   } else if (cmp2 == GST_VALUE_LESS_THAN) {
2536     pv1 = NULL;
2537     pv2 = dest;
2538   } else {
2539     return FALSE;
2540   }
2541
2542   if (cmp1 == GST_VALUE_LESS_THAN) {
2543     g_value_init (pv1, GST_TYPE_FRACTION_RANGE);
2544     gst_value_set_fraction_range (pv1, min1, max1);
2545   }
2546   if (cmp2 == GST_VALUE_LESS_THAN) {
2547     g_value_init (pv2, GST_TYPE_FRACTION_RANGE);
2548     gst_value_set_fraction_range (pv2, min2, max2);
2549   }
2550
2551   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
2552     gst_value_list_concat (dest, pv1, pv2);
2553     g_value_unset (pv1);
2554     g_value_unset (pv2);
2555   }
2556   return TRUE;
2557 }
2558
2559
2560 /**************
2561  * comparison *
2562  **************/
2563
2564 /**
2565  * gst_value_can_compare:
2566  * @value1: a value to compare
2567  * @value2: another value to compare
2568  *
2569  * Determines if @value1 and @value2 can be compared.
2570  *
2571  * Returns: TRUE if the values can be compared
2572  */
2573 gboolean
2574 gst_value_can_compare (const GValue * value1, const GValue * value2)
2575 {
2576   GstValueTable *table;
2577   guint i;
2578
2579   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
2580     return FALSE;
2581
2582   for (i = 0; i < gst_value_table->len; i++) {
2583     table = &g_array_index (gst_value_table, GstValueTable, i);
2584     if (g_type_is_a (G_VALUE_TYPE (value1), table->type) && table->compare)
2585       return TRUE;
2586   }
2587
2588   return FALSE;
2589 }
2590
2591 /**
2592  * gst_value_compare:
2593  * @value1: a value to compare
2594  * @value2: another value to compare
2595  *
2596  * Compares @value1 and @value2.  If @value1 and @value2 cannot be
2597  * compared, the function returns GST_VALUE_UNORDERED.  Otherwise,
2598  * if @value1 is greater than @value2, GST_VALUE_GREATER is returned.
2599  * If @value1 is less than @value2, GST_VALUE_LESSER is returned.
2600  * If the values are equal, GST_VALUE_EQUAL is returned.
2601  *
2602  * Returns: A GstValueCompareType value
2603  */
2604 int
2605 gst_value_compare (const GValue * value1, const GValue * value2)
2606 {
2607   GstValueTable *table, *best = NULL;
2608   guint i;
2609
2610   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
2611     return GST_VALUE_UNORDERED;
2612
2613   for (i = 0; i < gst_value_table->len; i++) {
2614     table = &g_array_index (gst_value_table, GstValueTable, i);
2615     if (table->type == G_VALUE_TYPE (value1) && table->compare != NULL) {
2616       best = table;
2617       break;
2618     }
2619     if (g_type_is_a (G_VALUE_TYPE (value1), table->type)) {
2620       if (!best || g_type_is_a (table->type, best->type))
2621         best = table;
2622     }
2623   }
2624   if (best) {
2625     return best->compare (value1, value2);
2626   }
2627
2628   g_critical ("unable to compare values of type %s\n",
2629       g_type_name (G_VALUE_TYPE (value1)));
2630   return GST_VALUE_UNORDERED;
2631 }
2632
2633 /* union */
2634
2635 /**
2636  * gst_value_can_union:
2637  * @value1: a value to union
2638  * @value2: another value to union
2639  *
2640  * Determines if @value1 and @value2 can be non-trivially unioned.
2641  * Any two values can be trivially unioned by adding both of them
2642  * to a GstValueList.  However, certain types have the possibility
2643  * to be unioned in a simpler way.  For example, an integer range
2644  * and an integer can be unioned if the integer is a subset of the
2645  * integer range.  If there is the possibility that two values can
2646  * be unioned, this function returns TRUE.
2647  *
2648  * Returns: TRUE if there is a function allowing the two values to
2649  * be unioned.
2650  */
2651 gboolean
2652 gst_value_can_union (const GValue * value1, const GValue * value2)
2653 {
2654   GstValueUnionInfo *union_info;
2655   guint i;
2656
2657   for (i = 0; i < gst_value_union_funcs->len; i++) {
2658     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
2659     if (union_info->type1 == G_VALUE_TYPE (value1) &&
2660         union_info->type2 == G_VALUE_TYPE (value2))
2661       return TRUE;
2662     if (union_info->type1 == G_VALUE_TYPE (value2) &&
2663         union_info->type2 == G_VALUE_TYPE (value1))
2664       return TRUE;
2665   }
2666
2667   return FALSE;
2668 }
2669
2670 /**
2671  * gst_value_union:
2672  * @dest: the destination value
2673  * @value1: a value to union
2674  * @value2: another value to union
2675  *
2676  * Creates a GValue cooresponding to the union of @value1 and @value2.
2677  *
2678  * Returns: always returns %TRUE
2679  */
2680 /* FIXME: change return type to 'void'? */
2681 gboolean
2682 gst_value_union (GValue * dest, const GValue * value1, const GValue * value2)
2683 {
2684   GstValueUnionInfo *union_info;
2685   guint i;
2686
2687   for (i = 0; i < gst_value_union_funcs->len; i++) {
2688     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
2689     if (union_info->type1 == G_VALUE_TYPE (value1) &&
2690         union_info->type2 == G_VALUE_TYPE (value2)) {
2691       if (union_info->func (dest, value1, value2)) {
2692         return TRUE;
2693       }
2694     }
2695     if (union_info->type1 == G_VALUE_TYPE (value2) &&
2696         union_info->type2 == G_VALUE_TYPE (value1)) {
2697       if (union_info->func (dest, value2, value1)) {
2698         return TRUE;
2699       }
2700     }
2701   }
2702
2703   gst_value_list_concat (dest, value1, value2);
2704   return TRUE;
2705 }
2706
2707 /**
2708  * gst_value_register_union_func:
2709  * @type1: a type to union
2710  * @type2: another type to union
2711  * @func: a function that implments creating a union between the two types
2712  *
2713  * Registers a union function that can create a union between GValues
2714  * of the type @type1 and @type2.
2715  *
2716  */
2717 void
2718 gst_value_register_union_func (GType type1, GType type2, GstValueUnionFunc func)
2719 {
2720   GstValueUnionInfo union_info;
2721
2722   union_info.type1 = type1;
2723   union_info.type2 = type2;
2724   union_info.func = func;
2725
2726   g_array_append_val (gst_value_union_funcs, union_info);
2727 }
2728
2729 /* intersection */
2730
2731 /**
2732  * gst_value_can_intersect:
2733  * @value1: a value to intersect
2734  * @value2: another value to intersect
2735  *
2736  * Determines if intersecting two values will produce a valid result.
2737  * Two values will produce a valid intersection if they have the same
2738  * type, or if there is a method (registered by
2739  * gst_value_register_intersection_func()) to calculate the intersection.
2740  *
2741  * Returns: TRUE if the values can intersect
2742  */
2743 gboolean
2744 gst_value_can_intersect (const GValue * value1, const GValue * value2)
2745 {
2746   GstValueIntersectInfo *intersect_info;
2747   guint i;
2748
2749   /* special cases */
2750   if (GST_VALUE_HOLDS_LIST (value1) || GST_VALUE_HOLDS_LIST (value2))
2751     return TRUE;
2752
2753   for (i = 0; i < gst_value_intersect_funcs->len; i++) {
2754     intersect_info = &g_array_index (gst_value_intersect_funcs,
2755         GstValueIntersectInfo, i);
2756     if (intersect_info->type1 == G_VALUE_TYPE (value1) &&
2757         intersect_info->type2 == G_VALUE_TYPE (value2))
2758       if (intersect_info->type2 == G_VALUE_TYPE (value1) &&
2759           intersect_info->type1 == G_VALUE_TYPE (value2))
2760         return TRUE;
2761   }
2762
2763   return gst_value_can_compare (value1, value2);
2764 }
2765
2766 /**
2767  * gst_value_intersect:
2768  * @dest: a uninitialized #GValue that will hold the calculated
2769  * intersection value
2770  * @value1: a value to intersect
2771  * @value2: another value to intersect
2772  *
2773  * Calculates the intersection of two values.  If the values have
2774  * a non-empty intersection, the value representing the intersection
2775  * is placed in @dest.  If the intersection is non-empty, @dest is
2776  * not modified.
2777  *
2778  * Returns: TRUE if the intersection is non-empty
2779  */
2780 gboolean
2781 gst_value_intersect (GValue * dest, const GValue * value1,
2782     const GValue * value2)
2783 {
2784   GstValueIntersectInfo *intersect_info;
2785   guint i;
2786   gboolean ret = FALSE;
2787
2788   /* special cases first */
2789   if (GST_VALUE_HOLDS_LIST (value1))
2790     return gst_value_intersect_list (dest, value1, value2);
2791   if (GST_VALUE_HOLDS_LIST (value2))
2792     return gst_value_intersect_list (dest, value2, value1);
2793
2794   for (i = 0; i < gst_value_intersect_funcs->len; i++) {
2795     intersect_info = &g_array_index (gst_value_intersect_funcs,
2796         GstValueIntersectInfo, i);
2797     if (intersect_info->type1 == G_VALUE_TYPE (value1) &&
2798         intersect_info->type2 == G_VALUE_TYPE (value2)) {
2799       ret = intersect_info->func (dest, value1, value2);
2800       return ret;
2801     }
2802     if (intersect_info->type1 == G_VALUE_TYPE (value2) &&
2803         intersect_info->type2 == G_VALUE_TYPE (value1)) {
2804       ret = intersect_info->func (dest, value2, value1);
2805       return ret;
2806     }
2807   }
2808
2809   if (gst_value_compare (value1, value2) == GST_VALUE_EQUAL) {
2810     gst_value_init_and_copy (dest, value1);
2811     ret = TRUE;
2812   }
2813
2814   return ret;
2815 }
2816
2817 /**
2818  * gst_value_register_intersect_func:
2819  * @type1: the first type to intersect
2820  * @type2: the second type to intersect
2821  * @func: the intersection function
2822  *
2823  * Registers a function that is called to calculate the intersection
2824  * of the values having the types @type1 and @type2.
2825  */
2826 void
2827 gst_value_register_intersect_func (GType type1, GType type2,
2828     GstValueIntersectFunc func)
2829 {
2830   GstValueIntersectInfo intersect_info;
2831
2832   intersect_info.type1 = type1;
2833   intersect_info.type2 = type2;
2834   intersect_info.func = func;
2835
2836   g_array_append_val (gst_value_intersect_funcs, intersect_info);
2837 }
2838
2839
2840 /* subtraction */
2841
2842 /**
2843  * gst_value_subtract:
2844  * @dest: the destination value for the result if the subtraction is not empty
2845  * @minuend: the value to subtract from
2846  * @subtrahend: the value to subtract
2847  *
2848  * Subtracts @subtrahend from @minuend and stores the result in @dest.
2849  * Note that this means subtraction as in sets, not as in mathematics.
2850  *
2851  * Returns: %TRUE if the subtraction is not empty
2852  */
2853 gboolean
2854 gst_value_subtract (GValue * dest, const GValue * minuend,
2855     const GValue * subtrahend)
2856 {
2857   GstValueSubtractInfo *info;
2858   guint i;
2859
2860   /* special cases first */
2861   if (GST_VALUE_HOLDS_LIST (minuend))
2862     return gst_value_subtract_from_list (dest, minuend, subtrahend);
2863   if (GST_VALUE_HOLDS_LIST (subtrahend))
2864     return gst_value_subtract_list (dest, minuend, subtrahend);
2865
2866   for (i = 0; i < gst_value_subtract_funcs->len; i++) {
2867     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
2868     if (info->minuend == G_VALUE_TYPE (minuend) &&
2869         info->subtrahend == G_VALUE_TYPE (subtrahend)) {
2870       return info->func (dest, minuend, subtrahend);
2871     }
2872   }
2873
2874   if (gst_value_compare (minuend, subtrahend) != GST_VALUE_EQUAL) {
2875     gst_value_init_and_copy (dest, minuend);
2876     return TRUE;
2877   }
2878
2879   return FALSE;
2880 }
2881
2882 #if 0
2883 gboolean
2884 gst_value_subtract (GValue * dest, const GValue * minuend,
2885     const GValue * subtrahend)
2886 {
2887   gboolean ret = gst_value_subtract2 (dest, minuend, subtrahend);
2888
2889   g_printerr ("\"%s\"  -  \"%s\"  =  \"%s\"\n", gst_value_serialize (minuend),
2890       gst_value_serialize (subtrahend),
2891       ret ? gst_value_serialize (dest) : "---");
2892   return ret;
2893 }
2894 #endif
2895
2896 /**
2897  * gst_value_can_subtract:
2898  * @minuend: the value to subtract from
2899  * @subtrahend: the value to subtract
2900  *
2901  * Checks if it's possible to subtract @subtrahend from @minuend.
2902  *
2903  * Returns: TRUE if a subtraction is possible
2904  */
2905 gboolean
2906 gst_value_can_subtract (const GValue * minuend, const GValue * subtrahend)
2907 {
2908   GstValueSubtractInfo *info;
2909   guint i;
2910
2911   /* special cases */
2912   if (GST_VALUE_HOLDS_LIST (minuend) || GST_VALUE_HOLDS_LIST (subtrahend))
2913     return TRUE;
2914
2915   for (i = 0; i < gst_value_subtract_funcs->len; i++) {
2916     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
2917     if (info->minuend == G_VALUE_TYPE (minuend) &&
2918         info->subtrahend == G_VALUE_TYPE (subtrahend))
2919       return TRUE;
2920   }
2921
2922   return gst_value_can_compare (minuend, subtrahend);
2923 }
2924
2925 /**
2926  * gst_value_register_subtract_func:
2927  * @minuend_type: type of the minuend
2928  * @subtrahend_type: type of the subtrahend
2929  * @func: function to use
2930  *
2931  * Registers @func as a function capable of subtracting the values of
2932  * @subtrahend_type from values of @minuend_type.
2933  */
2934 void
2935 gst_value_register_subtract_func (GType minuend_type, GType subtrahend_type,
2936     GstValueSubtractFunc func)
2937 {
2938   GstValueSubtractInfo info;
2939
2940   /* one type must be unfixed, other subtractions can be done as comparisons */
2941   g_return_if_fail (!gst_type_is_fixed (minuend_type)
2942       || !gst_type_is_fixed (subtrahend_type));
2943
2944   info.minuend = minuend_type;
2945   info.subtrahend = subtrahend_type;
2946   info.func = func;
2947
2948   g_array_append_val (gst_value_subtract_funcs, info);
2949 }
2950
2951 /**
2952  * gst_value_register:
2953  * @table: structure containing functions to register
2954  *
2955  * Registers functions to perform calculations on #GValues of a given
2956  * type.
2957  */
2958 /**
2959  * GstValueTable:
2960  * @type: GType that the functions operate on.
2961  * @compare: A function that compares two values of this type.
2962  * @serialize: A function that transforms a value of this type to a
2963  * string.  Strings created by this function must be unique and should
2964  * be human readable.
2965  * @deserialize: A function that transforms a string to a value of
2966  * this type.  This function must transform strings created by the
2967  * serialize function back to the original value.  This function may
2968  * optionally transform other strings into values.
2969  */
2970 void
2971 gst_value_register (const GstValueTable * table)
2972 {
2973   g_array_append_val (gst_value_table, *table);
2974 }
2975
2976 /**
2977  * gst_value_init_and_copy:
2978  * @dest: the target value
2979  * @src: the source value
2980  *
2981  * Initialises the target value to be of the same type as source and then copies
2982  * the contents from source to target.
2983  */
2984 void
2985 gst_value_init_and_copy (GValue * dest, const GValue * src)
2986 {
2987   g_value_init (dest, G_VALUE_TYPE (src));
2988   g_value_copy (src, dest);
2989 }
2990
2991 /**
2992  * gst_value_serialize:
2993  * @value: a #GValue to serialize
2994  *
2995  * tries to transform the given @value into a string representation that allows
2996  * getting back this string later on using gst_value_deserialize().
2997  *
2998  * Returns: the serialization for @value or NULL if none exists
2999  */
3000 gchar *
3001 gst_value_serialize (const GValue * value)
3002 {
3003   guint i;
3004   GValue s_val = { 0 };
3005   GstValueTable *table, *best = NULL;
3006   char *s;
3007
3008   g_return_val_if_fail (G_IS_VALUE (value), NULL);
3009
3010   for (i = 0; i < gst_value_table->len; i++) {
3011     table = &g_array_index (gst_value_table, GstValueTable, i);
3012     if (table->serialize == NULL)
3013       continue;
3014     if (table->type == G_VALUE_TYPE (value)) {
3015       best = table;
3016       break;
3017     }
3018     if (g_type_is_a (G_VALUE_TYPE (value), table->type)) {
3019       if (!best || g_type_is_a (table->type, best->type))
3020         best = table;
3021     }
3022   }
3023   if (best)
3024     return best->serialize (value);
3025
3026   g_value_init (&s_val, G_TYPE_STRING);
3027   if (g_value_transform (value, &s_val)) {
3028     s = gst_string_wrap (g_value_get_string (&s_val));
3029   } else {
3030     s = NULL;
3031   }
3032   g_value_unset (&s_val);
3033
3034   return s;
3035 }
3036
3037 /**
3038  * gst_value_deserialize:
3039  * @dest: #GValue to fill with contents of deserialization
3040  * @src: string to deserialize
3041  *
3042  * Tries to deserialize a string into the type specified by the given GValue.
3043  * If the operation succeeds, TRUE is returned, FALSE otherwise.
3044  *
3045  * Returns: TRUE on success
3046  */
3047 gboolean
3048 gst_value_deserialize (GValue * dest, const gchar * src)
3049 {
3050   GstValueTable *table, *best = NULL;
3051   guint i;
3052
3053   g_return_val_if_fail (src != NULL, FALSE);
3054   g_return_val_if_fail (G_IS_VALUE (dest), FALSE);
3055
3056   for (i = 0; i < gst_value_table->len; i++) {
3057     table = &g_array_index (gst_value_table, GstValueTable, i);
3058     if (table->serialize == NULL)
3059       continue;
3060
3061     if (table->type == G_VALUE_TYPE (dest)) {
3062       best = table;
3063       break;
3064     }
3065
3066     if (g_type_is_a (G_VALUE_TYPE (dest), table->type)) {
3067       if (!best || g_type_is_a (table->type, best->type))
3068         best = table;
3069     }
3070   }
3071   if (best) {
3072     return best->deserialize (dest, src);
3073   }
3074
3075   return FALSE;
3076 }
3077
3078 /**
3079  * gst_value_is_fixed:
3080  * @value: the #GValue to check
3081  *
3082  * Tests if the given GValue, if available in a GstStructure (or any other
3083  * container) contains a "fixed" (which means: one value) or an "unfixed"
3084  * (which means: multiple possible values, such as data lists or data
3085  * ranges) value.
3086  *
3087  * Returns: true if the value is "fixed".
3088  */
3089
3090 gboolean
3091 gst_value_is_fixed (const GValue * value)
3092 {
3093   GType type = G_VALUE_TYPE (value);
3094
3095   if (type == GST_TYPE_ARRAY) {
3096     gboolean fixed = TRUE;
3097     gint size, n;
3098     const GValue *kid;
3099
3100     /* check recursively */
3101     size = gst_value_array_get_size (value);
3102     for (n = 0; n < size; n++) {
3103       kid = gst_value_array_get_value (value, n);
3104       fixed &= gst_value_is_fixed (kid);
3105     }
3106
3107     return fixed;
3108   }
3109
3110   return gst_type_is_fixed (type);
3111 }
3112
3113 /************
3114  * fraction *
3115  ************/
3116
3117 /* helper functions */
3118
3119 /* Finds the greatest common divisor.
3120  * Returns 1 if none other found.
3121  * This is Euclid's algorithm. */
3122 static gint
3123 gst_greatest_common_divisor (gint a, gint b)
3124 {
3125   while (b != 0) {
3126     int temp = a;
3127
3128     a = b;
3129     b = temp % b;
3130   }
3131
3132   return ABS (a);
3133 }
3134
3135 static void
3136 gst_value_init_fraction (GValue * value)
3137 {
3138   value->data[0].v_int = 0;
3139   value->data[1].v_int = 1;
3140 }
3141
3142 static void
3143 gst_value_copy_fraction (const GValue * src_value, GValue * dest_value)
3144 {
3145   dest_value->data[0].v_int = src_value->data[0].v_int;
3146   dest_value->data[1].v_int = src_value->data[1].v_int;
3147 }
3148
3149 static gchar *
3150 gst_value_collect_fraction (GValue * value, guint n_collect_values,
3151     GTypeCValue * collect_values, guint collect_flags)
3152 {
3153   gst_value_set_fraction (value,
3154       collect_values[0].v_int, collect_values[1].v_int);
3155
3156   return NULL;
3157 }
3158
3159 static gchar *
3160 gst_value_lcopy_fraction (const GValue * value, guint n_collect_values,
3161     GTypeCValue * collect_values, guint collect_flags)
3162 {
3163   gint *numerator = collect_values[0].v_pointer;
3164   gint *denominator = collect_values[1].v_pointer;
3165
3166   if (!numerator)
3167     return g_strdup_printf ("numerator for `%s' passed as NULL",
3168         G_VALUE_TYPE_NAME (value));
3169   if (!denominator)
3170     return g_strdup_printf ("denominator for `%s' passed as NULL",
3171         G_VALUE_TYPE_NAME (value));
3172
3173   *numerator = value->data[0].v_int;
3174   *denominator = value->data[1].v_int;
3175
3176   return NULL;
3177 }
3178
3179 /**
3180  * gst_value_set_fraction:
3181  * @value: a GValue initialized to #GST_TYPE_FRACTION
3182  * @numerator: the numerator of the fraction
3183  * @denominator: the denominator of the fraction
3184  *
3185  * Sets @value to the fraction specified by @numerator over @denominator.
3186  * The fraction gets reduced to the smallest numerator and denominator,
3187  * and if necessary the sign is moved to the numerator.
3188  */
3189 void
3190 gst_value_set_fraction (GValue * value, gint numerator, gint denominator)
3191 {
3192   gint gcd = 0;
3193
3194   g_return_if_fail (GST_VALUE_HOLDS_FRACTION (value));
3195   g_return_if_fail (denominator != 0);
3196   g_return_if_fail (denominator >= -G_MAXINT);
3197   g_return_if_fail (numerator >= -G_MAXINT);
3198
3199   /* normalize sign */
3200   if (denominator < 0) {
3201     numerator = -numerator;
3202     denominator = -denominator;
3203   }
3204
3205   /* check for reduction */
3206   gcd = gst_greatest_common_divisor (numerator, denominator);
3207   if (gcd) {
3208     numerator /= gcd;
3209     denominator /= gcd;
3210   }
3211
3212   g_assert (denominator > 0);
3213
3214   value->data[0].v_int = numerator;
3215   value->data[1].v_int = denominator;
3216 }
3217
3218 /**
3219  * gst_value_get_fraction_numerator:
3220  * @value: a GValue initialized to #GST_TYPE_FRACTION
3221  *
3222  * Gets the numerator of the fraction specified by @value.
3223  *
3224  * Returns: the numerator of the fraction.
3225  */
3226 gint
3227 gst_value_get_fraction_numerator (const GValue * value)
3228 {
3229   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 0);
3230
3231   return value->data[0].v_int;
3232 }
3233
3234 /**
3235  * gst_value_get_fraction_denominator:
3236  * @value: a GValue initialized to #GST_TYPE_FRACTION
3237  *
3238  * Gets the denominator of the fraction specified by @value.
3239  *
3240  * Returns: the denominator of the fraction.
3241  */
3242 gint
3243 gst_value_get_fraction_denominator (const GValue * value)
3244 {
3245   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 1);
3246
3247   return value->data[1].v_int;
3248 }
3249
3250 /**
3251  * gst_value_fraction_multiply:
3252  * @product: a GValue initialized to #GST_TYPE_FRACTION
3253  * @factor1: a GValue initialized to #GST_TYPE_FRACTION
3254  * @factor2: a GValue initialized to #GST_TYPE_FRACTION
3255  *
3256  * Multiplies the two GValues containing a GstFraction and sets @product
3257  * to the product of the two fractions.
3258  *
3259  * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise.
3260  */
3261 gboolean
3262 gst_value_fraction_multiply (GValue * product, const GValue * factor1,
3263     const GValue * factor2)
3264 {
3265   gint gcd, n1, n2, d1, d2;
3266
3267   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor1), FALSE);
3268   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor2), FALSE);
3269
3270   n1 = factor1->data[0].v_int;
3271   n2 = factor2->data[0].v_int;
3272   d1 = factor1->data[1].v_int;
3273   d2 = factor2->data[1].v_int;
3274
3275   gcd = gst_greatest_common_divisor (n1, d2);
3276   n1 /= gcd;
3277   d2 /= gcd;
3278   gcd = gst_greatest_common_divisor (n2, d1);
3279   n2 /= gcd;
3280   d1 /= gcd;
3281
3282   g_return_val_if_fail (n1 == 0 || G_MAXINT / ABS (n1) >= ABS (n2), FALSE);
3283   g_return_val_if_fail (G_MAXINT / ABS (d1) >= ABS (d2), FALSE);
3284
3285   gst_value_set_fraction (product, n1 * n2, d1 * d2);
3286
3287   return TRUE;
3288 }
3289
3290 /**
3291  * gst_value_fraction_subtract:
3292  * @dest: a GValue initialized to #GST_TYPE_FRACTION
3293  * @minuend: a GValue initialized to #GST_TYPE_FRACTION
3294  * @subtrahend: a GValue initialized to #GST_TYPE_FRACTION
3295  *
3296  * Subtracts the @subtrahend from the @minuend and sets @dest to the result.
3297  *
3298  * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise.
3299  */
3300 gboolean
3301 gst_value_fraction_subtract (GValue * dest,
3302     const GValue * minuend, const GValue * subtrahend)
3303 {
3304   gint n1, n2, d1, d2;
3305
3306   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (minuend), FALSE);
3307   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (subtrahend), FALSE);
3308
3309   n1 = minuend->data[0].v_int;
3310   n2 = subtrahend->data[0].v_int;
3311   d1 = minuend->data[1].v_int;
3312   d2 = subtrahend->data[1].v_int;
3313
3314   if (n1 == 0) {
3315     gst_value_set_fraction (dest, -n2, d2);
3316     return TRUE;
3317   }
3318   if (n2 == 0) {
3319     gst_value_set_fraction (dest, n1, d1);
3320     return TRUE;
3321   }
3322
3323   g_return_val_if_fail (n1 == 0 || G_MAXINT / ABS (n1) >= ABS (d2), FALSE);
3324   g_return_val_if_fail (G_MAXINT / ABS (d1) >= ABS (n2), FALSE);
3325   g_return_val_if_fail (G_MAXINT / ABS (d1) >= ABS (d2), FALSE);
3326
3327   gst_value_set_fraction (dest, (n1 * d2) - (n2 * d1), d1 * d2);
3328
3329   return TRUE;
3330 }
3331
3332 static gchar *
3333 gst_value_serialize_fraction (const GValue * value)
3334 {
3335   gint32 numerator = value->data[0].v_int;
3336   gint32 denominator = value->data[1].v_int;
3337   gboolean positive = TRUE;
3338
3339   /* get the sign and make components absolute */
3340   if (numerator < 0) {
3341     numerator = -numerator;
3342     positive = !positive;
3343   }
3344   if (denominator < 0) {
3345     denominator = -denominator;
3346     positive = !positive;
3347   }
3348
3349   return g_strdup_printf ("%s%d/%d",
3350       positive ? "" : "-", numerator, denominator);
3351 }
3352
3353 static gboolean
3354 gst_value_deserialize_fraction (GValue * dest, const gchar * s)
3355 {
3356   gint num, den;
3357
3358   if (s && sscanf (s, "%d/%d", &num, &den) == 2) {
3359     gst_value_set_fraction (dest, num, den);
3360     return TRUE;
3361   }
3362   if (s && sscanf (s, "%d", &num) == 1) {
3363     gst_value_set_fraction (dest, num, 1);
3364     return TRUE;
3365   }
3366   if (g_ascii_strcasecmp (s, "min") == 0) {
3367     gst_value_set_fraction (dest, -G_MAXINT, 1);
3368     return TRUE;
3369   } else if (g_ascii_strcasecmp (s, "max") == 0) {
3370     gst_value_set_fraction (dest, G_MAXINT, 1);
3371     return TRUE;
3372   }
3373
3374   return FALSE;
3375 }
3376
3377 static void
3378 gst_value_transform_fraction_string (const GValue * src_value,
3379     GValue * dest_value)
3380 {
3381   dest_value->data[0].v_pointer = gst_value_serialize_fraction (src_value);
3382 }
3383
3384 static void
3385 gst_value_transform_string_fraction (const GValue * src_value,
3386     GValue * dest_value)
3387 {
3388   if (!gst_value_deserialize_fraction (dest_value,
3389           src_value->data[0].v_pointer))
3390     /* If the deserialize fails, ensure we leave the fraction in a
3391      * valid, if incorrect, state */
3392     gst_value_set_fraction (dest_value, 0, 1);
3393 }
3394
3395 #define MAX_TERMS       30
3396 #define MIN_DIVISOR     1.0e-10
3397 #define MAX_ERROR       1.0e-20
3398
3399 /* use continued fractions to transform a double into a fraction,
3400  * see http://mathforum.org/dr.math/faq/faq.fractions.html#decfrac.
3401  * This algorithm takes care of overflows.
3402  */
3403 static void
3404 gst_value_transform_double_fraction (const GValue * src_value,
3405     GValue * dest_value)
3406 {
3407   gdouble V, F;                 /* double being converted */
3408   gint N, D;                    /* will contain the result */
3409   gint A;                       /* current term in continued fraction */
3410   gint64 N1, D1;                /* numerator, denominator of last approx */
3411   gint64 N2, D2;                /* numerator, denominator of previous approx */
3412   gint i;
3413   gboolean negative = FALSE;
3414
3415   /* initialize fraction being converted */
3416   F = src_value->data[0].v_double;
3417   if (F < 0.0) {
3418     F = -F;
3419     negative = TRUE;
3420   }
3421
3422   V = F;
3423   /* initialize fractions with 1/0, 0/1 */
3424   N1 = 1;
3425   D1 = 0;
3426   N2 = 0;
3427   D2 = 1;
3428   N = 1;
3429   D = 1;
3430
3431   for (i = 0; i < MAX_TERMS; i++) {
3432     /* get next term */
3433     A = (gint) F;               /* no floor() needed, F is always >= 0 */
3434     /* get new divisor */
3435     F = F - A;
3436
3437     /* calculate new fraction in temp */
3438     N2 = N1 * A + N2;
3439     D2 = D1 * A + D2;
3440
3441     /* guard against overflow */
3442     if (N2 > G_MAXINT || D2 > G_MAXINT) {
3443       break;
3444     }
3445
3446     N = N2;
3447     D = D2;
3448
3449     /* save last two fractions */
3450     N2 = N1;
3451     D2 = D1;
3452     N1 = N;
3453     D1 = D;
3454
3455     /* quit if dividing by zero or close enough to target */
3456     if (F < MIN_DIVISOR || fabs (V - ((gdouble) N) / D) < MAX_ERROR) {
3457       break;
3458     }
3459
3460     /* Take reciprocal */
3461     F = 1 / F;
3462   }
3463   /* fix for overflow */
3464   if (D == 0) {
3465     N = G_MAXINT;
3466     D = 1;
3467   }
3468   /* fix for negative */
3469   if (negative)
3470     N = -N;
3471
3472   /* will also simplify */
3473   gst_value_set_fraction (dest_value, N, D);
3474 }
3475
3476 static void
3477 gst_value_transform_fraction_double (const GValue * src_value,
3478     GValue * dest_value)
3479 {
3480   dest_value->data[0].v_double = ((double) src_value->data[0].v_int) /
3481       ((double) src_value->data[1].v_int);
3482 }
3483
3484 static gint
3485 gst_value_compare_fraction (const GValue * value1, const GValue * value2)
3486 {
3487   gint n1, n2;
3488   gint d1, d2;
3489
3490   gint64 new_num_1;
3491   gint64 new_num_2;
3492
3493   n1 = value1->data[0].v_int;
3494   n2 = value2->data[0].v_int;
3495   d1 = value1->data[1].v_int;
3496   d2 = value2->data[1].v_int;
3497
3498   /* fractions are reduced when set, so we can quickly see if they're equal */
3499   if (n1 == n2 && d1 == d2)
3500     return GST_VALUE_EQUAL;
3501
3502   /* extend to 64 bits */
3503   new_num_1 = ((gint64) n1) * d2;
3504   new_num_2 = ((gint64) n2) * d1;
3505   if (new_num_1 < new_num_2)
3506     return GST_VALUE_LESS_THAN;
3507   if (new_num_1 > new_num_2)
3508     return GST_VALUE_GREATER_THAN;
3509
3510   /* new_num_1 == new_num_2 implies that both denominators must have 
3511    * been 0, beause otherwise simplification would have caught the
3512    * equivalence */
3513   g_assert_not_reached ();
3514   return GST_VALUE_UNORDERED;
3515 }
3516
3517 /*********
3518  * GDate *
3519  *********/
3520
3521 /**
3522  * gst_value_set_date:
3523  * @value: a GValue initialized to GST_TYPE_DATE
3524  * @date: the date to set the value to
3525  *
3526  * Sets the contents of @value to coorespond to @date.  The actual
3527  * #GDate structure is copied before it is used.
3528  */
3529 void
3530 gst_value_set_date (GValue * value, const GDate * date)
3531 {
3532   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_DATE);
3533
3534   g_value_set_boxed (value, date);
3535 }
3536
3537 /**
3538  * gst_value_get_date:
3539  * @value: a GValue initialized to GST_TYPE_DATE
3540  *
3541  * Gets the contents of @value.
3542  *
3543  * Returns: the contents of @value
3544  */
3545 const GDate *
3546 gst_value_get_date (const GValue * value)
3547 {
3548   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_DATE, NULL);
3549
3550   return (const GDate *) g_value_get_boxed (value);
3551 }
3552
3553 static gpointer
3554 gst_date_copy (gpointer boxed)
3555 {
3556   const GDate *date = (const GDate *) boxed;
3557
3558   return g_date_new_julian (g_date_get_julian (date));
3559 }
3560
3561 static gint
3562 gst_value_compare_date (const GValue * value1, const GValue * value2)
3563 {
3564   const GDate *date1 = (const GDate *) g_value_get_boxed (value1);
3565   const GDate *date2 = (const GDate *) g_value_get_boxed (value2);
3566   guint32 j1, j2;
3567
3568   if (date1 == date2)
3569     return GST_VALUE_EQUAL;
3570
3571   if ((date1 == NULL || !g_date_valid (date1))
3572       && (date2 != NULL && g_date_valid (date2))) {
3573     return GST_VALUE_LESS_THAN;
3574   }
3575
3576   if ((date2 == NULL || !g_date_valid (date2))
3577       && (date1 != NULL && g_date_valid (date1))) {
3578     return GST_VALUE_GREATER_THAN;
3579   }
3580
3581   if (date1 == NULL || date2 == NULL || !g_date_valid (date1)
3582       || !g_date_valid (date2)) {
3583     return GST_VALUE_UNORDERED;
3584   }
3585
3586   j1 = g_date_get_julian (date1);
3587   j2 = g_date_get_julian (date2);
3588
3589   if (j1 == j2)
3590     return GST_VALUE_EQUAL;
3591   else if (j1 < j2)
3592     return GST_VALUE_LESS_THAN;
3593   else
3594     return GST_VALUE_GREATER_THAN;
3595 }
3596
3597 static gchar *
3598 gst_value_serialize_date (const GValue * val)
3599 {
3600   const GDate *date = (const GDate *) g_value_get_boxed (val);
3601
3602   if (date == NULL || !g_date_valid (date))
3603     return g_strdup ("9999-99-99");
3604
3605   return g_strdup_printf ("%04u-%02u-%02u", g_date_get_year (date),
3606       g_date_get_month (date), g_date_get_day (date));
3607 }
3608
3609 static gboolean
3610 gst_value_deserialize_date (GValue * dest, const char *s)
3611 {
3612   guint year, month, day;
3613
3614   if (!s || sscanf (s, "%04u-%02u-%02u", &year, &month, &day) != 3)
3615     return FALSE;
3616
3617   if (!g_date_valid_dmy (day, month, year))
3618     return FALSE;
3619
3620   g_value_take_boxed (dest, g_date_new_dmy (day, month, year));
3621   return TRUE;
3622 }
3623
3624 static void
3625 gst_value_transform_date_string (const GValue * src_value, GValue * dest_value)
3626 {
3627   dest_value->data[0].v_pointer = gst_value_serialize_date (src_value);
3628 }
3629
3630 static void
3631 gst_value_transform_string_date (const GValue * src_value, GValue * dest_value)
3632 {
3633   gst_value_deserialize_date (dest_value, src_value->data[0].v_pointer);
3634 }
3635
3636 static GTypeInfo _info = {
3637   0,
3638   NULL,
3639   NULL,
3640   NULL,
3641   NULL,
3642   NULL,
3643   0,
3644   0,
3645   NULL,
3646   NULL,
3647 };
3648
3649 static GTypeFundamentalInfo _finfo = {
3650   0
3651 };
3652
3653 #define FUNC_VALUE_GET_TYPE(type, name)                         \
3654 GType gst_ ## type ## _get_type (void)                          \
3655 {                                                               \
3656   static GType gst_ ## type ## _type = 0;                       \
3657                                                                 \
3658   if (G_UNLIKELY (gst_ ## type ## _type == 0)) {                \
3659     _info.value_table = & _gst_ ## type ## _value_table;        \
3660     gst_ ## type ## _type = g_type_register_fundamental (       \
3661         g_type_fundamental_next (),                             \
3662         name, &_info, &_finfo, 0);                              \
3663   }                                                             \
3664                                                                 \
3665   return gst_ ## type ## _type;                                 \
3666 }
3667
3668 static const GTypeValueTable _gst_fourcc_value_table = {
3669   gst_value_init_fourcc,
3670   NULL,
3671   gst_value_copy_fourcc,
3672   NULL,
3673   "i",
3674   gst_value_collect_fourcc,
3675   "p",
3676   gst_value_lcopy_fourcc
3677 };
3678
3679 FUNC_VALUE_GET_TYPE (fourcc, "GstFourcc");
3680
3681 static const GTypeValueTable _gst_int_range_value_table = {
3682   gst_value_init_int_range,
3683   NULL,
3684   gst_value_copy_int_range,
3685   NULL,
3686   "ii",
3687   gst_value_collect_int_range,
3688   "pp",
3689   gst_value_lcopy_int_range
3690 };
3691
3692 FUNC_VALUE_GET_TYPE (int_range, "GstIntRange");
3693
3694 static const GTypeValueTable _gst_double_range_value_table = {
3695   gst_value_init_double_range,
3696   NULL,
3697   gst_value_copy_double_range,
3698   NULL,
3699   "dd",
3700   gst_value_collect_double_range,
3701   "pp",
3702   gst_value_lcopy_double_range
3703 };
3704
3705 FUNC_VALUE_GET_TYPE (double_range, "GstDoubleRange");
3706
3707 static const GTypeValueTable _gst_fraction_range_value_table = {
3708   gst_value_init_fraction_range,
3709   gst_value_free_fraction_range,
3710   gst_value_copy_fraction_range,
3711   NULL,
3712   "iiii",
3713   gst_value_collect_fraction_range,
3714   "pppp",
3715   gst_value_lcopy_fraction_range
3716 };
3717
3718 FUNC_VALUE_GET_TYPE (fraction_range, "GstFractionRange");
3719
3720 static const GTypeValueTable _gst_value_list_value_table = {
3721   gst_value_init_list_or_array,
3722   gst_value_free_list_or_array,
3723   gst_value_copy_list_or_array,
3724   gst_value_list_or_array_peek_pointer,
3725   "p",
3726   gst_value_collect_list_or_array,
3727   "p",
3728   gst_value_lcopy_list_or_array
3729 };
3730
3731 FUNC_VALUE_GET_TYPE (value_list, "GstValueList");
3732
3733 static const GTypeValueTable _gst_value_array_value_table = {
3734   gst_value_init_list_or_array,
3735   gst_value_free_list_or_array,
3736   gst_value_copy_list_or_array,
3737   gst_value_list_or_array_peek_pointer,
3738   "p",
3739   gst_value_collect_list_or_array,
3740   "p",
3741   gst_value_lcopy_list_or_array
3742 };
3743
3744 FUNC_VALUE_GET_TYPE (value_array, "GstValueArray");
3745
3746 static const GTypeValueTable _gst_fraction_value_table = {
3747   gst_value_init_fraction,
3748   NULL,
3749   gst_value_copy_fraction,
3750   NULL,
3751   "ii",
3752   gst_value_collect_fraction,
3753   "pp",
3754   gst_value_lcopy_fraction
3755 };
3756
3757 FUNC_VALUE_GET_TYPE (fraction, "GstFraction");
3758
3759
3760 GType
3761 gst_date_get_type (void)
3762 {
3763   static GType gst_date_type = 0;
3764
3765   if (!gst_date_type) {
3766     /* Not using G_TYPE_DATE here on purpose, even if we could
3767      * if GLIB_CHECK_VERSION(2,8,0) was true: we don't want the
3768      * serialised strings to have different type strings depending
3769      * on what version is used, so FIXME in 0.11 when we
3770      * require GLib-2.8 */
3771     gst_date_type = g_boxed_type_register_static ("GstDate",
3772         (GBoxedCopyFunc) gst_date_copy, (GBoxedFreeFunc) g_date_free);
3773   }
3774
3775   return gst_date_type;
3776 }
3777
3778 void
3779 _gst_value_initialize (void)
3780 {
3781   //const GTypeFundamentalInfo finfo = { G_TYPE_FLAG_DERIVABLE, };
3782
3783   gst_value_table = g_array_new (FALSE, FALSE, sizeof (GstValueTable));
3784   gst_value_union_funcs = g_array_new (FALSE, FALSE,
3785       sizeof (GstValueUnionInfo));
3786   gst_value_intersect_funcs = g_array_new (FALSE, FALSE,
3787       sizeof (GstValueIntersectInfo));
3788   gst_value_subtract_funcs = g_array_new (FALSE, FALSE,
3789       sizeof (GstValueSubtractInfo));
3790
3791   {
3792     static GstValueTable gst_value = {
3793       0,
3794       gst_value_compare_fourcc,
3795       gst_value_serialize_fourcc,
3796       gst_value_deserialize_fourcc,
3797     };
3798
3799     gst_value.type = gst_fourcc_get_type ();
3800     gst_value_register (&gst_value);
3801   }
3802
3803   {
3804     static GstValueTable gst_value = {
3805       0,
3806       gst_value_compare_int_range,
3807       gst_value_serialize_int_range,
3808       gst_value_deserialize_int_range,
3809     };
3810
3811     gst_value.type = gst_int_range_get_type ();
3812     gst_value_register (&gst_value);
3813   }
3814
3815   {
3816     static GstValueTable gst_value = {
3817       0,
3818       gst_value_compare_double_range,
3819       gst_value_serialize_double_range,
3820       gst_value_deserialize_double_range,
3821     };
3822
3823     gst_value.type = gst_double_range_get_type ();
3824     gst_value_register (&gst_value);
3825   }
3826
3827   {
3828     static GstValueTable gst_value = {
3829       0,
3830       gst_value_compare_fraction_range,
3831       gst_value_serialize_fraction_range,
3832       gst_value_deserialize_fraction_range,
3833     };
3834
3835     gst_value.type = gst_fraction_range_get_type ();
3836     gst_value_register (&gst_value);
3837   }
3838
3839   {
3840     static GstValueTable gst_value = {
3841       0,
3842       gst_value_compare_list_or_array,
3843       gst_value_serialize_list,
3844       gst_value_deserialize_list,
3845     };
3846
3847     gst_value.type = gst_value_list_get_type ();
3848     gst_value_register (&gst_value);
3849   }
3850
3851   {
3852     static GstValueTable gst_value = {
3853       0,
3854       gst_value_compare_list_or_array,
3855       gst_value_serialize_array,
3856       gst_value_deserialize_array,
3857     };
3858
3859     gst_value.type = gst_value_array_get_type ();;
3860     gst_value_register (&gst_value);
3861   }
3862
3863   {
3864 #if 0
3865     static const GTypeValueTable value_table = {
3866       gst_value_init_buffer,
3867       NULL,
3868       gst_value_copy_buffer,
3869       NULL,
3870       "i",
3871       NULL,                     /*gst_value_collect_buffer, */
3872       "p",
3873       NULL                      /*gst_value_lcopy_buffer */
3874     };
3875 #endif
3876     static GstValueTable gst_value = {
3877       0,
3878       gst_value_compare_buffer,
3879       gst_value_serialize_buffer,
3880       gst_value_deserialize_buffer,
3881     };
3882
3883     gst_value.type = GST_TYPE_BUFFER;
3884     gst_value_register (&gst_value);
3885   }
3886   {
3887     static GstValueTable gst_value = {
3888       0,
3889       gst_value_compare_fraction,
3890       gst_value_serialize_fraction,
3891       gst_value_deserialize_fraction,
3892     };
3893
3894     gst_value.type = gst_fraction_get_type ();
3895     gst_value_register (&gst_value);
3896   }
3897   {
3898     static GstValueTable gst_value = {
3899       0,
3900       NULL,
3901       gst_value_serialize_caps,
3902       gst_value_deserialize_caps,
3903     };
3904
3905     gst_value.type = GST_TYPE_CAPS;
3906     gst_value_register (&gst_value);
3907   }
3908   {
3909     static GstValueTable gst_value = {
3910       0,
3911       gst_value_compare_date,
3912       gst_value_serialize_date,
3913       gst_value_deserialize_date,
3914     };
3915
3916     gst_value.type = gst_date_get_type ();
3917     gst_value_register (&gst_value);
3918   }
3919
3920   REGISTER_SERIALIZATION (G_TYPE_DOUBLE, double);
3921   REGISTER_SERIALIZATION (G_TYPE_FLOAT, float);
3922
3923   REGISTER_SERIALIZATION (G_TYPE_STRING, string);
3924   REGISTER_SERIALIZATION (G_TYPE_BOOLEAN, boolean);
3925   REGISTER_SERIALIZATION (G_TYPE_ENUM, enum);
3926
3927   REGISTER_SERIALIZATION (G_TYPE_FLAGS, flags);
3928
3929   REGISTER_SERIALIZATION (G_TYPE_INT, int);
3930
3931   REGISTER_SERIALIZATION (G_TYPE_INT64, int64);
3932   REGISTER_SERIALIZATION (G_TYPE_LONG, long);
3933
3934   REGISTER_SERIALIZATION (G_TYPE_UINT, uint);
3935   REGISTER_SERIALIZATION (G_TYPE_UINT64, uint64);
3936   REGISTER_SERIALIZATION (G_TYPE_ULONG, ulong);
3937
3938   g_value_register_transform_func (GST_TYPE_FOURCC, G_TYPE_STRING,
3939       gst_value_transform_fourcc_string);
3940   g_value_register_transform_func (GST_TYPE_INT_RANGE, G_TYPE_STRING,
3941       gst_value_transform_int_range_string);
3942   g_value_register_transform_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_STRING,
3943       gst_value_transform_double_range_string);
3944   g_value_register_transform_func (GST_TYPE_FRACTION_RANGE, G_TYPE_STRING,
3945       gst_value_transform_fraction_range_string);
3946   g_value_register_transform_func (GST_TYPE_LIST, G_TYPE_STRING,
3947       gst_value_transform_list_string);
3948   g_value_register_transform_func (GST_TYPE_ARRAY, G_TYPE_STRING,
3949       gst_value_transform_array_string);
3950   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_STRING,
3951       gst_value_transform_fraction_string);
3952   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_FRACTION,
3953       gst_value_transform_string_fraction);
3954   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_DOUBLE,
3955       gst_value_transform_fraction_double);
3956   g_value_register_transform_func (G_TYPE_DOUBLE, GST_TYPE_FRACTION,
3957       gst_value_transform_double_fraction);
3958   g_value_register_transform_func (GST_TYPE_DATE, G_TYPE_STRING,
3959       gst_value_transform_date_string);
3960   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_DATE,
3961       gst_value_transform_string_date);
3962
3963   gst_value_register_intersect_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
3964       gst_value_intersect_int_int_range);
3965   gst_value_register_intersect_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
3966       gst_value_intersect_int_range_int_range);
3967   gst_value_register_intersect_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
3968       gst_value_intersect_double_double_range);
3969   gst_value_register_intersect_func (GST_TYPE_DOUBLE_RANGE,
3970       GST_TYPE_DOUBLE_RANGE, gst_value_intersect_double_range_double_range);
3971   gst_value_register_intersect_func (GST_TYPE_ARRAY,
3972       GST_TYPE_ARRAY, gst_value_intersect_array);
3973   gst_value_register_intersect_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
3974       gst_value_intersect_fraction_fraction_range);
3975   gst_value_register_intersect_func (GST_TYPE_FRACTION_RANGE,
3976       GST_TYPE_FRACTION_RANGE,
3977       gst_value_intersect_fraction_range_fraction_range);
3978
3979   gst_value_register_subtract_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
3980       gst_value_subtract_int_int_range);
3981   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, G_TYPE_INT,
3982       gst_value_subtract_int_range_int);
3983   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
3984       gst_value_subtract_int_range_int_range);
3985   gst_value_register_subtract_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
3986       gst_value_subtract_double_double_range);
3987   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_DOUBLE,
3988       gst_value_subtract_double_range_double);
3989   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE,
3990       GST_TYPE_DOUBLE_RANGE, gst_value_subtract_double_range_double_range);
3991
3992   gst_value_register_subtract_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
3993       gst_value_subtract_fraction_fraction_range);
3994   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE, GST_TYPE_FRACTION,
3995       gst_value_subtract_fraction_range_fraction);
3996   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE,
3997       GST_TYPE_FRACTION_RANGE,
3998       gst_value_subtract_fraction_range_fraction_range);
3999
4000 #if GLIB_CHECK_VERSION(2,8,0)
4001   /* see bug #317246, #64994, #65041 */
4002   {
4003     volatile GType date_type = G_TYPE_DATE;
4004
4005     g_type_name (date_type);
4006   }
4007 #endif
4008
4009   gst_value_register_union_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
4010       gst_value_union_int_int_range);
4011   gst_value_register_union_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
4012       gst_value_union_int_range_int_range);
4013
4014 #if 0
4015   /* Implement these if needed */
4016   gst_value_register_union_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
4017       gst_value_union_fraction_fraction_range);
4018   gst_value_register_union_func (GST_TYPE_FRACTION_RANGE,
4019       GST_TYPE_FRACTION_RANGE, gst_value_union_fraction_range_fraction_range);
4020 #endif
4021 }