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