don't mix tabs and spaces
[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 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include <gst/gst.h>
27 #include <gobject/gvaluecollector.h>
28
29
30 typedef struct _GstValueUnionInfo GstValueUnionInfo;
31 struct _GstValueUnionInfo
32 {
33   GType type1;
34   GType type2;
35   GstValueUnionFunc func;
36 };
37
38 typedef struct _GstValueIntersectInfo GstValueIntersectInfo;
39 struct _GstValueIntersectInfo
40 {
41   GType type1;
42   GType type2;
43   GstValueIntersectFunc func;
44 };
45
46 GType gst_type_fourcc;
47 GType gst_type_int_range;
48 GType gst_type_double_range;
49 GType gst_type_list;
50
51 static GArray *gst_value_table;
52 static GArray *gst_value_union_funcs;
53 static GArray *gst_value_intersect_funcs;
54
55 /*************************************/
56 /* list */
57
58 static void
59 gst_value_init_list (GValue * value)
60 {
61   value->data[0].v_pointer = g_array_new (FALSE, TRUE, sizeof (GValue));
62 }
63
64 static GArray *
65 gst_value_list_array_copy (const GArray * src)
66 {
67   GArray *dest;
68   gint i;
69
70   dest = g_array_sized_new (FALSE, TRUE, sizeof (GValue), src->len);
71   g_array_set_size (dest, src->len);
72   for (i = 0; i < src->len; i++) {
73     gst_value_init_and_copy (&g_array_index (dest, GValue, i),
74         &g_array_index (src, GValue, i));
75   }
76
77   return dest;
78 }
79
80 static void
81 gst_value_copy_list (const GValue * src_value, GValue * dest_value)
82 {
83   dest_value->data[0].v_pointer =
84       gst_value_list_array_copy ((GArray *) src_value->data[0].v_pointer);
85 }
86
87 static void
88 gst_value_free_list (GValue * value)
89 {
90   gint i;
91   GArray *src = (GArray *) value->data[0].v_pointer;
92
93   if ((value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS) == 0) {
94     for (i = 0; i < src->len; i++) {
95       g_value_unset (&g_array_index (src, GValue, i));
96     }
97     g_array_free (src, TRUE);
98   }
99 }
100
101 static gpointer
102 gst_value_list_peek_pointer (const GValue * value)
103 {
104   return value->data[0].v_pointer;
105 }
106
107 static gchar *
108 gst_value_collect_list (GValue * value, guint n_collect_values,
109     GTypeCValue * collect_values, guint collect_flags)
110 {
111   if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
112     value->data[0].v_pointer = collect_values[0].v_pointer;
113     value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
114   } else {
115     value->data[0].v_pointer =
116         gst_value_list_array_copy ((GArray *) collect_values[0].v_pointer);
117   }
118   return NULL;
119 }
120
121 static gchar *
122 gst_value_lcopy_list (const GValue * value, guint n_collect_values,
123     GTypeCValue * collect_values, guint collect_flags)
124 {
125   GArray **dest = collect_values[0].v_pointer;
126
127   if (!dest)
128     return g_strdup_printf ("value location for `%s' passed as NULL",
129         G_VALUE_TYPE_NAME (value));
130   if (!value->data[0].v_pointer)
131     return g_strdup_printf ("invalid value given for `%s'",
132         G_VALUE_TYPE_NAME (value));
133   if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
134     *dest = (GArray *) value->data[0].v_pointer;
135   } else {
136     *dest = gst_value_list_array_copy ((GArray *) value->data[0].v_pointer);
137   }
138   return NULL;
139 }
140
141 /**
142  * gst_value_list_prepend_value:
143  *
144  */
145 void
146 gst_value_list_prepend_value (GValue * value, const GValue * prepend_value)
147 {
148   g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
149
150   g_array_prepend_vals ((GArray *) value->data[0].v_pointer, prepend_value, 1);
151 }
152
153 /**
154  * gst_value_list_append_value:
155  *
156  */
157 void
158 gst_value_list_append_value (GValue * value, const GValue * append_value)
159 {
160   g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
161
162   g_array_append_vals ((GArray *) value->data[0].v_pointer, append_value, 1);
163 }
164
165 /**
166  * gst_value_list_get_size:
167  *
168  */
169 guint
170 gst_value_list_get_size (const GValue * value)
171 {
172   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), 0);
173
174   return ((GArray *) value->data[0].v_pointer)->len;
175 }
176
177 /**
178  * gst_value_list_get_value:
179  *
180  */
181 const GValue *
182 gst_value_list_get_value (const GValue * value, guint index)
183 {
184   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), NULL);
185   g_return_val_if_fail (index < gst_value_list_get_size (value), NULL);
186
187   return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer,
188       GValue, index);
189 }
190
191 /**
192  * gst_value_list_concat:
193  * @dest: an uninitialized #GValue to take the result
194  * @value1: first value to put into the union
195  * @value2: second value to put into the union
196  *
197  * Concatenates copies of value1 and value2 into a list. dest will be 
198  * initialized to the type GST_TYPE_LIST.
199  */
200 void
201 gst_value_list_concat (GValue * dest, const GValue * value1,
202     const GValue * value2)
203 {
204   guint i, value1_length, value2_length;
205   GArray *array;
206
207   g_return_if_fail (dest != NULL);
208   g_return_if_fail (G_VALUE_TYPE (dest) == 0);
209   g_return_if_fail (G_IS_VALUE (value1));
210   g_return_if_fail (G_IS_VALUE (value2));
211
212   value1_length =
213       (GST_VALUE_HOLDS_LIST (value1) ? gst_value_list_get_size (value1) : 1);
214   value2_length =
215       (GST_VALUE_HOLDS_LIST (value2) ? gst_value_list_get_size (value2) : 1);
216   g_value_init (dest, GST_TYPE_LIST);
217   array = (GArray *) dest->data[0].v_pointer;
218   g_array_set_size (array, value1_length + value2_length);
219
220   if (GST_VALUE_HOLDS_LIST (value1)) {
221     for (i = 0; i < value1_length; i++) {
222       gst_value_init_and_copy (&g_array_index (array, GValue, i),
223           gst_value_list_get_value (value1, i));
224     }
225   } else {
226     gst_value_init_and_copy (&g_array_index (array, GValue, 0), value1);
227   }
228
229   if (GST_VALUE_HOLDS_LIST (value2)) {
230     for (i = 0; i < value2_length; i++) {
231       gst_value_init_and_copy (&g_array_index (array, GValue,
232               i + value1_length), gst_value_list_get_value (value2, i));
233     }
234   } else {
235     gst_value_init_and_copy (&g_array_index (array, GValue, value1_length),
236         value2);
237   }
238 }
239
240 static void
241 gst_value_transform_list_string (const GValue * src_value, GValue * dest_value)
242 {
243   GValue *list_value;
244   GArray *array;
245   GString *s;
246   int i;
247   char *list_s;
248
249   array = src_value->data[0].v_pointer;
250
251   s = g_string_new ("{ ");
252   for (i = 0; i < array->len; i++) {
253     list_value = &g_array_index (array, GValue, i);
254
255     if (i != 0) {
256       g_string_append (s, ", ");
257     }
258     list_s = g_strdup_value_contents (list_value);
259     g_string_append (s, list_s);
260     g_free (list_s);
261   }
262   g_string_append (s, " }");
263
264   dest_value->data[0].v_pointer = g_string_free (s, FALSE);
265 }
266
267 static int
268 gst_value_compare_list (const GValue * value1, const GValue * value2)
269 {
270   int i, j;
271   GArray *array1 = value1->data[0].v_pointer;
272   GArray *array2 = value2->data[0].v_pointer;
273   GValue *v1;
274   GValue *v2;
275
276   if (array1->len != array2->len)
277     return GST_VALUE_UNORDERED;
278
279   for (i = 0; i < array1->len; i++) {
280     v1 = &g_array_index (array1, GValue, i);
281     for (j = 0; j < array1->len; j++) {
282       v2 = &g_array_index (array2, GValue, j);
283       if (gst_value_compare (v1, v2) == GST_VALUE_EQUAL)
284         break;
285     }
286     if (j == array1->len) {
287       return GST_VALUE_UNORDERED;
288     }
289   }
290
291   return GST_VALUE_EQUAL;
292 }
293
294 static char *
295 gst_value_serialize_list (const GValue * value)
296 {
297   int i;
298   GArray *array = value->data[0].v_pointer;
299   GString *s;
300   GValue *v;
301   gchar *s_val;
302
303   s = g_string_new ("{ ");
304   for (i = 0; i < array->len; i++) {
305     v = &g_array_index (array, GValue, i);
306     s_val = gst_value_serialize (v);
307     g_string_append (s, s_val);
308     g_free (s_val);
309     if (i < array->len - 1) {
310       g_string_append (s, ", ");
311     }
312   }
313   g_string_append (s, " }");
314   return g_string_free (s, FALSE);
315 }
316
317 static gboolean
318 gst_value_deserialize_list (GValue * dest, const char *s)
319 {
320   g_warning ("unimplemented");
321   return FALSE;
322 }
323
324 /*************************************/
325 /* fourcc */
326
327 static void
328 gst_value_init_fourcc (GValue * value)
329 {
330   value->data[0].v_int = 0;
331 }
332
333 static void
334 gst_value_copy_fourcc (const GValue * src_value, GValue * dest_value)
335 {
336   dest_value->data[0].v_int = src_value->data[0].v_int;
337 }
338
339 static gchar *
340 gst_value_collect_fourcc (GValue * value, guint n_collect_values,
341     GTypeCValue * collect_values, guint collect_flags)
342 {
343   value->data[0].v_int = collect_values[0].v_int;
344
345   return NULL;
346 }
347
348 static gchar *
349 gst_value_lcopy_fourcc (const GValue * value, guint n_collect_values,
350     GTypeCValue * collect_values, guint collect_flags)
351 {
352   guint32 *fourcc_p = collect_values[0].v_pointer;
353
354   if (!fourcc_p)
355     return g_strdup_printf ("value location for `%s' passed as NULL",
356         G_VALUE_TYPE_NAME (value));
357
358   *fourcc_p = value->data[0].v_int;
359
360   return NULL;
361 }
362
363 /**
364  * gst_value_set_fourcc:
365  *
366  */
367 void
368 gst_value_set_fourcc (GValue * value, guint32 fourcc)
369 {
370   g_return_if_fail (GST_VALUE_HOLDS_FOURCC (value));
371
372   value->data[0].v_int = fourcc;
373 }
374
375 /**
376  * gst_value_get_fourcc:
377  *
378  */
379 guint32
380 gst_value_get_fourcc (const GValue * value)
381 {
382   g_return_val_if_fail (GST_VALUE_HOLDS_FOURCC (value), 0);
383
384   return value->data[0].v_int;
385 }
386
387 static void
388 gst_value_transform_fourcc_string (const GValue * src_value,
389     GValue * dest_value)
390 {
391   guint32 fourcc = src_value->data[0].v_int;
392
393   if (g_ascii_isprint ((fourcc >> 0) & 0xff) &&
394       g_ascii_isprint ((fourcc >> 8) & 0xff) &&
395       g_ascii_isprint ((fourcc >> 16) & 0xff) &&
396       g_ascii_isprint ((fourcc >> 24) & 0xff)) {
397     dest_value->data[0].v_pointer =
398         g_strdup_printf (GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
399   } else {
400     dest_value->data[0].v_pointer = g_strdup_printf ("0x%08x", fourcc);
401   }
402 }
403
404 static int
405 gst_value_compare_fourcc (const GValue * value1, const GValue * value2)
406 {
407   if (value2->data[0].v_int == value1->data[0].v_int)
408     return GST_VALUE_EQUAL;
409   return GST_VALUE_UNORDERED;
410 }
411
412 static char *
413 gst_value_serialize_fourcc (const GValue * value)
414 {
415   guint32 fourcc = value->data[0].v_int;
416
417   if (g_ascii_isalnum ((fourcc >> 0) & 0xff) &&
418       g_ascii_isalnum ((fourcc >> 8) & 0xff) &&
419       g_ascii_isalnum ((fourcc >> 16) & 0xff) &&
420       g_ascii_isalnum ((fourcc >> 24) & 0xff)) {
421     return g_strdup_printf (GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
422   } else {
423     return g_strdup_printf ("0x%08x", fourcc);
424   }
425 }
426
427 static gboolean
428 gst_value_deserialize_fourcc (GValue * dest, const char *s)
429 {
430   gboolean ret = FALSE;
431   guint32 fourcc = 0;
432   char *end;
433
434   if (strlen (s) == 4) {
435     fourcc = GST_MAKE_FOURCC (s[0], s[1], s[2], s[3]);
436     ret = TRUE;
437   } else if (g_ascii_isdigit (*s)) {
438     fourcc = strtoul (s, &end, 0);
439     if (*end == 0) {
440       ret = TRUE;
441     }
442   }
443   gst_value_set_fourcc (dest, fourcc);
444
445   return ret;
446 }
447
448 /*************************************/
449 /* int range */
450
451 static void
452 gst_value_init_int_range (GValue * value)
453 {
454   value->data[0].v_int = 0;
455   value->data[1].v_int = 0;
456 }
457
458 static void
459 gst_value_copy_int_range (const GValue * src_value, GValue * dest_value)
460 {
461   dest_value->data[0].v_int = src_value->data[0].v_int;
462   dest_value->data[1].v_int = src_value->data[1].v_int;
463 }
464
465 static gchar *
466 gst_value_collect_int_range (GValue * value, guint n_collect_values,
467     GTypeCValue * collect_values, guint collect_flags)
468 {
469   /* FIXME */
470   value->data[0].v_int = collect_values[0].v_int;
471   value->data[1].v_int = collect_values[1].v_int;
472
473   return NULL;
474 }
475
476 static gchar *
477 gst_value_lcopy_int_range (const GValue * value, guint n_collect_values,
478     GTypeCValue * collect_values, guint collect_flags)
479 {
480   guint32 *int_range_start = collect_values[0].v_pointer;
481   guint32 *int_range_end = collect_values[1].v_pointer;
482
483   if (!int_range_start)
484     return g_strdup_printf ("start value location for `%s' passed as NULL",
485         G_VALUE_TYPE_NAME (value));
486   if (!int_range_end)
487     return g_strdup_printf ("end value location for `%s' passed as NULL",
488         G_VALUE_TYPE_NAME (value));
489
490   *int_range_start = value->data[0].v_int;
491   *int_range_end = value->data[1].v_int;
492
493   return NULL;
494 }
495
496 /**
497  * gst_value_set_int_range:
498  *
499  */
500 void
501 gst_value_set_int_range (GValue * value, int start, int end)
502 {
503   g_return_if_fail (GST_VALUE_HOLDS_INT_RANGE (value));
504
505   value->data[0].v_int = start;
506   value->data[1].v_int = end;
507 }
508
509 /**
510  * gst_value_get_int_range_min:
511  *
512  */
513 int
514 gst_value_get_int_range_min (const GValue * value)
515 {
516   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
517
518   return value->data[0].v_int;
519 }
520
521 /**
522  * gst_value_get_int_range_max:
523  *
524  */
525 int
526 gst_value_get_int_range_max (const GValue * value)
527 {
528   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
529
530   return value->data[1].v_int;
531 }
532
533 static void
534 gst_value_transform_int_range_string (const GValue * src_value,
535     GValue * dest_value)
536 {
537   dest_value->data[0].v_pointer = g_strdup_printf ("[%d,%d]",
538       (int) src_value->data[0].v_int, (int) src_value->data[1].v_int);
539 }
540
541 static int
542 gst_value_compare_int_range (const GValue * value1, const GValue * value2)
543 {
544   if (value2->data[0].v_int == value1->data[0].v_int &&
545       value2->data[0].v_int == value1->data[0].v_int)
546     return GST_VALUE_EQUAL;
547   return GST_VALUE_UNORDERED;
548 }
549
550 static char *
551 gst_value_serialize_int_range (const GValue * value)
552 {
553   return g_strdup_printf ("[ %d, %d ]", value->data[0].v_int,
554       value->data[1].v_int);
555 }
556
557 static gboolean
558 gst_value_deserialize_int_range (GValue * dest, const char *s)
559 {
560   g_warning ("unimplemented");
561   return FALSE;
562 }
563
564 /*************************************/
565 /* double range */
566
567 static void
568 gst_value_init_double_range (GValue * value)
569 {
570   value->data[0].v_double = 0;
571   value->data[1].v_double = 0;
572 }
573
574 static void
575 gst_value_copy_double_range (const GValue * src_value, GValue * dest_value)
576 {
577   dest_value->data[0].v_double = src_value->data[0].v_double;
578   dest_value->data[1].v_double = src_value->data[1].v_double;
579 }
580
581 static gchar *
582 gst_value_collect_double_range (GValue * value, guint n_collect_values,
583     GTypeCValue * collect_values, guint collect_flags)
584 {
585   value->data[0].v_double = collect_values[0].v_double;
586   value->data[1].v_double = collect_values[1].v_double;
587
588   return NULL;
589 }
590
591 static gchar *
592 gst_value_lcopy_double_range (const GValue * value, guint n_collect_values,
593     GTypeCValue * collect_values, guint collect_flags)
594 {
595   gdouble *double_range_start = collect_values[0].v_pointer;
596   gdouble *double_range_end = collect_values[1].v_pointer;
597
598   if (!double_range_start)
599     return g_strdup_printf ("start value location for `%s' passed as NULL",
600         G_VALUE_TYPE_NAME (value));
601   if (!double_range_end)
602     return g_strdup_printf ("end value location for `%s' passed as NULL",
603         G_VALUE_TYPE_NAME (value));
604
605   *double_range_start = value->data[0].v_double;
606   *double_range_end = value->data[1].v_double;
607
608   return NULL;
609 }
610
611 /**
612  * gst_value_set_double_range:
613  *
614  */
615 void
616 gst_value_set_double_range (GValue * value, double start, double end)
617 {
618   g_return_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value));
619
620   value->data[0].v_double = start;
621   value->data[1].v_double = end;
622 }
623
624 /**
625  * gst_value_get_double_range_min:
626  *
627  */
628 double
629 gst_value_get_double_range_min (const GValue * value)
630 {
631   g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
632
633   return value->data[0].v_double;
634 }
635
636 /**
637  * gst_value_get_double_range_max:
638  *
639  */
640 double
641 gst_value_get_double_range_max (const GValue * value)
642 {
643   g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
644
645   return value->data[1].v_double;
646 }
647
648 static void
649 gst_value_transform_double_range_string (const GValue * src_value,
650     GValue * dest_value)
651 {
652   char s1[G_ASCII_DTOSTR_BUF_SIZE], s2[G_ASCII_DTOSTR_BUF_SIZE];
653
654   dest_value->data[0].v_pointer = g_strdup_printf ("[%s,%s]",
655       g_ascii_dtostr (s1, G_ASCII_DTOSTR_BUF_SIZE,
656           src_value->data[0].v_double),
657       g_ascii_dtostr (s2, G_ASCII_DTOSTR_BUF_SIZE,
658           src_value->data[1].v_double));
659 }
660
661 static int
662 gst_value_compare_double_range (const GValue * value1, const GValue * value2)
663 {
664   if (value2->data[0].v_double == value1->data[0].v_double &&
665       value2->data[0].v_double == value1->data[0].v_double)
666     return GST_VALUE_EQUAL;
667   return GST_VALUE_UNORDERED;
668 }
669
670 static char *
671 gst_value_serialize_double_range (const GValue * value)
672 {
673   char d1[G_ASCII_DTOSTR_BUF_SIZE];
674   char d2[G_ASCII_DTOSTR_BUF_SIZE];
675
676   g_ascii_dtostr (d1, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
677   g_ascii_dtostr (d2, G_ASCII_DTOSTR_BUF_SIZE, value->data[1].v_double);
678   return g_strdup_printf ("[ %s, %s ]", d1, d2);
679 }
680
681 static gboolean
682 gst_value_deserialize_double_range (GValue * dest, const char *s)
683 {
684   g_warning ("unimplemented");
685   return FALSE;
686 }
687
688 /*************************************/
689 /* GstCaps */
690
691 /**
692  * gst_value_set_caps:
693  *
694  */
695 void
696 gst_value_set_caps (GValue * value, const GstCaps * caps)
697 {
698   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS);
699
700   g_value_set_boxed (value, caps);
701 }
702
703 /**
704  * gst_value_get_caps:
705  *
706  */
707 const GstCaps *
708 gst_value_get_caps (const GValue * value)
709 {
710   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS, NULL);
711
712   return (GstCaps *) g_value_get_boxed (value);
713 }
714
715 /*************************************/
716 /* boolean */
717
718 static int
719 gst_value_compare_boolean (const GValue * value1, const GValue * value2)
720 {
721   if ((value1->data[0].v_int != 0) == (value2->data[0].v_int != 0))
722     return GST_VALUE_EQUAL;
723   return GST_VALUE_UNORDERED;
724 }
725
726 static char *
727 gst_value_serialize_boolean (const GValue * value)
728 {
729   if (value->data[0].v_int) {
730     return g_strdup ("true");
731   }
732   return g_strdup ("false");
733 }
734
735 static gboolean
736 gst_value_deserialize_boolean (GValue * dest, const char *s)
737 {
738   gboolean ret = FALSE;
739
740   if (g_ascii_strcasecmp (s, "true") == 0 ||
741       g_ascii_strcasecmp (s, "yes") == 0 ||
742       g_ascii_strcasecmp (s, "t") == 0 || strcmp (s, "1") == 0) {
743     g_value_set_boolean (dest, TRUE);
744     ret = TRUE;
745   } else if (g_ascii_strcasecmp (s, "false") == 0 ||
746       g_ascii_strcasecmp (s, "no") == 0 ||
747       g_ascii_strcasecmp (s, "f") == 0 || strcmp (s, "0") == 0) {
748     g_value_set_boolean (dest, FALSE);
749     ret = TRUE;
750   }
751
752   return ret;
753 }
754
755 /*************************************/
756 /* int */
757
758 static int
759 gst_value_compare_int (const GValue * value1, const GValue * value2)
760 {
761   if (value1->data[0].v_int > value2->data[0].v_int)
762     return GST_VALUE_GREATER_THAN;
763   if (value1->data[0].v_int < value2->data[0].v_int)
764     return GST_VALUE_LESS_THAN;
765   return GST_VALUE_EQUAL;
766 }
767
768 static char *
769 gst_value_serialize_int (const GValue * value)
770 {
771   return g_strdup_printf ("%d", value->data[0].v_int);
772 }
773
774 static int
775 gst_strtoi (const char *s, char **end, int base)
776 {
777   int i;
778
779   if (s[0] == '-') {
780     i = -(int) strtoul (s + 1, end, base);
781   } else {
782     i = strtoul (s, end, base);
783   }
784
785   return i;
786 }
787
788 static gboolean
789 gst_value_deserialize_int (GValue * dest, const char *s)
790 {
791   int x;
792   char *end;
793   gboolean ret = FALSE;
794
795   x = gst_strtoi (s, &end, 0);
796   if (*end == 0) {
797     ret = TRUE;
798   } else {
799     if (g_ascii_strcasecmp (s, "little_endian") == 0) {
800       x = G_LITTLE_ENDIAN;
801       ret = TRUE;
802     } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {
803       x = G_BIG_ENDIAN;
804       ret = TRUE;
805     } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {
806       x = G_BYTE_ORDER;
807       ret = TRUE;
808     } else if (g_ascii_strcasecmp (s, "min") == 0) {
809       x = G_MININT;
810       ret = TRUE;
811     } else if (g_ascii_strcasecmp (s, "max") == 0) {
812       x = G_MAXINT;
813       ret = TRUE;
814     }
815   }
816   if (ret) {
817     g_value_set_int (dest, x);
818   }
819   return ret;
820 }
821
822 /*************************************/
823 /* double */
824
825 static int
826 gst_value_compare_double (const GValue * value1, const GValue * value2)
827 {
828   if (value1->data[0].v_double > value2->data[0].v_double)
829     return GST_VALUE_GREATER_THAN;
830   if (value1->data[0].v_double < value2->data[0].v_double)
831     return GST_VALUE_LESS_THAN;
832   if (value1->data[0].v_double == value2->data[0].v_double)
833     return GST_VALUE_EQUAL;
834   return GST_VALUE_UNORDERED;
835 }
836
837 static char *
838 gst_value_serialize_double (const GValue * value)
839 {
840   char d[G_ASCII_DTOSTR_BUF_SIZE];
841
842   g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
843   return g_strdup (d);
844 }
845
846 static gboolean
847 gst_value_deserialize_double (GValue * dest, const char *s)
848 {
849   double x;
850   gboolean ret = FALSE;
851   char *end;
852
853   x = g_ascii_strtod (s, &end);
854   if (*end == 0) {
855     ret = TRUE;
856   } else {
857     if (g_ascii_strcasecmp (s, "min") == 0) {
858       x = -G_MAXDOUBLE;
859       ret = TRUE;
860     } else if (g_ascii_strcasecmp (s, "max") == 0) {
861       x = G_MAXDOUBLE;
862       ret = TRUE;
863     }
864   }
865   if (ret) {
866     g_value_set_double (dest, x);
867   }
868   return ret;
869 }
870
871 /*************************************/
872 /* string */
873
874 static int
875 gst_value_compare_string (const GValue * value1, const GValue * value2)
876 {
877   int x = strcmp (value1->data[0].v_pointer, value2->data[0].v_pointer);
878
879   if (x < 0)
880     return GST_VALUE_LESS_THAN;
881   if (x > 0)
882     return GST_VALUE_GREATER_THAN;
883   return GST_VALUE_EQUAL;
884 }
885
886 #define GST_ASCII_IS_STRING(c) (g_ascii_isalnum((c)) || ((c) == '_') || \
887     ((c) == '-') || ((c) == '+') || ((c) == '/') || ((c) == ':') || \
888     ((c) == '.'))
889
890 static gchar *
891 gst_string_wrap (const char *s)
892 {
893   const gchar *t;
894   int len;
895   gchar *d, *e;
896   gboolean wrap = FALSE;
897
898   len = 0;
899   t = s;
900   while (*t) {
901     if (GST_ASCII_IS_STRING (*t)) {
902       len++;
903     } else if (*t < 0x20 || *t >= 0x7f) {
904       wrap = TRUE;
905       len += 4;
906     } else {
907       wrap = TRUE;
908       len += 2;
909     }
910     t++;
911   }
912
913   if (!wrap)
914     return strdup (s);
915
916   e = d = g_malloc (len + 3);
917
918   *e++ = '\"';
919   t = s;
920   while (*t) {
921     if (GST_ASCII_IS_STRING (*t)) {
922       *e++ = *t++;
923     } else if (*t < 0x20 || *t >= 0x7f) {
924       *e++ = '\\';
925       *e++ = '0' + ((*t) >> 6);
926       *e++ = '0' + (((*t) >> 3) & 0x7);
927       *e++ = '0' + ((*t++) & 0x7);
928     } else {
929       *e++ = '\\';
930       *e++ = *t++;
931     }
932   }
933   *e++ = '\"';
934   *e = 0;
935
936   return d;
937 }
938
939 static char *
940 gst_value_serialize_string (const GValue * value)
941 {
942   return gst_string_wrap (value->data[0].v_pointer);
943 }
944
945 static gboolean
946 gst_value_deserialize_string (GValue * dest, const char *s)
947 {
948   g_value_set_string (dest, s);
949
950   return TRUE;
951 }
952
953 /*************************************/
954 /* unions */
955
956 /*************************************/
957 /* intersection */
958
959 static gboolean
960 gst_value_intersect_int_int_range (GValue * dest, const GValue * src1,
961     const GValue * src2)
962 {
963   g_return_val_if_fail (G_VALUE_TYPE (src1) == G_TYPE_INT, FALSE);
964   g_return_val_if_fail (G_VALUE_TYPE (src2) == GST_TYPE_INT_RANGE, FALSE);
965
966   if (src2->data[0].v_int <= src1->data[0].v_int &&
967       src2->data[1].v_int >= src1->data[0].v_int) {
968     gst_value_init_and_copy (dest, src1);
969     return TRUE;
970   }
971
972   return FALSE;
973 }
974
975 static gboolean
976 gst_value_intersect_int_range_int_range (GValue * dest, const GValue * src1,
977     const GValue * src2)
978 {
979   int min;
980   int max;
981
982   g_return_val_if_fail (G_VALUE_TYPE (src1) == GST_TYPE_INT_RANGE, FALSE);
983   g_return_val_if_fail (G_VALUE_TYPE (src2) == GST_TYPE_INT_RANGE, FALSE);
984
985   min = MAX (src1->data[0].v_int, src2->data[0].v_int);
986   max = MIN (src1->data[1].v_int, src2->data[1].v_int);
987
988   if (min < max) {
989     g_value_init (dest, GST_TYPE_INT_RANGE);
990     gst_value_set_int_range (dest, min, max);
991     return TRUE;
992   }
993   if (min == max) {
994     g_value_init (dest, G_TYPE_INT);
995     g_value_set_int (dest, min);
996     return TRUE;
997   }
998
999   return FALSE;
1000 }
1001
1002 static gboolean
1003 gst_value_intersect_double_double_range (GValue * dest, const GValue * src1,
1004     const GValue * src2)
1005 {
1006   g_return_val_if_fail (G_VALUE_TYPE (src1) == G_TYPE_DOUBLE, FALSE);
1007   g_return_val_if_fail (G_VALUE_TYPE (src2) == GST_TYPE_DOUBLE_RANGE, FALSE);
1008
1009   if (src2->data[0].v_double <= src1->data[0].v_double &&
1010       src2->data[1].v_double >= src1->data[0].v_double) {
1011     gst_value_init_and_copy (dest, src1);
1012     return TRUE;
1013   }
1014
1015   return FALSE;
1016 }
1017
1018 static gboolean
1019 gst_value_intersect_double_range_double_range (GValue * dest,
1020     const GValue * src1, const GValue * src2)
1021 {
1022   double min;
1023   double max;
1024
1025   g_return_val_if_fail (G_VALUE_TYPE (src1) == GST_TYPE_DOUBLE_RANGE, FALSE);
1026   g_return_val_if_fail (G_VALUE_TYPE (src2) == GST_TYPE_DOUBLE_RANGE, FALSE);
1027
1028   min = MAX (src1->data[0].v_double, src2->data[0].v_double);
1029   max = MIN (src1->data[1].v_double, src2->data[1].v_double);
1030
1031   if (min < max) {
1032     g_value_init (dest, GST_TYPE_DOUBLE_RANGE);
1033     gst_value_set_double_range (dest, min, max);
1034     return TRUE;
1035   }
1036   if (min == max) {
1037     g_value_init (dest, G_TYPE_DOUBLE);
1038     g_value_set_int (dest, min);
1039     return TRUE;
1040   }
1041
1042   return FALSE;
1043 }
1044
1045 static gboolean
1046 gst_value_intersect_list (GValue * dest, const GValue * value1,
1047     const GValue * value2)
1048 {
1049   guint i, size;
1050   GValue intersection = { 0, };
1051   gboolean ret = FALSE;
1052
1053   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value1), FALSE);
1054
1055   size = gst_value_list_get_size (value1);
1056   for (i = 0; i < size; i++) {
1057     const GValue *cur = gst_value_list_get_value (value1, i);
1058
1059     if (gst_value_intersect (&intersection, cur, value2)) {
1060       /* append value */
1061       if (!ret) {
1062         gst_value_init_and_copy (dest, &intersection);
1063         ret = TRUE;
1064       } else if (GST_VALUE_HOLDS_LIST (dest)) {
1065         gst_value_list_append_value (dest, &intersection);
1066       } else {
1067         GValue temp = { 0, };
1068
1069         gst_value_init_and_copy (&temp, dest);
1070         g_value_unset (dest);
1071         gst_value_list_concat (dest, &temp, &intersection);
1072       }
1073       g_value_unset (&intersection);
1074     }
1075   }
1076
1077   return ret;
1078 }
1079
1080
1081 /*************************************/
1082
1083 /**
1084  * gst_value_can_compare:
1085  *
1086  */
1087 gboolean
1088 gst_value_can_compare (const GValue * value1, const GValue * value2)
1089 {
1090   GstValueTable *table;
1091   int i;
1092
1093   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
1094     return FALSE;
1095   for (i = 0; i < gst_value_table->len; i++) {
1096     table = &g_array_index (gst_value_table, GstValueTable, i);
1097     if (table->type == G_VALUE_TYPE (value1) && table->compare)
1098       return TRUE;
1099   }
1100
1101   return FALSE;
1102 }
1103
1104 /**
1105  * gst_value_compare:
1106  *
1107  */
1108 int
1109 gst_value_compare (const GValue * value1, const GValue * value2)
1110 {
1111   GstValueTable *table;
1112   int i;
1113
1114   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
1115     return GST_VALUE_UNORDERED;
1116
1117   for (i = 0; i < gst_value_table->len; i++) {
1118     table = &g_array_index (gst_value_table, GstValueTable, i);
1119     if (table->type != G_VALUE_TYPE (value1) || table->compare == NULL)
1120       continue;
1121
1122     return table->compare (value1, value2);
1123   }
1124
1125   g_critical ("unable to compare values of type %s\n",
1126       g_type_name (G_VALUE_TYPE (value1)));
1127   return GST_VALUE_UNORDERED;
1128 }
1129
1130 /* union */
1131
1132 /**
1133  * gst_value_can_union:
1134  *
1135  */
1136 gboolean
1137 gst_value_can_union (const GValue * value1, const GValue * value2)
1138 {
1139   GstValueUnionInfo *union_info;
1140   int i;
1141
1142   for (i = 0; i < gst_value_union_funcs->len; i++) {
1143     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
1144     if (union_info->type1 == G_VALUE_TYPE (value1) &&
1145         union_info->type2 == G_VALUE_TYPE (value2))
1146       return TRUE;
1147   }
1148
1149   return FALSE;
1150 }
1151
1152 /**
1153  * gst_value_union:
1154  *
1155  */
1156 gboolean
1157 gst_value_union (GValue * dest, const GValue * value1, const GValue * value2)
1158 {
1159   GstValueUnionInfo *union_info;
1160   int i;
1161
1162   for (i = 0; i < gst_value_union_funcs->len; i++) {
1163     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
1164     if (union_info->type1 == G_VALUE_TYPE (value1) &&
1165         union_info->type2 == G_VALUE_TYPE (value2)) {
1166       return union_info->func (dest, value1, value2);
1167     }
1168   }
1169
1170   gst_value_list_concat (dest, value1, value2);
1171   return TRUE;
1172 }
1173
1174 /**
1175  * gst_value_register_union_func:
1176  *
1177  */
1178 void
1179 gst_value_register_union_func (GType type1, GType type2, GstValueUnionFunc func)
1180 {
1181   GstValueUnionInfo union_info;
1182
1183   union_info.type1 = type1;
1184   union_info.type2 = type2;
1185   union_info.func = func;
1186
1187   g_array_append_val (gst_value_union_funcs, union_info);
1188 }
1189
1190 /* intersection */
1191
1192 /**
1193  * gst_value_can_intersect:
1194  *
1195  */
1196 gboolean
1197 gst_value_can_intersect (const GValue * value1, const GValue * value2)
1198 {
1199   GstValueIntersectInfo *intersect_info;
1200   int i;
1201
1202   /* special cases */
1203   if (GST_VALUE_HOLDS_LIST (value1) || GST_VALUE_HOLDS_LIST (value2))
1204     return TRUE;
1205
1206   for (i = 0; i < gst_value_intersect_funcs->len; i++) {
1207     intersect_info = &g_array_index (gst_value_intersect_funcs,
1208         GstValueIntersectInfo, i);
1209     if (intersect_info->type1 == G_VALUE_TYPE (value1) &&
1210         intersect_info->type2 == G_VALUE_TYPE (value2))
1211       return TRUE;
1212   }
1213
1214   return gst_value_can_compare (value1, value2);
1215 }
1216
1217 /**
1218  * gst_value_intersect:
1219  *
1220  */
1221 gboolean
1222 gst_value_intersect (GValue * dest, const GValue * value1,
1223     const GValue * value2)
1224 {
1225   GstValueIntersectInfo *intersect_info;
1226   int i;
1227   int ret = FALSE;
1228
1229   /* special cases first */
1230   if (GST_VALUE_HOLDS_LIST (value1))
1231     return gst_value_intersect_list (dest, value1, value2);
1232   if (GST_VALUE_HOLDS_LIST (value2))
1233     return gst_value_intersect_list (dest, value2, value1);
1234
1235   for (i = 0; i < gst_value_intersect_funcs->len; i++) {
1236     intersect_info = &g_array_index (gst_value_intersect_funcs,
1237         GstValueIntersectInfo, i);
1238     if (intersect_info->type1 == G_VALUE_TYPE (value1) &&
1239         intersect_info->type2 == G_VALUE_TYPE (value2)) {
1240       ret = intersect_info->func (dest, value1, value2);
1241       return ret;
1242     }
1243     if (intersect_info->type1 == G_VALUE_TYPE (value2) &&
1244         intersect_info->type2 == G_VALUE_TYPE (value1)) {
1245       ret = intersect_info->func (dest, value2, value1);
1246       return ret;
1247     }
1248   }
1249
1250   if (gst_value_compare (value1, value2) == GST_VALUE_EQUAL) {
1251     gst_value_init_and_copy (dest, value1);
1252     ret = TRUE;
1253   }
1254
1255   return ret;
1256 }
1257
1258 /**
1259  * gst_value_register_intersection_func:
1260  *
1261  */
1262 void
1263 gst_value_register_intersect_func (GType type1, GType type2,
1264     GstValueIntersectFunc func)
1265 {
1266   GstValueIntersectInfo intersect_info;
1267
1268   intersect_info.type1 = type1;
1269   intersect_info.type2 = type2;
1270   intersect_info.func = func;
1271
1272   g_array_append_val (gst_value_intersect_funcs, intersect_info);
1273 }
1274
1275 /**
1276  * gst_value_register:
1277  *
1278  */
1279 void
1280 gst_value_register (const GstValueTable * table)
1281 {
1282   g_array_append_val (gst_value_table, *table);
1283 }
1284
1285 /**
1286  * gst_value_init_and_copy:
1287  *
1288  */
1289 void
1290 gst_value_init_and_copy (GValue * dest, const GValue * src)
1291 {
1292   g_value_init (dest, G_VALUE_TYPE (src));
1293   g_value_copy (src, dest);
1294 }
1295
1296 /**
1297  * gst_value_serialize:
1298  *
1299  */
1300 gchar *
1301 gst_value_serialize (const GValue * value)
1302 {
1303   int i;
1304   GValue s_val = { 0 };
1305   GstValueTable *table;
1306   char *s;
1307
1308   for (i = 0; i < gst_value_table->len; i++) {
1309     table = &g_array_index (gst_value_table, GstValueTable, i);
1310     if (table->type != G_VALUE_TYPE (value) || table->serialize == NULL)
1311       continue;
1312
1313     return table->serialize (value);
1314   }
1315
1316   g_value_init (&s_val, G_TYPE_STRING);
1317   g_value_transform (value, &s_val);
1318   s = gst_string_wrap (g_value_get_string (&s_val));
1319   g_value_unset (&s_val);
1320
1321   return s;
1322 }
1323
1324 /**
1325  * gst_value_deserialize:
1326  *
1327  */
1328 gboolean
1329 gst_value_deserialize (GValue * dest, const gchar * src)
1330 {
1331   GstValueTable *table;
1332   int i;
1333
1334   for (i = 0; i < gst_value_table->len; i++) {
1335     table = &g_array_index (gst_value_table, GstValueTable, i);
1336     if (table->type != G_VALUE_TYPE (dest) || table->deserialize == NULL)
1337       continue;
1338
1339     return table->deserialize (dest, src);
1340   }
1341
1342   return FALSE;
1343 }
1344
1345 void
1346 _gst_value_initialize (void)
1347 {
1348   GTypeInfo info = {
1349     0,
1350     NULL,
1351     NULL,
1352     NULL,
1353     NULL,
1354     NULL,
1355     0,
1356     0,
1357     NULL,
1358     NULL,
1359   };
1360
1361   //const GTypeFundamentalInfo finfo = { G_TYPE_FLAG_DERIVABLE, };
1362
1363   gst_value_table = g_array_new (FALSE, FALSE, sizeof (GstValueTable));
1364   gst_value_union_funcs = g_array_new (FALSE, FALSE,
1365       sizeof (GstValueUnionInfo));
1366   gst_value_intersect_funcs = g_array_new (FALSE, FALSE,
1367       sizeof (GstValueIntersectInfo));
1368
1369   {
1370     static const GTypeValueTable value_table = {
1371       gst_value_init_fourcc,
1372       NULL,
1373       gst_value_copy_fourcc,
1374       NULL,
1375       "i",
1376       gst_value_collect_fourcc,
1377       "p",
1378       gst_value_lcopy_fourcc
1379     };
1380     static GstValueTable gst_value = {
1381       0,
1382       gst_value_compare_fourcc,
1383       gst_value_serialize_fourcc,
1384       gst_value_deserialize_fourcc,
1385     };
1386
1387     info.value_table = &value_table;
1388     gst_type_fourcc =
1389         g_type_register_static (G_TYPE_BOXED, "GstFourcc", &info, 0);
1390     gst_value.type = gst_type_fourcc;
1391     gst_value_register (&gst_value);
1392   }
1393
1394   {
1395     static const GTypeValueTable value_table = {
1396       gst_value_init_int_range,
1397       NULL,
1398       gst_value_copy_int_range,
1399       NULL,
1400       "ii",
1401       gst_value_collect_int_range,
1402       "pp",
1403       gst_value_lcopy_int_range
1404     };
1405     static GstValueTable gst_value = {
1406       0,
1407       gst_value_compare_int_range,
1408       gst_value_serialize_int_range,
1409       gst_value_deserialize_int_range,
1410     };
1411
1412     info.value_table = &value_table;
1413     gst_type_int_range =
1414         g_type_register_static (G_TYPE_BOXED, "GstIntRange", &info, 0);
1415     gst_value.type = gst_type_int_range;
1416     gst_value_register (&gst_value);
1417   }
1418
1419   {
1420     static const GTypeValueTable value_table = {
1421       gst_value_init_double_range,
1422       NULL,
1423       gst_value_copy_double_range,
1424       NULL,
1425       "dd",
1426       gst_value_collect_double_range,
1427       "pp",
1428       gst_value_lcopy_double_range
1429     };
1430     static GstValueTable gst_value = {
1431       0,
1432       gst_value_compare_double_range,
1433       gst_value_serialize_double_range,
1434       gst_value_deserialize_double_range,
1435     };
1436
1437     info.value_table = &value_table;
1438     gst_type_double_range =
1439         g_type_register_static (G_TYPE_BOXED, "GstDoubleRange", &info, 0);
1440     gst_value.type = gst_type_double_range;
1441     gst_value_register (&gst_value);
1442   }
1443
1444   {
1445     static const GTypeValueTable value_table = {
1446       gst_value_init_list,
1447       gst_value_free_list,
1448       gst_value_copy_list,
1449       gst_value_list_peek_pointer,
1450       "p",
1451       gst_value_collect_list,
1452       "p",
1453       gst_value_lcopy_list
1454     };
1455     static GstValueTable gst_value = {
1456       0,
1457       gst_value_compare_list,
1458       gst_value_serialize_list,
1459       gst_value_deserialize_list,
1460     };
1461
1462     info.value_table = &value_table;
1463     gst_type_list =
1464         g_type_register_static (G_TYPE_BOXED, "GstValueList", &info, 0);
1465     gst_value.type = gst_type_list;
1466     gst_value_register (&gst_value);
1467   }
1468
1469   {
1470     static const GstValueTable gst_value = {
1471       G_TYPE_INT,
1472       gst_value_compare_int,
1473       gst_value_serialize_int,
1474       gst_value_deserialize_int,
1475     };
1476
1477     gst_value_register (&gst_value);
1478   }
1479
1480   {
1481     static const GstValueTable gst_value = {
1482       G_TYPE_DOUBLE,
1483       gst_value_compare_double,
1484       gst_value_serialize_double,
1485       gst_value_deserialize_double,
1486     };
1487
1488     gst_value_register (&gst_value);
1489   }
1490
1491   {
1492     static const GstValueTable gst_value = {
1493       G_TYPE_STRING,
1494       gst_value_compare_string,
1495       gst_value_serialize_string,
1496       gst_value_deserialize_string,
1497     };
1498
1499     gst_value_register (&gst_value);
1500   }
1501
1502   {
1503     static const GstValueTable gst_value = {
1504       G_TYPE_BOOLEAN,
1505       gst_value_compare_boolean,
1506       gst_value_serialize_boolean,
1507       gst_value_deserialize_boolean,
1508     };
1509
1510     gst_value_register (&gst_value);
1511   }
1512
1513   g_value_register_transform_func (GST_TYPE_FOURCC, G_TYPE_STRING,
1514       gst_value_transform_fourcc_string);
1515   g_value_register_transform_func (GST_TYPE_INT_RANGE, G_TYPE_STRING,
1516       gst_value_transform_int_range_string);
1517   g_value_register_transform_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_STRING,
1518       gst_value_transform_double_range_string);
1519   g_value_register_transform_func (GST_TYPE_LIST, G_TYPE_STRING,
1520       gst_value_transform_list_string);
1521
1522   gst_value_register_intersect_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
1523       gst_value_intersect_int_int_range);
1524   gst_value_register_intersect_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
1525       gst_value_intersect_int_range_int_range);
1526   gst_value_register_intersect_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
1527       gst_value_intersect_double_double_range);
1528   gst_value_register_intersect_func (GST_TYPE_DOUBLE_RANGE,
1529       GST_TYPE_DOUBLE_RANGE, gst_value_intersect_double_range_double_range);
1530 }