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., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 /**
21 * SECTION:gstvalue
22 * @title: GstValue
23 * @short_description: GValue implementations specific
24 * to GStreamer
25 *
26 * GValue implementations specific to GStreamer.
27 *
28 * Note that operations on the same #GValue from multiple threads may lead to
29 * undefined behaviour.
30 */
31
32 /* Suppress warnings for GValueAraray */
33 #define GLIB_DISABLE_DEPRECATION_WARNINGS
34
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38 #include <math.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <ctype.h>
43
44 #include "gst_private.h"
45 #include "glib-compat-private.h"
46 #include <gst/gst.h>
47 #include <gobject/gvaluecollector.h>
48 #include "gstutils.h"
49
50 /* GstValueUnionFunc:
51 * @dest: a #GValue for the result
52 * @value1: a #GValue operand
53 * @value2: a #GValue operand
54 *
55 * Used by gst_value_union() to perform unification for a specific #GValue
56 * type. Register a new implementation with gst_value_register_union_func().
57 *
58 * Returns: %TRUE if a union was successful
59 */
60 typedef gboolean (*GstValueUnionFunc) (GValue * dest,
61 const GValue * value1, const GValue * value2);
62
63 /* GstValueIntersectFunc:
64 * @dest: (out caller-allocates): a #GValue for the result
65 * @value1: a #GValue operand
66 * @value2: a #GValue operand
67 *
68 * Used by gst_value_intersect() to perform intersection for a specific #GValue
69 * type. If the intersection is non-empty, the result is
70 * placed in @dest and %TRUE is returned. If the intersection is
71 * empty, @dest is unmodified and %FALSE is returned.
72 * Register a new implementation with gst_value_register_intersect_func().
73 *
74 * Returns: %TRUE if the values can intersect
75 */
76 typedef gboolean (*GstValueIntersectFunc) (GValue * dest,
77 const GValue * value1, const GValue * value2);
78
79 /* GstValueSubtractFunc:
80 * @dest: (out caller-allocates): a #GValue for the result
81 * @minuend: a #GValue operand
82 * @subtrahend: a #GValue operand
83 *
84 * Used by gst_value_subtract() to perform subtraction for a specific #GValue
85 * type. Register a new implementation with gst_value_register_subtract_func().
86 *
87 * Returns: %TRUE if the subtraction is not empty
88 */
89 typedef gboolean (*GstValueSubtractFunc) (GValue * dest,
90 const GValue * minuend, const GValue * subtrahend);
91
92 static void gst_value_register_union_func (GType type1,
93 GType type2, GstValueUnionFunc func);
94 static void gst_value_register_intersect_func (GType type1,
95 GType type2, GstValueIntersectFunc func);
96 static void gst_value_register_subtract_func (GType minuend_type,
97 GType subtrahend_type, GstValueSubtractFunc func);
98
99 static gboolean _priv_gst_value_parse_list (gchar * s, gchar ** after,
100 GValue * value, GType type);
101 static gboolean _priv_gst_value_parse_array (gchar * s, gchar ** after,
102 GValue * value, GType type);
103
104 typedef struct _GstValueUnionInfo GstValueUnionInfo;
105 struct _GstValueUnionInfo
106 {
107 GType type1;
108 GType type2;
109 GstValueUnionFunc func;
110 };
111
112 typedef struct _GstValueIntersectInfo GstValueIntersectInfo;
113 struct _GstValueIntersectInfo
114 {
115 GType type1;
116 GType type2;
117 GstValueIntersectFunc func;
118 };
119
120 typedef struct _GstValueSubtractInfo GstValueSubtractInfo;
121 struct _GstValueSubtractInfo
122 {
123 GType minuend;
124 GType subtrahend;
125 GstValueSubtractFunc func;
126 };
127
128 struct _GstFlagSetClass
129 {
130 GTypeClass parent;
131 GType flags_type; /* Type of the GFlags this flagset carries (can be 0) */
132 };
133
134 typedef struct _GstFlagSetClass GstFlagSetClass;
135
136 typedef struct _GstValueAbbreviation GstValueAbbreviation;
137
138 struct _GstValueAbbreviation
139 {
140 const gchar *type_name;
141 GType type;
142 };
143
144 #define FUNDAMENTAL_TYPE_ID_MAX \
145 (G_TYPE_FUNDAMENTAL_MAX >> G_TYPE_FUNDAMENTAL_SHIFT)
146 #define FUNDAMENTAL_TYPE_ID(type) \
147 ((type) >> G_TYPE_FUNDAMENTAL_SHIFT)
148
149 #define VALUE_LIST_ARRAY(v) ((GArray *) (v)->data[0].v_pointer)
150 #define VALUE_LIST_SIZE(v) (VALUE_LIST_ARRAY(v)->len)
151 #define VALUE_LIST_GET_VALUE(v, index) ((const GValue *) &g_array_index (VALUE_LIST_ARRAY(v), GValue, (index)))
152
153 static GArray *gst_value_table;
154 static GHashTable *gst_value_hash;
155 static GstValueTable *gst_value_tables_fundamental[FUNDAMENTAL_TYPE_ID_MAX + 1];
156 static GArray *gst_value_union_funcs;
157 static GArray *gst_value_intersect_funcs;
158 static GArray *gst_value_subtract_funcs;
159
160 /* Forward declarations */
161 static gchar *gst_value_serialize_fraction (const GValue * value);
162
163 static GstValueCompareFunc gst_value_get_compare_func (const GValue * value1);
164 static gint gst_value_compare_with_func (const GValue * value1,
165 const GValue * value2, GstValueCompareFunc compare);
166
167 static gchar *gst_string_wrap (const gchar * s);
168 static gchar *gst_string_unwrap (const gchar * s);
169
170 static void gst_value_move (GValue * dest, GValue * src);
171 static void _gst_value_list_append_and_take_value (GValue * value,
172 GValue * append_value);
173 static void _gst_value_array_append_and_take_value (GValue * value,
174 GValue * append_value);
175
176 static inline GstValueTable *
gst_value_hash_lookup_type(GType type)177 gst_value_hash_lookup_type (GType type)
178 {
179 if (G_LIKELY (G_TYPE_IS_FUNDAMENTAL (type)))
180 return gst_value_tables_fundamental[FUNDAMENTAL_TYPE_ID (type)];
181 else
182 return g_hash_table_lookup (gst_value_hash, (gpointer) type);
183 }
184
185 static void
gst_value_hash_add_type(GType type,const GstValueTable * table)186 gst_value_hash_add_type (GType type, const GstValueTable * table)
187 {
188 if (G_TYPE_IS_FUNDAMENTAL (type))
189 gst_value_tables_fundamental[FUNDAMENTAL_TYPE_ID (type)] = (gpointer) table;
190
191 g_hash_table_insert (gst_value_hash, (gpointer) type, (gpointer) table);
192 }
193
194 /********
195 * list *
196 ********/
197
198 /* two helper functions to serialize/stringify any type of list
199 * regular lists are done with { }, arrays with < >
200 */
201 gchar *
_priv_gst_value_serialize_any_list(const GValue * value,const gchar * begin,const gchar * end,gboolean print_type)202 _priv_gst_value_serialize_any_list (const GValue * value, const gchar * begin,
203 const gchar * end, gboolean print_type)
204 {
205 guint i;
206 GArray *array = value->data[0].v_pointer;
207 GString *s;
208 GValue *v;
209 gchar *s_val;
210 guint alen = array->len;
211
212 /* estimate minimum string length to minimise re-allocs in GString */
213 s = g_string_sized_new (2 + (6 * alen) + 2);
214 g_string_append (s, begin);
215 for (i = 0; i < alen; i++) {
216 v = &g_array_index (array, GValue, i);
217 s_val = gst_value_serialize (v);
218 if (s_val != NULL) {
219 if (print_type) {
220 g_string_append_c (s, '(');
221 g_string_append (s, _priv_gst_value_gtype_to_abbr (G_VALUE_TYPE (v)));
222 g_string_append_c (s, ')');
223 }
224 g_string_append (s, s_val);
225 g_free (s_val);
226 if (i < alen - 1) {
227 g_string_append_len (s, ", ", 2);
228 }
229 } else {
230 GST_WARNING ("Could not serialize list/array value of type '%s'",
231 G_VALUE_TYPE_NAME (v));
232 }
233 }
234 g_string_append (s, end);
235 return g_string_free (s, FALSE);
236 }
237
238 static void
gst_value_transform_any_list_string(const GValue * src_value,GValue * dest_value,const gchar * begin,const gchar * end)239 gst_value_transform_any_list_string (const GValue * src_value,
240 GValue * dest_value, const gchar * begin, const gchar * end)
241 {
242 GValue *list_value;
243 GArray *array;
244 GString *s;
245 guint i;
246 gchar *list_s;
247 guint alen;
248
249 array = src_value->data[0].v_pointer;
250 alen = array->len;
251
252 /* estimate minimum string length to minimise re-allocs in GString */
253 s = g_string_sized_new (2 + (10 * alen) + 2);
254 g_string_append (s, begin);
255 for (i = 0; i < alen; i++) {
256 list_value = &g_array_index (array, GValue, i);
257
258 if (i != 0) {
259 g_string_append_len (s, ", ", 2);
260 }
261 list_s = g_strdup_value_contents (list_value);
262 g_string_append (s, list_s);
263 g_free (list_s);
264 }
265 g_string_append (s, end);
266
267 dest_value->data[0].v_pointer = g_string_free (s, FALSE);
268 }
269
270 static gchar *
_gst_value_serialize_g_value_array(const GValue * value,const gchar * begin,const gchar * end)271 _gst_value_serialize_g_value_array (const GValue * value, const gchar * begin,
272 const gchar * end)
273 {
274 guint i;
275 GValueArray *array = value->data[0].v_pointer;
276 GString *s;
277 GValue *v;
278 gchar *s_val;
279 guint alen = 0;
280
281 if (array)
282 alen = array->n_values;
283
284 /* estimate minimum string length to minimise re-allocs in GString */
285 s = g_string_sized_new (2 + (6 * alen) + 2);
286 g_string_append (s, begin);
287 for (i = 0; i < alen; i++) {
288 v = g_value_array_get_nth (array, i);
289 s_val = gst_value_serialize (v);
290 if (s_val != NULL) {
291 g_string_append (s, s_val);
292 g_free (s_val);
293 if (i < alen - 1) {
294 g_string_append_len (s, ", ", 2);
295 }
296 } else {
297 GST_WARNING ("Could not serialize list/array value of type '%s'",
298 G_VALUE_TYPE_NAME (v));
299 }
300 }
301 g_string_append (s, end);
302 return g_string_free (s, FALSE);
303 }
304
305 static void
_gst_value_transform_g_value_array_string(const GValue * src_value,GValue * dest_value,const gchar * begin,const gchar * end)306 _gst_value_transform_g_value_array_string (const GValue * src_value,
307 GValue * dest_value, const gchar * begin, const gchar * end)
308 {
309 GValue *list_value;
310 GValueArray *array;
311 GString *s;
312 guint i;
313 gchar *list_s;
314 guint alen;
315
316 array = src_value->data[0].v_pointer;
317 alen = array->n_values;
318
319 /* estimate minimum string length to minimise re-allocs in GString */
320 s = g_string_sized_new (2 + (10 * alen) + 2);
321 g_string_append (s, begin);
322 for (i = 0; i < alen; i++) {
323 list_value = g_value_array_get_nth (array, i);
324
325 if (i != 0) {
326 g_string_append_len (s, ", ", 2);
327 }
328 list_s = g_strdup_value_contents (list_value);
329 g_string_append (s, list_s);
330 g_free (list_s);
331 }
332 g_string_append (s, end);
333
334 dest_value->data[0].v_pointer = g_string_free (s, FALSE);
335 }
336
337 /*
338 * helper function to see if a type is fixed. Is used internally here and
339 * there. Do not export, since it doesn't work for types where the content
340 * decides the fixedness (e.g. GST_TYPE_ARRAY).
341 */
342 static gboolean
gst_type_is_fixed(GType type)343 gst_type_is_fixed (GType type)
344 {
345 /* the basic int, string, double types */
346 if (type <= G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
347 return TRUE;
348 }
349 /* our fundamental types that are certainly not fixed */
350 if (type == GST_TYPE_INT_RANGE || type == GST_TYPE_DOUBLE_RANGE ||
351 type == GST_TYPE_INT64_RANGE ||
352 type == GST_TYPE_LIST || type == GST_TYPE_FRACTION_RANGE ||
353 type == GST_TYPE_STRUCTURE) {
354 return FALSE;
355 }
356 /* other (boxed) types that are fixed */
357 if (type == GST_TYPE_BUFFER) {
358 return TRUE;
359 }
360 /* heavy checks */
361 if (G_TYPE_IS_FUNDAMENTAL (type) || G_TYPE_FUNDAMENTAL (type) <=
362 G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
363 return TRUE;
364 }
365
366 return FALSE;
367 }
368
369 /* GValue functions usable for both regular lists and arrays */
370 static void
gst_value_init_list_or_array(GValue * value)371 gst_value_init_list_or_array (GValue * value)
372 {
373 value->data[0].v_pointer = g_array_new (FALSE, TRUE, sizeof (GValue));
374 }
375
376 static GArray *
copy_garray_of_gstvalue(const GArray * src)377 copy_garray_of_gstvalue (const GArray * src)
378 {
379 GArray *dest;
380 guint i, len;
381
382 len = src->len;
383 dest = g_array_sized_new (FALSE, TRUE, sizeof (GValue), len);
384 g_array_set_size (dest, len);
385 for (i = 0; i < len; i++) {
386 gst_value_init_and_copy (&g_array_index (dest, GValue, i),
387 &g_array_index (src, GValue, i));
388 }
389
390 return dest;
391 }
392
393 static void
gst_value_copy_list_or_array(const GValue * src_value,GValue * dest_value)394 gst_value_copy_list_or_array (const GValue * src_value, GValue * dest_value)
395 {
396 dest_value->data[0].v_pointer =
397 copy_garray_of_gstvalue ((GArray *) src_value->data[0].v_pointer);
398 }
399
400 static void
gst_value_free_list_or_array(GValue * value)401 gst_value_free_list_or_array (GValue * value)
402 {
403 guint i, len;
404 GArray *src = (GArray *) value->data[0].v_pointer;
405 len = src->len;
406
407 if ((value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS) == 0) {
408 for (i = 0; i < len; i++) {
409 g_value_unset (&g_array_index (src, GValue, i));
410 }
411 g_array_free (src, TRUE);
412 }
413 }
414
415 static gpointer
gst_value_list_or_array_peek_pointer(const GValue * value)416 gst_value_list_or_array_peek_pointer (const GValue * value)
417 {
418 return value->data[0].v_pointer;
419 }
420
421 static gchar *
gst_value_collect_list_or_array(GValue * value,guint n_collect_values,GTypeCValue * collect_values,guint collect_flags)422 gst_value_collect_list_or_array (GValue * value, guint n_collect_values,
423 GTypeCValue * collect_values, guint collect_flags)
424 {
425 if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
426 value->data[0].v_pointer = collect_values[0].v_pointer;
427 value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
428 } else {
429 value->data[0].v_pointer =
430 copy_garray_of_gstvalue ((GArray *) collect_values[0].v_pointer);
431 }
432 return NULL;
433 }
434
435 static gchar *
gst_value_lcopy_list_or_array(const GValue * value,guint n_collect_values,GTypeCValue * collect_values,guint collect_flags)436 gst_value_lcopy_list_or_array (const GValue * value, guint n_collect_values,
437 GTypeCValue * collect_values, guint collect_flags)
438 {
439 GArray **dest = collect_values[0].v_pointer;
440
441 if (!dest)
442 return g_strdup_printf ("value location for `%s' passed as NULL",
443 G_VALUE_TYPE_NAME (value));
444 if (!value->data[0].v_pointer)
445 return g_strdup_printf ("invalid value given for `%s'",
446 G_VALUE_TYPE_NAME (value));
447 if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
448 *dest = (GArray *) value->data[0].v_pointer;
449 } else {
450 *dest = copy_garray_of_gstvalue ((GArray *) value->data[0].v_pointer);
451 }
452 return NULL;
453 }
454
455 static gboolean
gst_value_list_or_array_get_basic_type(const GValue * value,GType * type)456 gst_value_list_or_array_get_basic_type (const GValue * value, GType * type)
457 {
458 if (G_UNLIKELY (value == NULL))
459 return FALSE;
460
461 if (GST_VALUE_HOLDS_LIST (value)) {
462 if (VALUE_LIST_SIZE (value) == 0)
463 return FALSE;
464 return gst_value_list_or_array_get_basic_type (VALUE_LIST_GET_VALUE (value,
465 0), type);
466 }
467 if (GST_VALUE_HOLDS_ARRAY (value)) {
468 const GArray *array = (const GArray *) value->data[0].v_pointer;
469 if (array->len == 0)
470 return FALSE;
471 return gst_value_list_or_array_get_basic_type (&g_array_index (array,
472 GValue, 0), type);
473 }
474
475 *type = G_VALUE_TYPE (value);
476
477 return TRUE;
478 }
479
480 #define IS_RANGE_COMPAT(type1,type2,t1,t2) \
481 (((t1) == (type1) && (t2) == (type2)) || ((t2) == (type1) && (t1) == (type2)))
482
483 static gboolean
gst_value_list_or_array_are_compatible(const GValue * value1,const GValue * value2)484 gst_value_list_or_array_are_compatible (const GValue * value1,
485 const GValue * value2)
486 {
487 GType basic_type1, basic_type2;
488
489 /* empty or same type is OK */
490 if (!gst_value_list_or_array_get_basic_type (value1, &basic_type1) ||
491 !gst_value_list_or_array_get_basic_type (value2, &basic_type2) ||
492 basic_type1 == basic_type2)
493 return TRUE;
494
495 /* ranges are distinct types for each bound type... */
496 if (IS_RANGE_COMPAT (G_TYPE_INT, GST_TYPE_INT_RANGE, basic_type1,
497 basic_type2))
498 return TRUE;
499 if (IS_RANGE_COMPAT (G_TYPE_INT64, GST_TYPE_INT64_RANGE, basic_type1,
500 basic_type2))
501 return TRUE;
502 if (IS_RANGE_COMPAT (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE, basic_type1,
503 basic_type2))
504 return TRUE;
505 if (IS_RANGE_COMPAT (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE, basic_type1,
506 basic_type2))
507 return TRUE;
508
509 return FALSE;
510 }
511
512 static inline void
_gst_value_list_append_and_take_value(GValue * value,GValue * append_value)513 _gst_value_list_append_and_take_value (GValue * value, GValue * append_value)
514 {
515 g_array_append_vals ((GArray *) value->data[0].v_pointer, append_value, 1);
516 memset (append_value, 0, sizeof (GValue));
517 }
518
519 /**
520 * gst_value_list_append_and_take_value:
521 * @value: a #GValue of type #GST_TYPE_LIST
522 * @append_value: (transfer full): the value to append
523 *
524 * Appends @append_value to the GstValueList in @value.
525 *
526 * Since: 1.2
527 */
528 void
gst_value_list_append_and_take_value(GValue * value,GValue * append_value)529 gst_value_list_append_and_take_value (GValue * value, GValue * append_value)
530 {
531 g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
532 g_return_if_fail (G_IS_VALUE (append_value));
533 g_return_if_fail (gst_value_list_or_array_are_compatible (value,
534 append_value));
535
536 _gst_value_list_append_and_take_value (value, append_value);
537 }
538
539 /**
540 * gst_value_list_append_value:
541 * @value: a #GValue of type #GST_TYPE_LIST
542 * @append_value: (transfer none): the value to append
543 *
544 * Appends @append_value to the GstValueList in @value.
545 */
546 void
gst_value_list_append_value(GValue * value,const GValue * append_value)547 gst_value_list_append_value (GValue * value, const GValue * append_value)
548 {
549 GValue val = { 0, };
550
551 g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
552 g_return_if_fail (G_IS_VALUE (append_value));
553 g_return_if_fail (gst_value_list_or_array_are_compatible (value,
554 append_value));
555
556 gst_value_init_and_copy (&val, append_value);
557 g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1);
558 }
559
560 /**
561 * gst_value_list_prepend_value:
562 * @value: a #GValue of type #GST_TYPE_LIST
563 * @prepend_value: the value to prepend
564 *
565 * Prepends @prepend_value to the GstValueList in @value.
566 */
567 void
gst_value_list_prepend_value(GValue * value,const GValue * prepend_value)568 gst_value_list_prepend_value (GValue * value, const GValue * prepend_value)
569 {
570 GValue val = { 0, };
571
572 g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
573 g_return_if_fail (G_IS_VALUE (prepend_value));
574 g_return_if_fail (gst_value_list_or_array_are_compatible (value,
575 prepend_value));
576
577 gst_value_init_and_copy (&val, prepend_value);
578 g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1);
579 }
580
581 /**
582 * gst_value_list_concat:
583 * @dest: (out caller-allocates): an uninitialized #GValue to take the result
584 * @value1: a #GValue
585 * @value2: a #GValue
586 *
587 * Concatenates copies of @value1 and @value2 into a list. Values that are not
588 * of type #GST_TYPE_LIST are treated as if they were lists of length 1.
589 * @dest will be initialized to the type #GST_TYPE_LIST.
590 */
591 void
gst_value_list_concat(GValue * dest,const GValue * value1,const GValue * value2)592 gst_value_list_concat (GValue * dest, const GValue * value1,
593 const GValue * value2)
594 {
595 guint i, value1_length, value2_length;
596 GArray *array;
597
598 g_return_if_fail (dest != NULL);
599 g_return_if_fail (G_VALUE_TYPE (dest) == 0);
600 g_return_if_fail (G_IS_VALUE (value1));
601 g_return_if_fail (G_IS_VALUE (value2));
602 g_return_if_fail (gst_value_list_or_array_are_compatible (value1, value2));
603
604 value1_length =
605 (GST_VALUE_HOLDS_LIST (value1) ? VALUE_LIST_SIZE (value1) : 1);
606 value2_length =
607 (GST_VALUE_HOLDS_LIST (value2) ? VALUE_LIST_SIZE (value2) : 1);
608 g_value_init (dest, GST_TYPE_LIST);
609 array = (GArray *) dest->data[0].v_pointer;
610 g_array_set_size (array, value1_length + value2_length);
611
612 if (GST_VALUE_HOLDS_LIST (value1)) {
613 for (i = 0; i < value1_length; i++) {
614 gst_value_init_and_copy (&g_array_index (array, GValue, i),
615 VALUE_LIST_GET_VALUE (value1, i));
616 }
617 } else {
618 gst_value_init_and_copy (&g_array_index (array, GValue, 0), value1);
619 }
620
621 if (GST_VALUE_HOLDS_LIST (value2)) {
622 for (i = 0; i < value2_length; i++) {
623 gst_value_init_and_copy (&g_array_index (array, GValue,
624 i + value1_length), VALUE_LIST_GET_VALUE (value2, i));
625 }
626 } else {
627 gst_value_init_and_copy (&g_array_index (array, GValue, value1_length),
628 value2);
629 }
630 }
631
632 /* same as gst_value_list_concat() but takes ownership of GValues */
633 static void
gst_value_list_concat_and_take_values(GValue * dest,GValue * val1,GValue * val2)634 gst_value_list_concat_and_take_values (GValue * dest, GValue * val1,
635 GValue * val2)
636 {
637 guint i, val1_length, val2_length;
638 gboolean val1_is_list;
639 gboolean val2_is_list;
640 GArray *array;
641
642 g_assert (dest != NULL);
643 g_assert (G_VALUE_TYPE (dest) == 0);
644 g_assert (G_IS_VALUE (val1));
645 g_assert (G_IS_VALUE (val2));
646 g_assert (gst_value_list_or_array_are_compatible (val1, val2));
647
648 val1_is_list = GST_VALUE_HOLDS_LIST (val1);
649 val1_length = (val1_is_list ? VALUE_LIST_SIZE (val1) : 1);
650
651 val2_is_list = GST_VALUE_HOLDS_LIST (val2);
652 val2_length = (val2_is_list ? VALUE_LIST_SIZE (val2) : 1);
653
654 g_value_init (dest, GST_TYPE_LIST);
655 array = (GArray *) dest->data[0].v_pointer;
656 g_array_set_size (array, val1_length + val2_length);
657
658 if (val1_is_list) {
659 for (i = 0; i < val1_length; i++) {
660 g_array_index (array, GValue, i) = *VALUE_LIST_GET_VALUE (val1, i);
661 }
662 g_array_set_size (VALUE_LIST_ARRAY (val1), 0);
663 g_value_unset (val1);
664 } else {
665 g_array_index (array, GValue, 0) = *val1;
666 G_VALUE_TYPE (val1) = G_TYPE_INVALID;
667 }
668
669 if (val2_is_list) {
670 for (i = 0; i < val2_length; i++) {
671 const GValue *v2 = VALUE_LIST_GET_VALUE (val2, i);
672 g_array_index (array, GValue, i + val1_length) = *v2;
673 }
674 g_array_set_size (VALUE_LIST_ARRAY (val2), 0);
675 g_value_unset (val2);
676 } else {
677 g_array_index (array, GValue, val1_length) = *val2;
678 G_VALUE_TYPE (val2) = G_TYPE_INVALID;
679 }
680 }
681
682 /**
683 * gst_value_list_merge:
684 * @dest: (out caller-allocates): an uninitialized #GValue to take the result
685 * @value1: a #GValue
686 * @value2: a #GValue
687 *
688 * Merges copies of @value1 and @value2. Values that are not
689 * of type #GST_TYPE_LIST are treated as if they were lists of length 1.
690 *
691 * The result will be put into @dest and will either be a list that will not
692 * contain any duplicates, or a non-list type (if @value1 and @value2
693 * were equal).
694 */
695 void
gst_value_list_merge(GValue * dest,const GValue * value1,const GValue * value2)696 gst_value_list_merge (GValue * dest, const GValue * value1,
697 const GValue * value2)
698 {
699 guint i, j, k, value1_length, value2_length, skipped;
700 const GValue *src;
701 gboolean skip;
702 GArray *array;
703
704 g_return_if_fail (dest != NULL);
705 g_return_if_fail (G_VALUE_TYPE (dest) == 0);
706 g_return_if_fail (G_IS_VALUE (value1));
707 g_return_if_fail (G_IS_VALUE (value2));
708 g_return_if_fail (gst_value_list_or_array_are_compatible (value1, value2));
709
710 value1_length =
711 (GST_VALUE_HOLDS_LIST (value1) ? VALUE_LIST_SIZE (value1) : 1);
712 value2_length =
713 (GST_VALUE_HOLDS_LIST (value2) ? VALUE_LIST_SIZE (value2) : 1);
714 g_value_init (dest, GST_TYPE_LIST);
715 array = (GArray *) dest->data[0].v_pointer;
716 g_array_set_size (array, value1_length + value2_length);
717
718 if (GST_VALUE_HOLDS_LIST (value1)) {
719 for (i = 0; i < value1_length; i++) {
720 gst_value_init_and_copy (&g_array_index (array, GValue, i),
721 VALUE_LIST_GET_VALUE (value1, i));
722 }
723 } else {
724 gst_value_init_and_copy (&g_array_index (array, GValue, 0), value1);
725 }
726
727 j = value1_length;
728 skipped = 0;
729 if (GST_VALUE_HOLDS_LIST (value2)) {
730 for (i = 0; i < value2_length; i++) {
731 skip = FALSE;
732 src = VALUE_LIST_GET_VALUE (value2, i);
733 for (k = 0; k < value1_length; k++) {
734 if (gst_value_compare (&g_array_index (array, GValue, k),
735 src) == GST_VALUE_EQUAL) {
736 skip = TRUE;
737 skipped++;
738 break;
739 }
740 }
741 if (!skip) {
742 gst_value_init_and_copy (&g_array_index (array, GValue, j), src);
743 j++;
744 }
745 }
746 } else {
747 skip = FALSE;
748 for (k = 0; k < value1_length; k++) {
749 if (gst_value_compare (&g_array_index (array, GValue, k),
750 value2) == GST_VALUE_EQUAL) {
751 skip = TRUE;
752 skipped++;
753 break;
754 }
755 }
756 if (!skip) {
757 gst_value_init_and_copy (&g_array_index (array, GValue, j), value2);
758 }
759 }
760 if (skipped) {
761 guint new_size = value1_length + (value2_length - skipped);
762
763 if (new_size > 1) {
764 /* shrink list */
765 g_array_set_size (array, new_size);
766 } else {
767 GValue single_dest;
768
769 /* size is 1, take single value in list and make it new dest */
770 single_dest = g_array_index (array, GValue, 0);
771
772 /* clean up old value allocations: must set array size to 0, because
773 * allocated values are not inited meaning g_value_unset() will not
774 * work on them */
775 g_array_set_size (array, 0);
776 g_value_unset (dest);
777
778 /* the single value is our new result */
779 *dest = single_dest;
780 }
781 }
782 }
783
784 /**
785 * gst_value_list_get_size:
786 * @value: a #GValue of type #GST_TYPE_LIST
787 *
788 * Gets the number of values contained in @value.
789 *
790 * Returns: the number of values
791 */
792 guint
gst_value_list_get_size(const GValue * value)793 gst_value_list_get_size (const GValue * value)
794 {
795 g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), 0);
796
797 return ((GArray *) value->data[0].v_pointer)->len;
798 }
799
800 /**
801 * gst_value_list_get_value:
802 * @value: a #GValue of type #GST_TYPE_LIST
803 * @index: index of value to get from the list
804 *
805 * Gets the value that is a member of the list contained in @value and
806 * has the index @index.
807 *
808 * Returns: (transfer none): the value at the given index
809 */
810 const GValue *
gst_value_list_get_value(const GValue * value,guint index)811 gst_value_list_get_value (const GValue * value, guint index)
812 {
813 g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), NULL);
814 g_return_val_if_fail (index < VALUE_LIST_SIZE (value), NULL);
815
816 return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer,
817 GValue, index);
818 }
819
820 /**
821 * gst_value_array_append_value:
822 * @value: a #GValue of type #GST_TYPE_ARRAY
823 * @append_value: the value to append
824 *
825 * Appends @append_value to the GstValueArray in @value.
826 */
827 void
gst_value_array_append_value(GValue * value,const GValue * append_value)828 gst_value_array_append_value (GValue * value, const GValue * append_value)
829 {
830 GValue val = { 0, };
831
832 g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value));
833 g_return_if_fail (G_IS_VALUE (append_value));
834 g_return_if_fail (gst_value_list_or_array_are_compatible (value,
835 append_value));
836
837 gst_value_init_and_copy (&val, append_value);
838 g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1);
839 }
840
841 static inline void
_gst_value_array_append_and_take_value(GValue * value,GValue * append_value)842 _gst_value_array_append_and_take_value (GValue * value, GValue * append_value)
843 {
844 g_array_append_vals ((GArray *) value->data[0].v_pointer, append_value, 1);
845 memset (append_value, 0, sizeof (GValue));
846 }
847
848 /**
849 * gst_value_array_append_and_take_value:
850 * @value: a #GValue of type #GST_TYPE_ARRAY
851 * @append_value: (transfer full): the value to append
852 *
853 * Appends @append_value to the GstValueArray in @value.
854 *
855 * Since: 1.2
856 */
857 void
gst_value_array_append_and_take_value(GValue * value,GValue * append_value)858 gst_value_array_append_and_take_value (GValue * value, GValue * append_value)
859 {
860 g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value));
861 g_return_if_fail (G_IS_VALUE (append_value));
862 g_return_if_fail (gst_value_list_or_array_are_compatible (value,
863 append_value));
864
865 _gst_value_array_append_and_take_value (value, append_value);
866 }
867
868 /**
869 * gst_value_array_prepend_value:
870 * @value: a #GValue of type #GST_TYPE_ARRAY
871 * @prepend_value: the value to prepend
872 *
873 * Prepends @prepend_value to the GstValueArray in @value.
874 */
875 void
gst_value_array_prepend_value(GValue * value,const GValue * prepend_value)876 gst_value_array_prepend_value (GValue * value, const GValue * prepend_value)
877 {
878 GValue val = { 0, };
879
880 g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value));
881 g_return_if_fail (G_IS_VALUE (prepend_value));
882 g_return_if_fail (gst_value_list_or_array_are_compatible (value,
883 prepend_value));
884
885 gst_value_init_and_copy (&val, prepend_value);
886 g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1);
887 }
888
889 /**
890 * gst_value_array_get_size:
891 * @value: a #GValue of type #GST_TYPE_ARRAY
892 *
893 * Gets the number of values contained in @value.
894 *
895 * Returns: the number of values
896 */
897 guint
gst_value_array_get_size(const GValue * value)898 gst_value_array_get_size (const GValue * value)
899 {
900 g_return_val_if_fail (GST_VALUE_HOLDS_ARRAY (value), 0);
901
902 return ((GArray *) value->data[0].v_pointer)->len;
903 }
904
905 /**
906 * gst_value_array_get_value:
907 * @value: a #GValue of type #GST_TYPE_ARRAY
908 * @index: index of value to get from the array
909 *
910 * Gets the value that is a member of the array contained in @value and
911 * has the index @index.
912 *
913 * Returns: (transfer none): the value at the given index
914 */
915 const GValue *
gst_value_array_get_value(const GValue * value,guint index)916 gst_value_array_get_value (const GValue * value, guint index)
917 {
918 g_return_val_if_fail (GST_VALUE_HOLDS_ARRAY (value), NULL);
919 g_return_val_if_fail (index < gst_value_array_get_size (value), NULL);
920
921 return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer,
922 GValue, index);
923 }
924
925 static void
gst_value_transform_list_string(const GValue * src_value,GValue * dest_value)926 gst_value_transform_list_string (const GValue * src_value, GValue * dest_value)
927 {
928 gst_value_transform_any_list_string (src_value, dest_value, "{ ", " }");
929 }
930
931 static void
gst_value_transform_array_string(const GValue * src_value,GValue * dest_value)932 gst_value_transform_array_string (const GValue * src_value, GValue * dest_value)
933 {
934 gst_value_transform_any_list_string (src_value, dest_value, "< ", " >");
935 }
936
937 static void
gst_value_transform_g_value_array_string(const GValue * src_value,GValue * dest_value)938 gst_value_transform_g_value_array_string (const GValue * src_value,
939 GValue * dest_value)
940 {
941 _gst_value_transform_g_value_array_string (src_value, dest_value, "< ", " >");
942 }
943
944 static void
gst_value_transform_g_value_array_any_list(const GValue * src_value,GValue * dest_value)945 gst_value_transform_g_value_array_any_list (const GValue * src_value,
946 GValue * dest_value)
947 {
948 const GValueArray *varray;
949 GArray *array;
950 gint i;
951
952 /* GLib will unset the value, memset to 0 the data instead of doing a proper
953 * reset. That's why we need to allocate the array here */
954 gst_value_init_list_or_array (dest_value);
955
956 varray = g_value_get_boxed (src_value);
957 array = dest_value->data[0].v_pointer;
958
959 for (i = 0; i < varray->n_values; i++) {
960 GValue val = G_VALUE_INIT;
961 gst_value_init_and_copy (&val, &varray->values[i]);
962 g_array_append_vals (array, &val, 1);
963 }
964 }
965
966 static void
gst_value_transform_any_list_g_value_array(const GValue * src_value,GValue * dest_value)967 gst_value_transform_any_list_g_value_array (const GValue * src_value,
968 GValue * dest_value)
969 {
970 GValueArray *varray;
971 const GArray *array;
972 gint i;
973
974 array = src_value->data[0].v_pointer;
975 varray = g_value_array_new (array->len);
976
977 for (i = 0; i < array->len; i++)
978 g_value_array_append (varray, &g_array_index (array, GValue, i));
979
980 g_value_take_boxed (dest_value, varray);
981 }
982
983 /* Do an unordered compare of the contents of a list */
984 static gint
gst_value_compare_value_list(const GValue * value1,const GValue * value2)985 gst_value_compare_value_list (const GValue * value1, const GValue * value2)
986 {
987 guint i, j;
988 GArray *array1 = value1->data[0].v_pointer;
989 GArray *array2 = value2->data[0].v_pointer;
990 GValue *v1;
991 GValue *v2;
992 gint len, to_remove;
993 guint8 *removed;
994 GstValueCompareFunc compare;
995
996 /* get length and do initial length check. */
997 len = array1->len;
998 if (len != array2->len)
999 return GST_VALUE_UNORDERED;
1000
1001 /* place to mark removed value indices of array2 */
1002 removed = g_newa (guint8, len);
1003 memset (removed, 0, len);
1004 to_remove = len;
1005
1006 /* loop over array1, all items should be in array2. When we find an
1007 * item in array2, remove it from array2 by marking it as removed */
1008 for (i = 0; i < len; i++) {
1009 v1 = &g_array_index (array1, GValue, i);
1010 if ((compare = gst_value_get_compare_func (v1))) {
1011 for (j = 0; j < len; j++) {
1012 /* item is removed, we can skip it */
1013 if (removed[j])
1014 continue;
1015 v2 = &g_array_index (array2, GValue, j);
1016 if (gst_value_compare_with_func (v1, v2, compare) == GST_VALUE_EQUAL) {
1017 /* mark item as removed now that we found it in array2 and
1018 * decrement the number of remaining items in array2. */
1019 removed[j] = 1;
1020 to_remove--;
1021 break;
1022 }
1023 }
1024 /* item in array1 and not in array2, UNORDERED */
1025 if (j == len)
1026 return GST_VALUE_UNORDERED;
1027 } else
1028 return GST_VALUE_UNORDERED;
1029 }
1030 /* if not all items were removed, array2 contained something not in array1 */
1031 if (to_remove != 0)
1032 return GST_VALUE_UNORDERED;
1033
1034 /* arrays are equal */
1035 return GST_VALUE_EQUAL;
1036 }
1037
1038 /* Perform an ordered comparison of the contents of an array */
1039 static gint
gst_value_compare_value_array(const GValue * value1,const GValue * value2)1040 gst_value_compare_value_array (const GValue * value1, const GValue * value2)
1041 {
1042 guint i;
1043 GArray *array1 = value1->data[0].v_pointer;
1044 GArray *array2 = value2->data[0].v_pointer;
1045 guint len = array1->len;
1046 GValue *v1;
1047 GValue *v2;
1048
1049 if (len != array2->len)
1050 return GST_VALUE_UNORDERED;
1051
1052 for (i = 0; i < len; i++) {
1053 v1 = &g_array_index (array1, GValue, i);
1054 v2 = &g_array_index (array2, GValue, i);
1055 if (gst_value_compare (v1, v2) != GST_VALUE_EQUAL)
1056 return GST_VALUE_UNORDERED;
1057 }
1058
1059 return GST_VALUE_EQUAL;
1060 }
1061
1062 static gint
gst_value_compare_g_value_array(const GValue * value1,const GValue * value2)1063 gst_value_compare_g_value_array (const GValue * value1, const GValue * value2)
1064 {
1065 guint i;
1066 GValueArray *array1 = value1->data[0].v_pointer;
1067 GValueArray *array2 = value2->data[0].v_pointer;
1068 guint len = array1->n_values;
1069 GValue *v1;
1070 GValue *v2;
1071
1072 if (len != array2->n_values)
1073 return GST_VALUE_UNORDERED;
1074
1075 for (i = 0; i < len; i++) {
1076 v1 = g_value_array_get_nth (array1, i);
1077 v2 = g_value_array_get_nth (array2, i);
1078 if (gst_value_compare (v1, v2) != GST_VALUE_EQUAL)
1079 return GST_VALUE_UNORDERED;
1080 }
1081
1082 return GST_VALUE_EQUAL;
1083 }
1084
1085 static gchar *
gst_value_serialize_value_list(const GValue * value)1086 gst_value_serialize_value_list (const GValue * value)
1087 {
1088 return _priv_gst_value_serialize_any_list (value, "{ ", " }", TRUE);
1089 }
1090
1091 static gboolean
gst_value_deserialize_value_list(GValue * dest,const gchar * s)1092 gst_value_deserialize_value_list (GValue * dest, const gchar * s)
1093 {
1094 gchar *s2 = (gchar *) s;
1095 return _priv_gst_value_parse_list (s2, &s2, dest, G_TYPE_INVALID);
1096 }
1097
1098 static gchar *
gst_value_serialize_value_array(const GValue * value)1099 gst_value_serialize_value_array (const GValue * value)
1100 {
1101 return _priv_gst_value_serialize_any_list (value, "< ", " >", TRUE);
1102 }
1103
1104 static gboolean
gst_value_deserialize_value_array(GValue * dest,const gchar * s)1105 gst_value_deserialize_value_array (GValue * dest, const gchar * s)
1106 {
1107 gchar *s2 = (gchar *) s;
1108 return _priv_gst_value_parse_array (s2, &s2, dest, G_TYPE_INVALID);
1109 }
1110
1111 static gchar *
gst_value_serialize_g_value_array(const GValue * value)1112 gst_value_serialize_g_value_array (const GValue * value)
1113 {
1114 return _gst_value_serialize_g_value_array (value, "< ", " >");
1115 }
1116
1117 static gboolean
gst_value_deserialize_g_value_array(GValue * dest,const gchar * s)1118 gst_value_deserialize_g_value_array (GValue * dest, const gchar * s)
1119 {
1120 g_warning ("gst_value_deserialize_g_value_array: unimplemented");
1121 return FALSE;
1122 }
1123
1124 /*************
1125 * int range *
1126 *
1127 * Values in the range are defined as any value greater or equal
1128 * to min*step, AND lesser or equal to max*step.
1129 * For step == 1, this falls back to the traditional range semantics.
1130 *
1131 * data[0] = (min << 32) | (max)
1132 * data[1] = step
1133 *
1134 *************/
1135
1136 #define INT_RANGE_MIN(v) ((gint) (((v)->data[0].v_uint64) >> 32))
1137 #define INT_RANGE_MAX(v) ((gint) (((v)->data[0].v_uint64) & 0xffffffff))
1138 #define INT_RANGE_STEP(v) ((v)->data[1].v_int)
1139
1140 static void
gst_value_init_int_range(GValue * value)1141 gst_value_init_int_range (GValue * value)
1142 {
1143 G_STATIC_ASSERT (sizeof (gint) <= 2 * sizeof (guint64));
1144
1145 value->data[0].v_uint64 = 0;
1146 value->data[1].v_int = 1;
1147 }
1148
1149 static void
gst_value_copy_int_range(const GValue * src_value,GValue * dest_value)1150 gst_value_copy_int_range (const GValue * src_value, GValue * dest_value)
1151 {
1152 dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
1153 dest_value->data[1].v_int = src_value->data[1].v_int;
1154 }
1155
1156 static gchar *
gst_value_collect_int_range(GValue * value,guint n_collect_values,GTypeCValue * collect_values,guint collect_flags)1157 gst_value_collect_int_range (GValue * value, guint n_collect_values,
1158 GTypeCValue * collect_values, guint collect_flags)
1159 {
1160 if (n_collect_values != 2)
1161 return g_strdup_printf ("not enough value locations for `%s' passed",
1162 G_VALUE_TYPE_NAME (value));
1163 if (collect_values[0].v_int >= collect_values[1].v_int)
1164 return g_strdup_printf ("range start is not smaller than end for `%s'",
1165 G_VALUE_TYPE_NAME (value));
1166
1167 gst_value_set_int_range_step (value, collect_values[0].v_int,
1168 collect_values[1].v_int, 1);
1169
1170 return NULL;
1171 }
1172
1173 static gchar *
gst_value_lcopy_int_range(const GValue * value,guint n_collect_values,GTypeCValue * collect_values,guint collect_flags)1174 gst_value_lcopy_int_range (const GValue * value, guint n_collect_values,
1175 GTypeCValue * collect_values, guint collect_flags)
1176 {
1177 guint32 *int_range_start = collect_values[0].v_pointer;
1178 guint32 *int_range_end = collect_values[1].v_pointer;
1179
1180 if (!int_range_start)
1181 return g_strdup_printf ("start value location for `%s' passed as NULL",
1182 G_VALUE_TYPE_NAME (value));
1183 if (!int_range_end)
1184 return g_strdup_printf ("end value location for `%s' passed as NULL",
1185 G_VALUE_TYPE_NAME (value));
1186
1187 *int_range_start = INT_RANGE_MIN (value);
1188 *int_range_end = INT_RANGE_MAX (value);
1189
1190 return NULL;
1191 }
1192
1193 /**
1194 * gst_value_set_int_range_step:
1195 * @value: a GValue initialized to GST_TYPE_INT_RANGE
1196 * @start: the start of the range
1197 * @end: the end of the range
1198 * @step: the step of the range
1199 *
1200 * Sets @value to the range specified by @start, @end and @step.
1201 */
1202 void
gst_value_set_int_range_step(GValue * value,gint start,gint end,gint step)1203 gst_value_set_int_range_step (GValue * value, gint start, gint end, gint step)
1204 {
1205 guint64 sstart, sstop;
1206
1207 g_return_if_fail (GST_VALUE_HOLDS_INT_RANGE (value));
1208 g_return_if_fail (start < end);
1209 g_return_if_fail (step > 0);
1210 g_return_if_fail (start % step == 0);
1211 g_return_if_fail (end % step == 0);
1212
1213 sstart = (guint) (start / step);
1214 sstop = (guint) (end / step);
1215 value->data[0].v_uint64 = (sstart << 32) | sstop;
1216 value->data[1].v_int = step;
1217 }
1218
1219 /**
1220 * gst_value_set_int_range:
1221 * @value: a GValue initialized to GST_TYPE_INT_RANGE
1222 * @start: the start of the range
1223 * @end: the end of the range
1224 *
1225 * Sets @value to the range specified by @start and @end.
1226 */
1227 void
gst_value_set_int_range(GValue * value,gint start,gint end)1228 gst_value_set_int_range (GValue * value, gint start, gint end)
1229 {
1230 gst_value_set_int_range_step (value, start, end, 1);
1231 }
1232
1233 /**
1234 * gst_value_get_int_range_min:
1235 * @value: a GValue initialized to GST_TYPE_INT_RANGE
1236 *
1237 * Gets the minimum of the range specified by @value.
1238 *
1239 * Returns: the minimum of the range
1240 */
1241 gint
gst_value_get_int_range_min(const GValue * value)1242 gst_value_get_int_range_min (const GValue * value)
1243 {
1244 g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
1245
1246 return INT_RANGE_MIN (value) * INT_RANGE_STEP (value);
1247 }
1248
1249 /**
1250 * gst_value_get_int_range_max:
1251 * @value: a GValue initialized to GST_TYPE_INT_RANGE
1252 *
1253 * Gets the maximum of the range specified by @value.
1254 *
1255 * Returns: the maximum of the range
1256 */
1257 gint
gst_value_get_int_range_max(const GValue * value)1258 gst_value_get_int_range_max (const GValue * value)
1259 {
1260 g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
1261
1262 return INT_RANGE_MAX (value) * INT_RANGE_STEP (value);
1263 }
1264
1265 /**
1266 * gst_value_get_int_range_step:
1267 * @value: a GValue initialized to GST_TYPE_INT_RANGE
1268 *
1269 * Gets the step of the range specified by @value.
1270 *
1271 * Returns: the step of the range
1272 */
1273 gint
gst_value_get_int_range_step(const GValue * value)1274 gst_value_get_int_range_step (const GValue * value)
1275 {
1276 g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
1277
1278 return INT_RANGE_STEP (value);
1279 }
1280
1281 static void
gst_value_transform_int_range_string(const GValue * src_value,GValue * dest_value)1282 gst_value_transform_int_range_string (const GValue * src_value,
1283 GValue * dest_value)
1284 {
1285 if (INT_RANGE_STEP (src_value) == 1)
1286 dest_value->data[0].v_pointer = g_strdup_printf ("[%d,%d]",
1287 INT_RANGE_MIN (src_value), INT_RANGE_MAX (src_value));
1288 else
1289 dest_value->data[0].v_pointer = g_strdup_printf ("[%d,%d,%d]",
1290 INT_RANGE_MIN (src_value) * INT_RANGE_STEP (src_value),
1291 INT_RANGE_MAX (src_value) * INT_RANGE_STEP (src_value),
1292 INT_RANGE_STEP (src_value));
1293 }
1294
1295 static gint
gst_value_compare_int_range(const GValue * value1,const GValue * value2)1296 gst_value_compare_int_range (const GValue * value1, const GValue * value2)
1297 {
1298 /* calculate the number of values in each range */
1299 gint n1 = INT_RANGE_MAX (value1) - INT_RANGE_MIN (value1) + 1;
1300 gint n2 = INT_RANGE_MAX (value2) - INT_RANGE_MIN (value2) + 1;
1301
1302 /* they must be equal */
1303 if (n1 != n2)
1304 return GST_VALUE_UNORDERED;
1305
1306 /* if empty, equal */
1307 if (n1 == 0)
1308 return GST_VALUE_EQUAL;
1309
1310 /* if more than one value, then it is only equal if the step is equal
1311 and bounds lie on the same value */
1312 if (n1 > 1) {
1313 if (INT_RANGE_STEP (value1) == INT_RANGE_STEP (value2) &&
1314 INT_RANGE_MIN (value1) == INT_RANGE_MIN (value2) &&
1315 INT_RANGE_MAX (value1) == INT_RANGE_MAX (value2)) {
1316 return GST_VALUE_EQUAL;
1317 }
1318 return GST_VALUE_UNORDERED;
1319 } else {
1320 /* if just one, only if the value is equal */
1321 if (INT_RANGE_MIN (value1) == INT_RANGE_MIN (value2))
1322 return GST_VALUE_EQUAL;
1323 return GST_VALUE_UNORDERED;
1324 }
1325 }
1326
1327 static gchar *
gst_value_serialize_int_range(const GValue * value)1328 gst_value_serialize_int_range (const GValue * value)
1329 {
1330 if (INT_RANGE_STEP (value) == 1)
1331 return g_strdup_printf ("[ %d, %d ]", INT_RANGE_MIN (value),
1332 INT_RANGE_MAX (value));
1333 else
1334 return g_strdup_printf ("[ %d, %d, %d ]",
1335 INT_RANGE_MIN (value) * INT_RANGE_STEP (value),
1336 INT_RANGE_MAX (value) * INT_RANGE_STEP (value), INT_RANGE_STEP (value));
1337 }
1338
1339 static gboolean
gst_value_deserialize_int_range(GValue * dest,const gchar * s)1340 gst_value_deserialize_int_range (GValue * dest, const gchar * s)
1341 {
1342 g_warning ("unimplemented");
1343 return FALSE;
1344 }
1345
1346 /***************
1347 * int64 range *
1348 *
1349 * Values in the range are defined as any value greater or equal
1350 * to min*step, AND lesser or equal to max*step.
1351 * For step == 1, this falls back to the traditional range semantics.
1352 ***************/
1353
1354 #define INT64_RANGE_MIN(v) (((gint64 *)((v)->data[0].v_pointer))[0])
1355 #define INT64_RANGE_MAX(v) (((gint64 *)((v)->data[0].v_pointer))[1])
1356 #define INT64_RANGE_STEP(v) (((gint64 *)((v)->data[0].v_pointer))[2])
1357
1358 static void
gst_value_init_int64_range(GValue * value)1359 gst_value_init_int64_range (GValue * value)
1360 {
1361 gint64 *vals = g_slice_alloc0 (3 * sizeof (gint64));
1362 value->data[0].v_pointer = vals;
1363 INT64_RANGE_MIN (value) = 0;
1364 INT64_RANGE_MAX (value) = 0;
1365 INT64_RANGE_STEP (value) = 1;
1366 }
1367
1368 static void
gst_value_free_int64_range(GValue * value)1369 gst_value_free_int64_range (GValue * value)
1370 {
1371 g_return_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value));
1372 g_slice_free1 (3 * sizeof (gint64), value->data[0].v_pointer);
1373 value->data[0].v_pointer = NULL;
1374 }
1375
1376 static void
gst_value_copy_int64_range(const GValue * src_value,GValue * dest_value)1377 gst_value_copy_int64_range (const GValue * src_value, GValue * dest_value)
1378 {
1379 gint64 *vals = (gint64 *) dest_value->data[0].v_pointer;
1380 gint64 *src_vals = (gint64 *) src_value->data[0].v_pointer;
1381
1382 if (vals == NULL) {
1383 gst_value_init_int64_range (dest_value);
1384 }
1385
1386 if (src_vals != NULL) {
1387 INT64_RANGE_MIN (dest_value) = INT64_RANGE_MIN (src_value);
1388 INT64_RANGE_MAX (dest_value) = INT64_RANGE_MAX (src_value);
1389 INT64_RANGE_STEP (dest_value) = INT64_RANGE_STEP (src_value);
1390 }
1391 }
1392
1393 static gchar *
gst_value_collect_int64_range(GValue * value,guint n_collect_values,GTypeCValue * collect_values,guint collect_flags)1394 gst_value_collect_int64_range (GValue * value, guint n_collect_values,
1395 GTypeCValue * collect_values, guint collect_flags)
1396 {
1397 gint64 *vals = value->data[0].v_pointer;
1398
1399 if (n_collect_values != 2)
1400 return g_strdup_printf ("not enough value locations for `%s' passed",
1401 G_VALUE_TYPE_NAME (value));
1402 if (collect_values[0].v_int64 >= collect_values[1].v_int64)
1403 return g_strdup_printf ("range start is not smaller than end for `%s'",
1404 G_VALUE_TYPE_NAME (value));
1405
1406 if (vals == NULL) {
1407 gst_value_init_int64_range (value);
1408 }
1409
1410 gst_value_set_int64_range_step (value, collect_values[0].v_int64,
1411 collect_values[1].v_int64, 1);
1412
1413 return NULL;
1414 }
1415
1416 static gchar *
gst_value_lcopy_int64_range(const GValue * value,guint n_collect_values,GTypeCValue * collect_values,guint collect_flags)1417 gst_value_lcopy_int64_range (const GValue * value, guint n_collect_values,
1418 GTypeCValue * collect_values, guint collect_flags)
1419 {
1420 guint64 *int_range_start = collect_values[0].v_pointer;
1421 guint64 *int_range_end = collect_values[1].v_pointer;
1422 guint64 *int_range_step = collect_values[2].v_pointer;
1423 gint64 *vals = (gint64 *) value->data[0].v_pointer;
1424
1425 if (!int_range_start)
1426 return g_strdup_printf ("start value location for `%s' passed as NULL",
1427 G_VALUE_TYPE_NAME (value));
1428 if (!int_range_end)
1429 return g_strdup_printf ("end value location for `%s' passed as NULL",
1430 G_VALUE_TYPE_NAME (value));
1431 if (!int_range_step)
1432 return g_strdup_printf ("step value location for `%s' passed as NULL",
1433 G_VALUE_TYPE_NAME (value));
1434
1435 if (G_UNLIKELY (vals == NULL)) {
1436 return g_strdup_printf ("Uninitialised `%s' passed",
1437 G_VALUE_TYPE_NAME (value));
1438 }
1439
1440 *int_range_start = INT64_RANGE_MIN (value);
1441 *int_range_end = INT64_RANGE_MAX (value);
1442 *int_range_step = INT64_RANGE_STEP (value);
1443
1444 return NULL;
1445 }
1446
1447 /**
1448 * gst_value_set_int64_range_step:
1449 * @value: a GValue initialized to GST_TYPE_INT64_RANGE
1450 * @start: the start of the range
1451 * @end: the end of the range
1452 * @step: the step of the range
1453 *
1454 * Sets @value to the range specified by @start, @end and @step.
1455 */
1456 void
gst_value_set_int64_range_step(GValue * value,gint64 start,gint64 end,gint64 step)1457 gst_value_set_int64_range_step (GValue * value, gint64 start, gint64 end,
1458 gint64 step)
1459 {
1460 g_return_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value));
1461 g_return_if_fail (start < end);
1462 g_return_if_fail (step > 0);
1463 g_return_if_fail (start % step == 0);
1464 g_return_if_fail (end % step == 0);
1465
1466 INT64_RANGE_MIN (value) = start / step;
1467 INT64_RANGE_MAX (value) = end / step;
1468 INT64_RANGE_STEP (value) = step;
1469 }
1470
1471 /**
1472 * gst_value_set_int64_range:
1473 * @value: a GValue initialized to GST_TYPE_INT64_RANGE
1474 * @start: the start of the range
1475 * @end: the end of the range
1476 *
1477 * Sets @value to the range specified by @start and @end.
1478 */
1479 void
gst_value_set_int64_range(GValue * value,gint64 start,gint64 end)1480 gst_value_set_int64_range (GValue * value, gint64 start, gint64 end)
1481 {
1482 gst_value_set_int64_range_step (value, start, end, 1);
1483 }
1484
1485 /**
1486 * gst_value_get_int64_range_min:
1487 * @value: a GValue initialized to GST_TYPE_INT64_RANGE
1488 *
1489 * Gets the minimum of the range specified by @value.
1490 *
1491 * Returns: the minimum of the range
1492 */
1493 gint64
gst_value_get_int64_range_min(const GValue * value)1494 gst_value_get_int64_range_min (const GValue * value)
1495 {
1496 g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value), 0);
1497
1498 return INT64_RANGE_MIN (value) * INT64_RANGE_STEP (value);
1499 }
1500
1501 /**
1502 * gst_value_get_int64_range_max:
1503 * @value: a GValue initialized to GST_TYPE_INT64_RANGE
1504 *
1505 * Gets the maximum of the range specified by @value.
1506 *
1507 * Returns: the maximum of the range
1508 */
1509 gint64
gst_value_get_int64_range_max(const GValue * value)1510 gst_value_get_int64_range_max (const GValue * value)
1511 {
1512 g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value), 0);
1513
1514 return INT64_RANGE_MAX (value) * INT64_RANGE_STEP (value);
1515 }
1516
1517 /**
1518 * gst_value_get_int64_range_step:
1519 * @value: a GValue initialized to GST_TYPE_INT64_RANGE
1520 *
1521 * Gets the step of the range specified by @value.
1522 *
1523 * Returns: the step of the range
1524 */
1525 gint64
gst_value_get_int64_range_step(const GValue * value)1526 gst_value_get_int64_range_step (const GValue * value)
1527 {
1528 g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value), 0);
1529
1530 return INT64_RANGE_STEP (value);
1531 }
1532
1533 static void
gst_value_transform_int64_range_string(const GValue * src_value,GValue * dest_value)1534 gst_value_transform_int64_range_string (const GValue * src_value,
1535 GValue * dest_value)
1536 {
1537 if (INT64_RANGE_STEP (src_value) == 1)
1538 dest_value->data[0].v_pointer =
1539 g_strdup_printf ("(gint64)[%" G_GINT64_FORMAT ",%" G_GINT64_FORMAT "]",
1540 INT64_RANGE_MIN (src_value), INT64_RANGE_MAX (src_value));
1541 else
1542 dest_value->data[0].v_pointer =
1543 g_strdup_printf ("(gint64)[%" G_GINT64_FORMAT ",%" G_GINT64_FORMAT
1544 ",%" G_GINT64_FORMAT "]",
1545 INT64_RANGE_MIN (src_value) * INT64_RANGE_STEP (src_value),
1546 INT64_RANGE_MAX (src_value) * INT64_RANGE_STEP (src_value),
1547 INT64_RANGE_STEP (src_value));
1548 }
1549
1550 static gint
gst_value_compare_int64_range(const GValue * value1,const GValue * value2)1551 gst_value_compare_int64_range (const GValue * value1, const GValue * value2)
1552 {
1553 /* calculate the number of values in each range */
1554 gint64 n1 = INT64_RANGE_MAX (value1) - INT64_RANGE_MIN (value1) + 1;
1555 gint64 n2 = INT64_RANGE_MAX (value2) - INT64_RANGE_MIN (value2) + 1;
1556
1557 /* they must be equal */
1558 if (n1 != n2)
1559 return GST_VALUE_UNORDERED;
1560
1561 /* if empty, equal */
1562 if (n1 == 0)
1563 return GST_VALUE_EQUAL;
1564
1565 /* if more than one value, then it is only equal if the step is equal
1566 and bounds lie on the same value */
1567 if (n1 > 1) {
1568 if (INT64_RANGE_STEP (value1) == INT64_RANGE_STEP (value2) &&
1569 INT64_RANGE_MIN (value1) == INT64_RANGE_MIN (value2) &&
1570 INT64_RANGE_MAX (value1) == INT64_RANGE_MAX (value2)) {
1571 return GST_VALUE_EQUAL;
1572 }
1573 return GST_VALUE_UNORDERED;
1574 } else {
1575 /* if just one, only if the value is equal */
1576 if (INT64_RANGE_MIN (value1) == INT64_RANGE_MIN (value2))
1577 return GST_VALUE_EQUAL;
1578 return GST_VALUE_UNORDERED;
1579 }
1580 }
1581
1582 static gchar *
gst_value_serialize_int64_range(const GValue * value)1583 gst_value_serialize_int64_range (const GValue * value)
1584 {
1585 if (INT64_RANGE_STEP (value) == 1)
1586 return g_strdup_printf ("[ %" G_GINT64_FORMAT ", %" G_GINT64_FORMAT " ]",
1587 INT64_RANGE_MIN (value), INT64_RANGE_MAX (value));
1588 else
1589 return g_strdup_printf ("[ %" G_GINT64_FORMAT ", %" G_GINT64_FORMAT ", %"
1590 G_GINT64_FORMAT " ]",
1591 INT64_RANGE_MIN (value) * INT64_RANGE_STEP (value),
1592 INT64_RANGE_MAX (value) * INT64_RANGE_STEP (value),
1593 INT64_RANGE_STEP (value));
1594 }
1595
1596 static gboolean
gst_value_deserialize_int64_range(GValue * dest,const gchar * s)1597 gst_value_deserialize_int64_range (GValue * dest, const gchar * s)
1598 {
1599 g_warning ("unimplemented");
1600 return FALSE;
1601 }
1602
1603 /****************
1604 * double range *
1605 ****************/
1606
1607 static void
gst_value_init_double_range(GValue * value)1608 gst_value_init_double_range (GValue * value)
1609 {
1610 value->data[0].v_double = 0;
1611 value->data[1].v_double = 0;
1612 }
1613
1614 static void
gst_value_copy_double_range(const GValue * src_value,GValue * dest_value)1615 gst_value_copy_double_range (const GValue * src_value, GValue * dest_value)
1616 {
1617 dest_value->data[0].v_double = src_value->data[0].v_double;
1618 dest_value->data[1].v_double = src_value->data[1].v_double;
1619 }
1620
1621 static gchar *
gst_value_collect_double_range(GValue * value,guint n_collect_values,GTypeCValue * collect_values,guint collect_flags)1622 gst_value_collect_double_range (GValue * value, guint n_collect_values,
1623 GTypeCValue * collect_values, guint collect_flags)
1624 {
1625 if (n_collect_values != 2)
1626 return g_strdup_printf ("not enough value locations for `%s' passed",
1627 G_VALUE_TYPE_NAME (value));
1628 if (collect_values[0].v_double >= collect_values[1].v_double)
1629 return g_strdup_printf ("range start is not smaller than end for `%s'",
1630 G_VALUE_TYPE_NAME (value));
1631
1632 value->data[0].v_double = collect_values[0].v_double;
1633 value->data[1].v_double = collect_values[1].v_double;
1634
1635 return NULL;
1636 }
1637
1638 static gchar *
gst_value_lcopy_double_range(const GValue * value,guint n_collect_values,GTypeCValue * collect_values,guint collect_flags)1639 gst_value_lcopy_double_range (const GValue * value, guint n_collect_values,
1640 GTypeCValue * collect_values, guint collect_flags)
1641 {
1642 gdouble *double_range_start = collect_values[0].v_pointer;
1643 gdouble *double_range_end = collect_values[1].v_pointer;
1644
1645 if (!double_range_start)
1646 return g_strdup_printf ("start value location for `%s' passed as NULL",
1647 G_VALUE_TYPE_NAME (value));
1648 if (!double_range_end)
1649 return g_strdup_printf ("end value location for `%s' passed as NULL",
1650 G_VALUE_TYPE_NAME (value));
1651
1652 *double_range_start = value->data[0].v_double;
1653 *double_range_end = value->data[1].v_double;
1654
1655 return NULL;
1656 }
1657
1658 /**
1659 * gst_value_set_double_range:
1660 * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
1661 * @start: the start of the range
1662 * @end: the end of the range
1663 *
1664 * Sets @value to the range specified by @start and @end.
1665 */
1666 void
gst_value_set_double_range(GValue * value,gdouble start,gdouble end)1667 gst_value_set_double_range (GValue * value, gdouble start, gdouble end)
1668 {
1669 g_return_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value));
1670 g_return_if_fail (start < end);
1671
1672 value->data[0].v_double = start;
1673 value->data[1].v_double = end;
1674 }
1675
1676 /**
1677 * gst_value_get_double_range_min:
1678 * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
1679 *
1680 * Gets the minimum of the range specified by @value.
1681 *
1682 * Returns: the minimum of the range
1683 */
1684 gdouble
gst_value_get_double_range_min(const GValue * value)1685 gst_value_get_double_range_min (const GValue * value)
1686 {
1687 g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
1688
1689 return value->data[0].v_double;
1690 }
1691
1692 /**
1693 * gst_value_get_double_range_max:
1694 * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
1695 *
1696 * Gets the maximum of the range specified by @value.
1697 *
1698 * Returns: the maximum of the range
1699 */
1700 gdouble
gst_value_get_double_range_max(const GValue * value)1701 gst_value_get_double_range_max (const GValue * value)
1702 {
1703 g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
1704
1705 return value->data[1].v_double;
1706 }
1707
1708 static void
gst_value_transform_double_range_string(const GValue * src_value,GValue * dest_value)1709 gst_value_transform_double_range_string (const GValue * src_value,
1710 GValue * dest_value)
1711 {
1712 gchar s1[G_ASCII_DTOSTR_BUF_SIZE], s2[G_ASCII_DTOSTR_BUF_SIZE];
1713
1714 dest_value->data[0].v_pointer = g_strdup_printf ("[%s,%s]",
1715 g_ascii_dtostr (s1, G_ASCII_DTOSTR_BUF_SIZE,
1716 src_value->data[0].v_double),
1717 g_ascii_dtostr (s2, G_ASCII_DTOSTR_BUF_SIZE,
1718 src_value->data[1].v_double));
1719 }
1720
1721 static gint
gst_value_compare_double_range(const GValue * value1,const GValue * value2)1722 gst_value_compare_double_range (const GValue * value1, const GValue * value2)
1723 {
1724 if (value2->data[0].v_double == value1->data[0].v_double &&
1725 value2->data[1].v_double == value1->data[1].v_double)
1726 return GST_VALUE_EQUAL;
1727 return GST_VALUE_UNORDERED;
1728 }
1729
1730 static gchar *
gst_value_serialize_double_range(const GValue * value)1731 gst_value_serialize_double_range (const GValue * value)
1732 {
1733 gchar d1[G_ASCII_DTOSTR_BUF_SIZE];
1734 gchar d2[G_ASCII_DTOSTR_BUF_SIZE];
1735
1736 g_ascii_dtostr (d1, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
1737 g_ascii_dtostr (d2, G_ASCII_DTOSTR_BUF_SIZE, value->data[1].v_double);
1738 return g_strdup_printf ("[ %s, %s ]", d1, d2);
1739 }
1740
1741 static gboolean
gst_value_deserialize_double_range(GValue * dest,const gchar * s)1742 gst_value_deserialize_double_range (GValue * dest, const gchar * s)
1743 {
1744 g_warning ("unimplemented");
1745 return FALSE;
1746 }
1747
1748 /****************
1749 * fraction range *
1750 ****************/
1751
1752 static void
gst_value_init_fraction_range(GValue * value)1753 gst_value_init_fraction_range (GValue * value)
1754 {
1755 GValue *vals;
1756 GType ftype;
1757
1758 ftype = GST_TYPE_FRACTION;
1759
1760 value->data[0].v_pointer = vals = g_slice_alloc0 (2 * sizeof (GValue));
1761 g_value_init (&vals[0], ftype);
1762 g_value_init (&vals[1], ftype);
1763 }
1764
1765 static void
gst_value_free_fraction_range(GValue * value)1766 gst_value_free_fraction_range (GValue * value)
1767 {
1768 GValue *vals = (GValue *) value->data[0].v_pointer;
1769
1770 if (vals != NULL) {
1771 /* we know the two values contain fractions without internal allocs */
1772 /* g_value_unset (&vals[0]); */
1773 /* g_value_unset (&vals[1]); */
1774 g_slice_free1 (2 * sizeof (GValue), vals);
1775 value->data[0].v_pointer = NULL;
1776 }
1777 }
1778
1779 static void
gst_value_copy_fraction_range(const GValue * src_value,GValue * dest_value)1780 gst_value_copy_fraction_range (const GValue * src_value, GValue * dest_value)
1781 {
1782 GValue *vals = (GValue *) dest_value->data[0].v_pointer;
1783 GValue *src_vals = (GValue *) src_value->data[0].v_pointer;
1784
1785 if (vals == NULL) {
1786 gst_value_init_fraction_range (dest_value);
1787 vals = dest_value->data[0].v_pointer;
1788 }
1789 if (src_vals != NULL) {
1790 g_value_copy (&src_vals[0], &vals[0]);
1791 g_value_copy (&src_vals[1], &vals[1]);
1792 }
1793 }
1794
1795 static gchar *
gst_value_collect_fraction_range(GValue * value,guint n_collect_values,GTypeCValue * collect_values,guint collect_flags)1796 gst_value_collect_fraction_range (GValue * value, guint n_collect_values,
1797 GTypeCValue * collect_values, guint collect_flags)
1798 {
1799 GValue *vals = (GValue *) value->data[0].v_pointer;
1800
1801 if (n_collect_values != 4)
1802 return g_strdup_printf ("not enough value locations for `%s' passed",
1803 G_VALUE_TYPE_NAME (value));
1804 if (collect_values[1].v_int == 0)
1805 return g_strdup_printf ("passed '0' as first denominator for `%s'",
1806 G_VALUE_TYPE_NAME (value));
1807 if (collect_values[3].v_int == 0)
1808 return g_strdup_printf ("passed '0' as second denominator for `%s'",
1809 G_VALUE_TYPE_NAME (value));
1810 if (gst_util_fraction_compare (collect_values[0].v_int,
1811 collect_values[1].v_int, collect_values[2].v_int,
1812 collect_values[3].v_int) >= 0)
1813 return g_strdup_printf ("range start is not smaller than end for `%s'",
1814 G_VALUE_TYPE_NAME (value));
1815
1816 if (vals == NULL) {
1817 gst_value_init_fraction_range (value);
1818 vals = value->data[0].v_pointer;
1819 }
1820
1821 gst_value_set_fraction (&vals[0], collect_values[0].v_int,
1822 collect_values[1].v_int);
1823 gst_value_set_fraction (&vals[1], collect_values[2].v_int,
1824 collect_values[3].v_int);
1825
1826 return NULL;
1827 }
1828
1829 static gchar *
gst_value_lcopy_fraction_range(const GValue * value,guint n_collect_values,GTypeCValue * collect_values,guint collect_flags)1830 gst_value_lcopy_fraction_range (const GValue * value, guint n_collect_values,
1831 GTypeCValue * collect_values, guint collect_flags)
1832 {
1833 gint i;
1834 gint *dest_values[4];
1835 GValue *vals = (GValue *) value->data[0].v_pointer;
1836
1837 if (G_UNLIKELY (n_collect_values != 4))
1838 return g_strdup_printf ("not enough value locations for `%s' passed",
1839 G_VALUE_TYPE_NAME (value));
1840
1841 for (i = 0; i < 4; i++) {
1842 if (G_UNLIKELY (collect_values[i].v_pointer == NULL)) {
1843 return g_strdup_printf ("value location for `%s' passed as NULL",
1844 G_VALUE_TYPE_NAME (value));
1845 }
1846 dest_values[i] = collect_values[i].v_pointer;
1847 }
1848
1849 if (G_UNLIKELY (vals == NULL)) {
1850 return g_strdup_printf ("Uninitialised `%s' passed",
1851 G_VALUE_TYPE_NAME (value));
1852 }
1853
1854 dest_values[0][0] = gst_value_get_fraction_numerator (&vals[0]);
1855 dest_values[1][0] = gst_value_get_fraction_denominator (&vals[0]);
1856 dest_values[2][0] = gst_value_get_fraction_numerator (&vals[1]);
1857 dest_values[3][0] = gst_value_get_fraction_denominator (&vals[1]);
1858 return NULL;
1859 }
1860
1861 /**
1862 * gst_value_set_fraction_range:
1863 * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1864 * @start: the start of the range (a GST_TYPE_FRACTION GValue)
1865 * @end: the end of the range (a GST_TYPE_FRACTION GValue)
1866 *
1867 * Sets @value to the range specified by @start and @end.
1868 */
1869 void
gst_value_set_fraction_range(GValue * value,const GValue * start,const GValue * end)1870 gst_value_set_fraction_range (GValue * value, const GValue * start,
1871 const GValue * end)
1872 {
1873 GValue *vals;
1874
1875 g_return_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value));
1876 g_return_if_fail (GST_VALUE_HOLDS_FRACTION (start));
1877 g_return_if_fail (GST_VALUE_HOLDS_FRACTION (end));
1878 g_return_if_fail (gst_util_fraction_compare (start->data[0].v_int,
1879 start->data[1].v_int, end->data[0].v_int, end->data[1].v_int) < 0);
1880
1881 vals = (GValue *) value->data[0].v_pointer;
1882 if (vals == NULL) {
1883 gst_value_init_fraction_range (value);
1884 vals = value->data[0].v_pointer;
1885 }
1886 g_value_copy (start, &vals[0]);
1887 g_value_copy (end, &vals[1]);
1888 }
1889
1890 /**
1891 * gst_value_set_fraction_range_full:
1892 * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1893 * @numerator_start: the numerator start of the range
1894 * @denominator_start: the denominator start of the range
1895 * @numerator_end: the numerator end of the range
1896 * @denominator_end: the denominator end of the range
1897 *
1898 * Sets @value to the range specified by @numerator_start/@denominator_start
1899 * and @numerator_end/@denominator_end.
1900 */
1901 void
gst_value_set_fraction_range_full(GValue * value,gint numerator_start,gint denominator_start,gint numerator_end,gint denominator_end)1902 gst_value_set_fraction_range_full (GValue * value,
1903 gint numerator_start, gint denominator_start,
1904 gint numerator_end, gint denominator_end)
1905 {
1906 GValue start = { 0 };
1907 GValue end = { 0 };
1908
1909 g_return_if_fail (value != NULL);
1910 g_return_if_fail (denominator_start != 0);
1911 g_return_if_fail (denominator_end != 0);
1912 g_return_if_fail (gst_util_fraction_compare (numerator_start,
1913 denominator_start, numerator_end, denominator_end) < 0);
1914
1915 g_value_init (&start, GST_TYPE_FRACTION);
1916 g_value_init (&end, GST_TYPE_FRACTION);
1917
1918 gst_value_set_fraction (&start, numerator_start, denominator_start);
1919 gst_value_set_fraction (&end, numerator_end, denominator_end);
1920 gst_value_set_fraction_range (value, &start, &end);
1921
1922 /* we know the two values contain fractions without internal allocs */
1923 /* g_value_unset (&start); */
1924 /* g_value_unset (&end); */
1925 }
1926
1927 /* FIXME 2.0: Don't leak the internal representation of fraction
1928 * ranges but instead return the numerator and denominator
1929 * separately.
1930 * This would allow to store fraction ranges as
1931 * data[0] = (min_n << 32) | (min_d)
1932 * data[1] = (max_n << 32) | (max_d)
1933 * without requiring an additional allocation for each value.
1934 */
1935
1936 /**
1937 * gst_value_get_fraction_range_min:
1938 * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1939 *
1940 * Gets the minimum of the range specified by @value.
1941 *
1942 * Returns: (nullable): the minimum of the range
1943 */
1944 const GValue *
gst_value_get_fraction_range_min(const GValue * value)1945 gst_value_get_fraction_range_min (const GValue * value)
1946 {
1947 GValue *vals;
1948
1949 g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value), NULL);
1950
1951 vals = (GValue *) value->data[0].v_pointer;
1952 if (vals != NULL) {
1953 return &vals[0];
1954 }
1955
1956 return NULL;
1957 }
1958
1959 /**
1960 * gst_value_get_fraction_range_max:
1961 * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1962 *
1963 * Gets the maximum of the range specified by @value.
1964 *
1965 * Returns: (nullable): the maximum of the range
1966 */
1967 const GValue *
gst_value_get_fraction_range_max(const GValue * value)1968 gst_value_get_fraction_range_max (const GValue * value)
1969 {
1970 GValue *vals;
1971
1972 g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value), NULL);
1973
1974 vals = (GValue *) value->data[0].v_pointer;
1975 if (vals != NULL) {
1976 return &vals[1];
1977 }
1978
1979 return NULL;
1980 }
1981
1982 static gchar *
gst_value_serialize_fraction_range(const GValue * value)1983 gst_value_serialize_fraction_range (const GValue * value)
1984 {
1985 GValue *vals = (GValue *) value->data[0].v_pointer;
1986 gchar *retval;
1987
1988 if (vals == NULL) {
1989 retval = g_strdup ("[ 0/1, 0/1 ]");
1990 } else {
1991 gchar *start, *end;
1992
1993 start = gst_value_serialize_fraction (&vals[0]);
1994 end = gst_value_serialize_fraction (&vals[1]);
1995
1996 retval = g_strdup_printf ("[ %s, %s ]", start, end);
1997 g_free (start);
1998 g_free (end);
1999 }
2000
2001 return retval;
2002 }
2003
2004 static void
gst_value_transform_fraction_range_string(const GValue * src_value,GValue * dest_value)2005 gst_value_transform_fraction_range_string (const GValue * src_value,
2006 GValue * dest_value)
2007 {
2008 dest_value->data[0].v_pointer =
2009 gst_value_serialize_fraction_range (src_value);
2010 }
2011
2012 static gint
gst_value_compare_fraction_range(const GValue * value1,const GValue * value2)2013 gst_value_compare_fraction_range (const GValue * value1, const GValue * value2)
2014 {
2015 GValue *vals1, *vals2;
2016 GstValueCompareFunc compare;
2017
2018 if (value2->data[0].v_pointer == value1->data[0].v_pointer)
2019 return GST_VALUE_EQUAL; /* Only possible if both are NULL */
2020
2021 if (value2->data[0].v_pointer == NULL || value1->data[0].v_pointer == NULL)
2022 return GST_VALUE_UNORDERED;
2023
2024 vals1 = (GValue *) value1->data[0].v_pointer;
2025 vals2 = (GValue *) value2->data[0].v_pointer;
2026 if ((compare = gst_value_get_compare_func (&vals1[0]))) {
2027 if (gst_value_compare_with_func (&vals1[0], &vals2[0], compare) ==
2028 GST_VALUE_EQUAL &&
2029 gst_value_compare_with_func (&vals1[1], &vals2[1], compare) ==
2030 GST_VALUE_EQUAL)
2031 return GST_VALUE_EQUAL;
2032 }
2033 return GST_VALUE_UNORDERED;
2034 }
2035
2036 static gboolean
gst_value_deserialize_fraction_range(GValue * dest,const gchar * s)2037 gst_value_deserialize_fraction_range (GValue * dest, const gchar * s)
2038 {
2039 g_warning ("unimplemented");
2040 return FALSE;
2041 }
2042
2043 /***********
2044 * GstCaps *
2045 ***********/
2046
2047 /**
2048 * gst_value_set_caps:
2049 * @value: a GValue initialized to GST_TYPE_CAPS
2050 * @caps: (transfer none): the caps to set the value to
2051 *
2052 * Sets the contents of @value to @caps. A reference to the
2053 * provided @caps will be taken by the @value.
2054 */
2055 void
gst_value_set_caps(GValue * value,const GstCaps * caps)2056 gst_value_set_caps (GValue * value, const GstCaps * caps)
2057 {
2058 g_return_if_fail (G_IS_VALUE (value));
2059 g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS);
2060 g_return_if_fail (caps == NULL || GST_IS_CAPS (caps));
2061
2062 g_value_set_boxed (value, caps);
2063 }
2064
2065 /**
2066 * gst_value_get_caps:
2067 * @value: a GValue initialized to GST_TYPE_CAPS
2068 *
2069 * Gets the contents of @value. The reference count of the returned
2070 * #GstCaps will not be modified, therefore the caller must take one
2071 * before getting rid of the @value.
2072 *
2073 * Returns: (transfer none): the contents of @value
2074 */
2075 const GstCaps *
gst_value_get_caps(const GValue * value)2076 gst_value_get_caps (const GValue * value)
2077 {
2078 g_return_val_if_fail (G_IS_VALUE (value), NULL);
2079 g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS, NULL);
2080
2081 return (GstCaps *) g_value_get_boxed (value);
2082 }
2083
2084 static gint
gst_value_compare_caps(const GValue * value1,const GValue * value2)2085 gst_value_compare_caps (const GValue * value1, const GValue * value2)
2086 {
2087 GstCaps *caps1 = GST_CAPS (gst_value_get_caps (value1));
2088 GstCaps *caps2 = GST_CAPS (gst_value_get_caps (value2));
2089
2090 if (gst_caps_is_equal (caps1, caps2))
2091 return GST_VALUE_EQUAL;
2092 return GST_VALUE_UNORDERED;
2093 }
2094
2095 static gchar *
gst_value_serialize_caps(const GValue * value)2096 gst_value_serialize_caps (const GValue * value)
2097 {
2098 GstCaps *caps = g_value_get_boxed (value);
2099 return priv_gst_string_take_and_wrap (gst_caps_to_string (caps));
2100 }
2101
2102 static gboolean
gst_value_deserialize_caps(GValue * dest,const gchar * s)2103 gst_value_deserialize_caps (GValue * dest, const gchar * s)
2104 {
2105 GstCaps *caps;
2106
2107 if (*s != '"') {
2108 caps = gst_caps_from_string (s);
2109 } else {
2110 gchar *str = gst_string_unwrap (s);
2111
2112 if (G_UNLIKELY (!str))
2113 return FALSE;
2114
2115 caps = gst_caps_from_string (str);
2116 g_free (str);
2117 }
2118
2119 if (caps) {
2120 g_value_take_boxed (dest, caps);
2121 return TRUE;
2122 }
2123 return FALSE;
2124 }
2125
2126 /********************************************
2127 * Serialization/deserialization of GValues *
2128 ********************************************/
2129
2130 static GstValueAbbreviation *
_priv_gst_value_get_abbrs(gint * n_abbrs)2131 _priv_gst_value_get_abbrs (gint * n_abbrs)
2132 {
2133 static GstValueAbbreviation *abbrs = NULL;
2134 static volatile gsize num = 0;
2135
2136 if (g_once_init_enter (&num)) {
2137 /* dynamically generate the array */
2138 gsize _num;
2139 GstValueAbbreviation dyn_abbrs[] = {
2140 {"int", G_TYPE_INT}
2141 ,
2142 {"i", G_TYPE_INT}
2143 ,
2144 {"uint", G_TYPE_UINT}
2145 ,
2146 {"u", G_TYPE_UINT}
2147 ,
2148 {"float", G_TYPE_FLOAT}
2149 ,
2150 {"f", G_TYPE_FLOAT}
2151 ,
2152 {"double", G_TYPE_DOUBLE}
2153 ,
2154 {"d", G_TYPE_DOUBLE}
2155 ,
2156 {"buffer", GST_TYPE_BUFFER}
2157 ,
2158 {"fraction", GST_TYPE_FRACTION}
2159 ,
2160 {"boolean", G_TYPE_BOOLEAN}
2161 ,
2162 {"bool", G_TYPE_BOOLEAN}
2163 ,
2164 {"b", G_TYPE_BOOLEAN}
2165 ,
2166 {"string", G_TYPE_STRING}
2167 ,
2168 {"str", G_TYPE_STRING}
2169 ,
2170 {"s", G_TYPE_STRING}
2171 ,
2172 {"structure", GST_TYPE_STRUCTURE}
2173 ,
2174 {"date", G_TYPE_DATE}
2175 ,
2176 {"datetime", GST_TYPE_DATE_TIME}
2177 ,
2178 {"bitmask", GST_TYPE_BITMASK}
2179 ,
2180 {"flagset", GST_TYPE_FLAG_SET}
2181 ,
2182 {"sample", GST_TYPE_SAMPLE}
2183 ,
2184 {"taglist", GST_TYPE_TAG_LIST}
2185 ,
2186 {"type", G_TYPE_GTYPE}
2187 ,
2188 {"array", GST_TYPE_ARRAY}
2189 ,
2190 {"list", GST_TYPE_LIST}
2191 };
2192 _num = G_N_ELEMENTS (dyn_abbrs);
2193 /* permanently allocate and copy the array now */
2194 abbrs = g_new0 (GstValueAbbreviation, _num);
2195 memcpy (abbrs, dyn_abbrs, sizeof (GstValueAbbreviation) * _num);
2196 g_once_init_leave (&num, _num);
2197 }
2198 *n_abbrs = num;
2199
2200 return abbrs;
2201 }
2202
2203 /* given a type_name that could be a type abbreviation or a registered GType,
2204 * return a matching GType */
2205 static GType
_priv_gst_value_gtype_from_abbr(const char * type_name)2206 _priv_gst_value_gtype_from_abbr (const char *type_name)
2207 {
2208 int i;
2209 GstValueAbbreviation *abbrs;
2210 gint n_abbrs;
2211 GType ret;
2212
2213 g_return_val_if_fail (type_name != NULL, G_TYPE_INVALID);
2214
2215 abbrs = _priv_gst_value_get_abbrs (&n_abbrs);
2216
2217 for (i = 0; i < n_abbrs; i++) {
2218 if (strcmp (type_name, abbrs[i].type_name) == 0) {
2219 return abbrs[i].type;
2220 }
2221 }
2222
2223 /* this is the fallback */
2224 ret = g_type_from_name (type_name);
2225 /* If not found, try it as a dynamic type */
2226 if (G_UNLIKELY (ret == 0))
2227 ret = gst_dynamic_type_factory_load (type_name);
2228 return ret;
2229
2230 }
2231
2232 const char *
_priv_gst_value_gtype_to_abbr(GType type)2233 _priv_gst_value_gtype_to_abbr (GType type)
2234 {
2235 int i;
2236 GstValueAbbreviation *abbrs;
2237 gint n_abbrs;
2238
2239 g_return_val_if_fail (type != G_TYPE_INVALID, NULL);
2240
2241 abbrs = _priv_gst_value_get_abbrs (&n_abbrs);
2242
2243 for (i = 0; i < n_abbrs; i++) {
2244 if (type == abbrs[i].type) {
2245 return abbrs[i].type_name;
2246 }
2247 }
2248
2249 return g_type_name (type);
2250 }
2251
2252 /*
2253 * _priv_gst_value_parse_string:
2254 * @s: string to parse
2255 * @end: out-pointer to char behind end of string
2256 * @next: out-pointer to start of unread data
2257 * @unescape: @TRUE if the substring is escaped.
2258 *
2259 * Find the end of a sub-string. If end == next, the string will not be
2260 * null-terminated. In all other cases it will be.
2261 *
2262 * Note: This function modifies the string in @s (if unescape == @TRUE).
2263 *
2264 * Returns: @TRUE if a sub-string was found and @FALSE if the string is not
2265 * terminated.
2266 */
2267 gboolean
_priv_gst_value_parse_string(gchar * s,gchar ** end,gchar ** next,gboolean unescape)2268 _priv_gst_value_parse_string (gchar * s, gchar ** end, gchar ** next,
2269 gboolean unescape)
2270 {
2271 gchar *w;
2272
2273 if (*s == 0)
2274 return FALSE;
2275
2276 if (*s != '"') {
2277 int ret = _priv_gst_value_parse_simple_string (s, end);
2278 *next = *end;
2279
2280 return ret;
2281 }
2282
2283 /* Find the closing quotes */
2284 if (unescape) {
2285 w = s;
2286 s++;
2287 while (*s != '"') {
2288 if (G_UNLIKELY (*s == 0))
2289 return FALSE;
2290 if (G_UNLIKELY (*s == '\\')) {
2291 s++;
2292 if (G_UNLIKELY (*s == 0))
2293 return FALSE;
2294 }
2295 *w = *s;
2296 w++;
2297 s++;
2298 }
2299 s++;
2300 } else {
2301 s++;
2302 while (*s != '"') {
2303 if (G_UNLIKELY (*s == 0))
2304 return FALSE;
2305 if (G_UNLIKELY (*s == '\\')) {
2306 s++;
2307 if (G_UNLIKELY (*s == 0))
2308 return FALSE;
2309 }
2310 s++;
2311 }
2312 s++;
2313 w = s;
2314 }
2315
2316 *end = w;
2317 *next = s;
2318
2319 return TRUE;
2320 }
2321
2322 static gboolean
_priv_gst_value_parse_range(gchar * s,gchar ** after,GValue * value,GType type)2323 _priv_gst_value_parse_range (gchar * s, gchar ** after, GValue * value,
2324 GType type)
2325 {
2326 GValue value1 = { 0 };
2327 GValue value2 = { 0 };
2328 GValue value3 = { 0 };
2329 GType range_type;
2330 gboolean ret, have_step = FALSE;
2331
2332 if (*s != '[')
2333 return FALSE;
2334 s++;
2335
2336 ret = _priv_gst_value_parse_value (s, &s, &value1, type);
2337 if (!ret)
2338 return FALSE;
2339
2340 while (g_ascii_isspace (*s))
2341 s++;
2342
2343 if (*s != ',')
2344 return FALSE;
2345 s++;
2346
2347 while (g_ascii_isspace (*s))
2348 s++;
2349
2350 ret = _priv_gst_value_parse_value (s, &s, &value2, type);
2351 if (!ret)
2352 return FALSE;
2353
2354 while (g_ascii_isspace (*s))
2355 s++;
2356
2357 /* optional step for int and int64 */
2358 if (G_VALUE_TYPE (&value1) == G_TYPE_INT
2359 || G_VALUE_TYPE (&value1) == G_TYPE_INT64) {
2360 if (*s == ',') {
2361 s++;
2362
2363 while (g_ascii_isspace (*s))
2364 s++;
2365
2366 ret = _priv_gst_value_parse_value (s, &s, &value3, type);
2367 if (!ret)
2368 return FALSE;
2369
2370 while (g_ascii_isspace (*s))
2371 s++;
2372
2373 have_step = TRUE;
2374 }
2375 }
2376
2377 if (*s != ']')
2378 return FALSE;
2379 s++;
2380
2381 if (G_VALUE_TYPE (&value1) != G_VALUE_TYPE (&value2))
2382 return FALSE;
2383 if (have_step && G_VALUE_TYPE (&value1) != G_VALUE_TYPE (&value3))
2384 return FALSE;
2385
2386 if (G_VALUE_TYPE (&value1) == G_TYPE_DOUBLE) {
2387 range_type = GST_TYPE_DOUBLE_RANGE;
2388 g_value_init (value, range_type);
2389 gst_value_set_double_range (value,
2390 gst_g_value_get_double_unchecked (&value1),
2391 gst_g_value_get_double_unchecked (&value2));
2392 } else if (G_VALUE_TYPE (&value1) == G_TYPE_INT) {
2393 range_type = GST_TYPE_INT_RANGE;
2394 g_value_init (value, range_type);
2395 if (have_step)
2396 gst_value_set_int_range_step (value,
2397 gst_g_value_get_int_unchecked (&value1),
2398 gst_g_value_get_int_unchecked (&value2),
2399 gst_g_value_get_int_unchecked (&value3));
2400 else
2401 gst_value_set_int_range (value, gst_g_value_get_int_unchecked (&value1),
2402 gst_g_value_get_int_unchecked (&value2));
2403 } else if (G_VALUE_TYPE (&value1) == G_TYPE_INT64) {
2404 range_type = GST_TYPE_INT64_RANGE;
2405 g_value_init (value, range_type);
2406 if (have_step)
2407 gst_value_set_int64_range_step (value,
2408 gst_g_value_get_int64_unchecked (&value1),
2409 gst_g_value_get_int64_unchecked (&value2),
2410 gst_g_value_get_int64_unchecked (&value3));
2411 else
2412 gst_value_set_int64_range (value,
2413 gst_g_value_get_int64_unchecked (&value1),
2414 gst_g_value_get_int64_unchecked (&value2));
2415 } else if (G_VALUE_TYPE (&value1) == GST_TYPE_FRACTION) {
2416 range_type = GST_TYPE_FRACTION_RANGE;
2417 g_value_init (value, range_type);
2418 gst_value_set_fraction_range (value, &value1, &value2);
2419 } else {
2420 return FALSE;
2421 }
2422
2423 *after = s;
2424 return TRUE;
2425 }
2426
2427 static gboolean
_priv_gst_value_parse_any_list(gchar * s,gchar ** after,GValue * value,GType type,char begin,char end)2428 _priv_gst_value_parse_any_list (gchar * s, gchar ** after, GValue * value,
2429 GType type, char begin, char end)
2430 {
2431 GValue list_value = { 0 };
2432 gboolean ret;
2433 GArray *array;
2434
2435 array = g_value_peek_pointer (value);
2436
2437 if (*s != begin)
2438 return FALSE;
2439 s++;
2440
2441 while (g_ascii_isspace (*s))
2442 s++;
2443 if (*s == end) {
2444 s++;
2445 *after = s;
2446 return TRUE;
2447 }
2448
2449 ret = _priv_gst_value_parse_value (s, &s, &list_value, type);
2450 if (!ret)
2451 return FALSE;
2452
2453 g_array_append_val (array, list_value);
2454
2455 while (g_ascii_isspace (*s))
2456 s++;
2457
2458 while (*s != end) {
2459 if (*s != ',')
2460 return FALSE;
2461 s++;
2462
2463 while (g_ascii_isspace (*s))
2464 s++;
2465
2466 memset (&list_value, 0, sizeof (list_value));
2467 ret = _priv_gst_value_parse_value (s, &s, &list_value, type);
2468 if (!ret)
2469 return FALSE;
2470
2471 g_array_append_val (array, list_value);
2472 while (g_ascii_isspace (*s))
2473 s++;
2474 }
2475
2476 s++;
2477
2478 *after = s;
2479 return TRUE;
2480 }
2481
2482 static gboolean
_priv_gst_value_parse_list(gchar * s,gchar ** after,GValue * value,GType type)2483 _priv_gst_value_parse_list (gchar * s, gchar ** after, GValue * value,
2484 GType type)
2485 {
2486 return _priv_gst_value_parse_any_list (s, after, value, type, '{', '}');
2487 }
2488
2489 static gboolean
_priv_gst_value_parse_array(gchar * s,gchar ** after,GValue * value,GType type)2490 _priv_gst_value_parse_array (gchar * s, gchar ** after, GValue * value,
2491 GType type)
2492 {
2493 return _priv_gst_value_parse_any_list (s, after, value, type, '<', '>');
2494 }
2495
2496 gboolean
_priv_gst_value_parse_simple_string(gchar * str,gchar ** end)2497 _priv_gst_value_parse_simple_string (gchar * str, gchar ** end)
2498 {
2499 char *s = str;
2500
2501 while (G_LIKELY (GST_ASCII_IS_STRING (*s))) {
2502 s++;
2503 }
2504
2505 *end = s;
2506
2507 return (s != str);
2508 }
2509
2510 gboolean
_priv_gst_value_parse_value(gchar * str,gchar ** after,GValue * value,GType default_type)2511 _priv_gst_value_parse_value (gchar * str,
2512 gchar ** after, GValue * value, GType default_type)
2513 {
2514 gchar *type_name;
2515 gchar *type_end;
2516 gchar *value_s;
2517 gchar *value_end;
2518 gchar *s;
2519 gchar c;
2520 int ret = 0;
2521 GType type = default_type;
2522
2523 s = str;
2524 while (g_ascii_isspace (*s))
2525 s++;
2526
2527 /* check if there's a (type_name) 'cast' */
2528 type_name = NULL;
2529 if (*s == '(') {
2530 s++;
2531 while (g_ascii_isspace (*s))
2532 s++;
2533 type_name = s;
2534 if (G_UNLIKELY (!_priv_gst_value_parse_simple_string (s, &type_end)))
2535 return FALSE;
2536 s = type_end;
2537 while (g_ascii_isspace (*s))
2538 s++;
2539 if (G_UNLIKELY (*s != ')'))
2540 return FALSE;
2541 s++;
2542 while (g_ascii_isspace (*s))
2543 s++;
2544
2545 c = *type_end;
2546 *type_end = 0;
2547 type = _priv_gst_value_gtype_from_abbr (type_name);
2548 GST_DEBUG ("trying type name '%s'", type_name);
2549 *type_end = c;
2550
2551 if (G_UNLIKELY (type == G_TYPE_INVALID)) {
2552 GST_WARNING ("invalid type");
2553 return FALSE;
2554 }
2555 }
2556
2557 while (g_ascii_isspace (*s))
2558 s++;
2559 if (*s == '[') {
2560 ret = _priv_gst_value_parse_range (s, &s, value, type);
2561 } else if (*s == '{') {
2562 g_value_init (value, GST_TYPE_LIST);
2563 ret = _priv_gst_value_parse_list (s, &s, value, type);
2564 } else if (*s == '<') {
2565 g_value_init (value, GST_TYPE_ARRAY);
2566 ret = _priv_gst_value_parse_array (s, &s, value, type);
2567 } else {
2568 value_s = s;
2569
2570 if (G_UNLIKELY (type == G_TYPE_INVALID)) {
2571 GType try_types[] =
2572 { G_TYPE_INT, G_TYPE_DOUBLE, GST_TYPE_FRACTION, GST_TYPE_FLAG_SET,
2573 G_TYPE_BOOLEAN, G_TYPE_STRING
2574 };
2575 int i;
2576
2577 if (G_UNLIKELY (!_priv_gst_value_parse_string (s, &value_end, &s, TRUE)))
2578 return FALSE;
2579 /* Set NULL terminator for deserialization */
2580 c = *value_end;
2581 *value_end = '\0';
2582
2583 for (i = 0; i < G_N_ELEMENTS (try_types); i++) {
2584 g_value_init (value, try_types[i]);
2585 ret = gst_value_deserialize (value, value_s);
2586 if (ret)
2587 break;
2588 g_value_unset (value);
2589 }
2590 } else {
2591 g_value_init (value, type);
2592
2593 if (G_UNLIKELY (!_priv_gst_value_parse_string (s, &value_end, &s,
2594 (type != G_TYPE_STRING))))
2595 return FALSE;
2596 /* Set NULL terminator for deserialization */
2597 c = *value_end;
2598 *value_end = '\0';
2599
2600 ret = gst_value_deserialize (value, value_s);
2601 if (G_UNLIKELY (!ret))
2602 g_value_unset (value);
2603 }
2604 *value_end = c;
2605 }
2606
2607 *after = s;
2608
2609 return ret;
2610 }
2611
2612 /**************
2613 * GstSegment *
2614 **************/
2615
2616 static gchar *
gst_value_serialize_segment_internal(const GValue * value,gboolean escape)2617 gst_value_serialize_segment_internal (const GValue * value, gboolean escape)
2618 {
2619 GstSegment *seg = g_value_get_boxed (value);
2620 gchar *t, *res;
2621 GstStructure *s;
2622
2623 s = gst_structure_new ("GstSegment",
2624 "flags", GST_TYPE_SEGMENT_FLAGS, seg->flags,
2625 "rate", G_TYPE_DOUBLE, seg->rate,
2626 "applied-rate", G_TYPE_DOUBLE, seg->applied_rate,
2627 "format", GST_TYPE_FORMAT, seg->format,
2628 "base", G_TYPE_UINT64, seg->base,
2629 "offset", G_TYPE_UINT64, seg->offset,
2630 "start", G_TYPE_UINT64, seg->start,
2631 "stop", G_TYPE_UINT64, seg->stop,
2632 "time", G_TYPE_UINT64, seg->time,
2633 "position", G_TYPE_UINT64, seg->position,
2634 "duration", G_TYPE_UINT64, seg->duration, NULL);
2635 t = gst_structure_to_string (s);
2636 if (escape) {
2637 res = g_strdup_printf ("\"%s\"", t);
2638 g_free (t);
2639 } else {
2640 res = t;
2641 }
2642 gst_structure_free (s);
2643
2644 return res;
2645 }
2646
2647 static gchar *
gst_value_serialize_segment(const GValue * value)2648 gst_value_serialize_segment (const GValue * value)
2649 {
2650 return gst_value_serialize_segment_internal (value, TRUE);
2651 }
2652
2653 static gboolean
gst_value_deserialize_segment(GValue * dest,const gchar * s)2654 gst_value_deserialize_segment (GValue * dest, const gchar * s)
2655 {
2656 GstStructure *str;
2657 GstSegment seg;
2658 gboolean res;
2659
2660 str = gst_structure_from_string (s, NULL);
2661 if (str == NULL)
2662 return FALSE;
2663
2664 res = gst_structure_get (str,
2665 "flags", GST_TYPE_SEGMENT_FLAGS, &seg.flags,
2666 "rate", G_TYPE_DOUBLE, &seg.rate,
2667 "applied-rate", G_TYPE_DOUBLE, &seg.applied_rate,
2668 "format", GST_TYPE_FORMAT, &seg.format,
2669 "base", G_TYPE_UINT64, &seg.base,
2670 "offset", G_TYPE_UINT64, &seg.offset,
2671 "start", G_TYPE_UINT64, &seg.start,
2672 "stop", G_TYPE_UINT64, &seg.stop,
2673 "time", G_TYPE_UINT64, &seg.time,
2674 "position", G_TYPE_UINT64, &seg.position,
2675 "duration", G_TYPE_UINT64, &seg.duration, NULL);
2676 gst_structure_free (str);
2677
2678 if (res)
2679 g_value_set_boxed (dest, &seg);
2680
2681 return res;
2682 }
2683
2684 /****************
2685 * GstStructure *
2686 ****************/
2687
2688 /**
2689 * gst_value_set_structure:
2690 * @value: a GValue initialized to GST_TYPE_STRUCTURE
2691 * @structure: the structure to set the value to
2692 *
2693 * Sets the contents of @value to @structure.
2694 */
2695 void
gst_value_set_structure(GValue * value,const GstStructure * structure)2696 gst_value_set_structure (GValue * value, const GstStructure * structure)
2697 {
2698 g_return_if_fail (G_IS_VALUE (value));
2699 g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE);
2700 g_return_if_fail (structure == NULL || GST_IS_STRUCTURE (structure));
2701
2702 g_value_set_boxed (value, structure);
2703 }
2704
2705 /**
2706 * gst_value_get_structure:
2707 * @value: a GValue initialized to GST_TYPE_STRUCTURE
2708 *
2709 * Gets the contents of @value.
2710 *
2711 * Returns: (transfer none): the contents of @value
2712 */
2713 const GstStructure *
gst_value_get_structure(const GValue * value)2714 gst_value_get_structure (const GValue * value)
2715 {
2716 g_return_val_if_fail (G_IS_VALUE (value), NULL);
2717 g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE, NULL);
2718
2719 return (GstStructure *) g_value_get_boxed (value);
2720 }
2721
2722 static gchar *
gst_value_serialize_structure(const GValue * value)2723 gst_value_serialize_structure (const GValue * value)
2724 {
2725 GstStructure *structure = g_value_get_boxed (value);
2726
2727 return priv_gst_string_take_and_wrap (gst_structure_to_string (structure));
2728 }
2729
2730 static gboolean
gst_value_deserialize_structure(GValue * dest,const gchar * s)2731 gst_value_deserialize_structure (GValue * dest, const gchar * s)
2732 {
2733 GstStructure *structure;
2734
2735 if (*s != '"') {
2736 structure = gst_structure_from_string (s, NULL);
2737 } else {
2738 gchar *str = gst_string_unwrap (s);
2739
2740 if (G_UNLIKELY (!str))
2741 return FALSE;
2742
2743 structure = gst_structure_from_string (str, NULL);
2744 g_free (str);
2745 }
2746
2747 if (G_LIKELY (structure)) {
2748 g_value_take_boxed (dest, structure);
2749 return TRUE;
2750 }
2751 return FALSE;
2752 }
2753
2754 static gboolean
gst_value_compare_structure(const GValue * value1,const GValue * value2)2755 gst_value_compare_structure (const GValue * value1, const GValue * value2)
2756 {
2757 GstStructure *structure1 = GST_STRUCTURE (g_value_get_boxed (value1));
2758 GstStructure *structure2 = GST_STRUCTURE (g_value_get_boxed (value2));
2759
2760 if (structure1 == structure2)
2761 return GST_VALUE_EQUAL;
2762
2763 if (!structure1 || !structure2)
2764 return GST_VALUE_UNORDERED;
2765
2766 if (gst_structure_is_equal (structure1, structure2))
2767 return GST_VALUE_EQUAL;
2768
2769 return GST_VALUE_UNORDERED;
2770 }
2771
2772 /*******************
2773 * GstCapsFeatures *
2774 *******************/
2775
2776 /**
2777 * gst_value_set_caps_features:
2778 * @value: a GValue initialized to GST_TYPE_CAPS_FEATURES
2779 * @features: the features to set the value to
2780 *
2781 * Sets the contents of @value to @features.
2782 */
2783 void
gst_value_set_caps_features(GValue * value,const GstCapsFeatures * features)2784 gst_value_set_caps_features (GValue * value, const GstCapsFeatures * features)
2785 {
2786 g_return_if_fail (G_IS_VALUE (value));
2787 g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS_FEATURES);
2788 g_return_if_fail (features == NULL || GST_IS_CAPS_FEATURES (features));
2789
2790 g_value_set_boxed (value, features);
2791 }
2792
2793 /**
2794 * gst_value_get_caps_features:
2795 * @value: a GValue initialized to GST_TYPE_CAPS_FEATURES
2796 *
2797 * Gets the contents of @value.
2798 *
2799 * Returns: (transfer none): the contents of @value
2800 */
2801 const GstCapsFeatures *
gst_value_get_caps_features(const GValue * value)2802 gst_value_get_caps_features (const GValue * value)
2803 {
2804 g_return_val_if_fail (G_IS_VALUE (value), NULL);
2805 g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS_FEATURES, NULL);
2806
2807 return (GstCapsFeatures *) g_value_get_boxed (value);
2808 }
2809
2810 static gchar *
gst_value_serialize_caps_features(const GValue * value)2811 gst_value_serialize_caps_features (const GValue * value)
2812 {
2813 GstCapsFeatures *features = g_value_get_boxed (value);
2814
2815 return priv_gst_string_take_and_wrap (gst_caps_features_to_string (features));
2816 }
2817
2818 static gboolean
gst_value_deserialize_caps_features(GValue * dest,const gchar * s)2819 gst_value_deserialize_caps_features (GValue * dest, const gchar * s)
2820 {
2821 GstCapsFeatures *features;
2822
2823 if (*s != '"') {
2824 features = gst_caps_features_from_string (s);
2825 } else {
2826 gchar *str = gst_string_unwrap (s);
2827
2828 if (G_UNLIKELY (!str))
2829 return FALSE;
2830
2831 features = gst_caps_features_from_string (str);
2832 g_free (str);
2833 }
2834
2835 if (G_LIKELY (features)) {
2836 g_value_take_boxed (dest, features);
2837 return TRUE;
2838 }
2839 return FALSE;
2840 }
2841
2842 /**************
2843 * GstTagList *
2844 **************/
2845 static gint
gst_value_compare_tag_list(const GValue * value1,const GValue * value2)2846 gst_value_compare_tag_list (const GValue * value1, const GValue * value2)
2847 {
2848 GstTagList *taglist1 = GST_TAG_LIST (g_value_get_boxed (value1));
2849 GstTagList *taglist2 = GST_TAG_LIST (g_value_get_boxed (value2));
2850
2851 if (gst_tag_list_is_equal (taglist1, taglist2))
2852 return GST_VALUE_EQUAL;
2853 return GST_VALUE_UNORDERED;
2854 }
2855
2856 static gboolean
gst_value_deserialize_tag_list(GValue * dest,const gchar * s)2857 gst_value_deserialize_tag_list (GValue * dest, const gchar * s)
2858 {
2859 GstTagList *taglist;
2860
2861 if (*s != '"') {
2862 taglist = gst_tag_list_new_from_string (s);
2863 } else {
2864 gchar *str = gst_string_unwrap (s);
2865
2866 if (G_UNLIKELY (!str))
2867 return FALSE;
2868
2869 taglist = gst_tag_list_new_from_string (str);
2870 g_free (str);
2871 }
2872
2873 if (G_LIKELY (taglist != NULL)) {
2874 g_value_take_boxed (dest, taglist);
2875 return TRUE;
2876 }
2877 return FALSE;
2878 }
2879
2880 static gchar *
gst_value_serialize_tag_list(const GValue * value)2881 gst_value_serialize_tag_list (const GValue * value)
2882 {
2883 GstTagList *taglist = g_value_get_boxed (value);
2884
2885 return priv_gst_string_take_and_wrap (gst_tag_list_to_string (taglist));
2886 }
2887
2888
2889 /*************
2890 * GstBuffer *
2891 *************/
2892
2893 static gint
compare_buffer(GstBuffer * buf1,GstBuffer * buf2)2894 compare_buffer (GstBuffer * buf1, GstBuffer * buf2)
2895 {
2896 gsize size1, size2;
2897 GstMapInfo info1, info2;
2898 gint result, mret;
2899
2900 if (buf1 == buf2)
2901 return GST_VALUE_EQUAL;
2902
2903 size1 = gst_buffer_get_size (buf1);
2904 size2 = gst_buffer_get_size (buf2);
2905
2906 if (size1 != size2)
2907 return GST_VALUE_UNORDERED;
2908
2909 if (size1 == 0)
2910 return GST_VALUE_EQUAL;
2911
2912 if (!gst_buffer_map (buf1, &info1, GST_MAP_READ))
2913 return GST_VALUE_UNORDERED;
2914
2915 if (!gst_buffer_map (buf2, &info2, GST_MAP_READ)) {
2916 gst_buffer_unmap (buf1, &info1);
2917 return GST_VALUE_UNORDERED;
2918 }
2919
2920 mret = memcmp (info1.data, info2.data, info1.size);
2921 if (mret == 0)
2922 result = GST_VALUE_EQUAL;
2923 else if (mret < 0)
2924 result = GST_VALUE_LESS_THAN;
2925 else
2926 result = GST_VALUE_GREATER_THAN;
2927
2928 gst_buffer_unmap (buf1, &info1);
2929 gst_buffer_unmap (buf2, &info2);
2930
2931 return result;
2932 }
2933
2934 static gint
gst_value_compare_buffer(const GValue * value1,const GValue * value2)2935 gst_value_compare_buffer (const GValue * value1, const GValue * value2)
2936 {
2937 GstBuffer *buf1 = gst_value_get_buffer (value1);
2938 GstBuffer *buf2 = gst_value_get_buffer (value2);
2939
2940 return compare_buffer (buf1, buf2);
2941 }
2942
2943 static gchar *
gst_value_serialize_buffer(const GValue * value)2944 gst_value_serialize_buffer (const GValue * value)
2945 {
2946 GstMapInfo info;
2947 guint8 *data;
2948 gint i;
2949 gchar *string;
2950 GstBuffer *buffer;
2951
2952 buffer = gst_value_get_buffer (value);
2953 if (buffer == NULL)
2954 return NULL;
2955
2956 if (!gst_buffer_map (buffer, &info, GST_MAP_READ))
2957 return NULL;
2958
2959 data = info.data;
2960
2961 string = g_malloc (info.size * 2 + 1);
2962 for (i = 0; i < info.size; i++) {
2963 sprintf (string + i * 2, "%02x", data[i]);
2964 }
2965 string[info.size * 2] = 0;
2966
2967 gst_buffer_unmap (buffer, &info);
2968
2969 return string;
2970 }
2971
2972 static gboolean
gst_value_deserialize_buffer(GValue * dest,const gchar * s)2973 gst_value_deserialize_buffer (GValue * dest, const gchar * s)
2974 {
2975 GstBuffer *buffer;
2976 gint len;
2977 gchar ts[3];
2978 GstMapInfo info;
2979 guint8 *data;
2980 gint i;
2981
2982 len = strlen (s);
2983 if (len & 1)
2984 goto wrong_length;
2985
2986 buffer = gst_buffer_new_allocate (NULL, len / 2, NULL);
2987 if (!gst_buffer_map (buffer, &info, GST_MAP_WRITE))
2988 goto map_failed;
2989 data = info.data;
2990
2991 for (i = 0; i < len / 2; i++) {
2992 if (!isxdigit ((int) s[i * 2]) || !isxdigit ((int) s[i * 2 + 1]))
2993 goto wrong_char;
2994
2995 ts[0] = s[i * 2 + 0];
2996 ts[1] = s[i * 2 + 1];
2997 ts[2] = 0;
2998
2999 data[i] = (guint8) strtoul (ts, NULL, 16);
3000 }
3001 gst_buffer_unmap (buffer, &info);
3002
3003 gst_value_take_buffer (dest, buffer);
3004
3005 return TRUE;
3006
3007 /* ERRORS */
3008 wrong_length:
3009 {
3010 return FALSE;
3011 }
3012 map_failed:
3013 {
3014 return FALSE;
3015 }
3016 wrong_char:
3017 {
3018 gst_buffer_unref (buffer);
3019 gst_buffer_unmap (buffer, &info);
3020 return FALSE;
3021 }
3022 }
3023
3024 /*************
3025 * GstSample *
3026 *************/
3027
3028 /* This function is mostly used for comparing image/buffer tags in taglists */
3029 static gint
gst_value_compare_sample(const GValue * value1,const GValue * value2)3030 gst_value_compare_sample (const GValue * value1, const GValue * value2)
3031 {
3032 GstBuffer *buf1 = gst_sample_get_buffer (gst_value_get_sample (value1));
3033 GstBuffer *buf2 = gst_sample_get_buffer (gst_value_get_sample (value2));
3034
3035 /* FIXME: should we take into account anything else such as caps? */
3036 return compare_buffer (buf1, buf2);
3037 }
3038
3039 static gchar *
gst_value_serialize_sample(const GValue * value)3040 gst_value_serialize_sample (const GValue * value)
3041 {
3042 const GstStructure *info_structure;
3043 GstSegment *segment;
3044 GstBuffer *buffer;
3045 GstCaps *caps;
3046 GstSample *sample;
3047 GValue val = { 0, };
3048 gchar *info_str, *caps_str, *tmp;
3049 gchar *buf_str, *seg_str, *s;
3050
3051 sample = g_value_get_boxed (value);
3052
3053 buffer = gst_sample_get_buffer (sample);
3054 if (buffer) {
3055 g_value_init (&val, GST_TYPE_BUFFER);
3056 g_value_set_boxed (&val, buffer);
3057 buf_str = gst_value_serialize_buffer (&val);
3058 g_value_unset (&val);
3059 } else {
3060 buf_str = g_strdup ("None");
3061 }
3062
3063 caps = gst_sample_get_caps (sample);
3064 if (caps) {
3065 tmp = gst_caps_to_string (caps);
3066 caps_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1);
3067 g_strdelimit (caps_str, "=", '_');
3068 g_free (tmp);
3069 } else {
3070 caps_str = g_strdup ("None");
3071 }
3072
3073 segment = gst_sample_get_segment (sample);
3074 if (segment) {
3075 g_value_init (&val, GST_TYPE_SEGMENT);
3076 g_value_set_boxed (&val, segment);
3077 tmp = gst_value_serialize_segment_internal (&val, FALSE);
3078 seg_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1);
3079 g_strdelimit (seg_str, "=", '_');
3080 g_free (tmp);
3081 g_value_unset (&val);
3082 } else {
3083 seg_str = g_strdup ("None");
3084 }
3085
3086 info_structure = gst_sample_get_info (sample);
3087 if (info_structure) {
3088 tmp = gst_structure_to_string (info_structure);
3089 info_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1);
3090 g_strdelimit (info_str, "=", '_');
3091 g_free (tmp);
3092 } else {
3093 info_str = g_strdup ("None");
3094 }
3095
3096 s = g_strconcat (buf_str, ":", caps_str, ":", seg_str, ":", info_str, NULL);
3097 g_free (buf_str);
3098 g_free (caps_str);
3099 g_free (seg_str);
3100 g_free (info_str);
3101
3102 return s;
3103 }
3104
3105 static gboolean
gst_value_deserialize_sample(GValue * dest,const gchar * s)3106 gst_value_deserialize_sample (GValue * dest, const gchar * s)
3107 {
3108 GValue bval = G_VALUE_INIT, sval = G_VALUE_INIT;
3109 GstStructure *info;
3110 GstSample *sample;
3111 GstCaps *caps = NULL;
3112 gboolean ret = FALSE;
3113 gchar **fields;
3114 gsize outlen;
3115 gint len;
3116
3117 GST_TRACE ("deserialize '%s'", s);
3118
3119 fields = g_strsplit (s, ":", -1);
3120 len = g_strv_length (fields);
3121 if (len != 4)
3122 goto wrong_length;
3123
3124 g_value_init (&bval, GST_TYPE_BUFFER);
3125 g_value_init (&sval, GST_TYPE_SEGMENT);
3126
3127 if (!gst_value_deserialize_buffer (&bval, fields[0]))
3128 goto fail;
3129
3130 if (strcmp (fields[1], "None") != 0) {
3131 g_strdelimit (fields[1], "_", '=');
3132 g_base64_decode_inplace (fields[1], &outlen);
3133 GST_TRACE ("caps : %s", fields[1]);
3134 caps = gst_caps_from_string (fields[1]);
3135 if (caps == NULL)
3136 goto fail;
3137 }
3138
3139 if (strcmp (fields[2], "None") != 0) {
3140 g_strdelimit (fields[2], "_", '=');
3141 g_base64_decode_inplace (fields[2], &outlen);
3142 GST_TRACE ("segment : %s", fields[2]);
3143 if (!gst_value_deserialize_segment (&sval, fields[2]))
3144 goto fail;
3145 }
3146
3147 if (strcmp (fields[3], "None") != 0) {
3148 g_strdelimit (fields[3], "_", '=');
3149 g_base64_decode_inplace (fields[3], &outlen);
3150 GST_TRACE ("info : %s", fields[3]);
3151 info = gst_structure_from_string (fields[3], NULL);
3152 if (info == NULL)
3153 goto fail;
3154 } else {
3155 info = NULL;
3156 }
3157
3158 sample = gst_sample_new (gst_value_get_buffer (&bval), caps,
3159 g_value_get_boxed (&sval), info);
3160
3161 g_value_take_boxed (dest, sample);
3162
3163 ret = TRUE;
3164
3165 fail:
3166 if (caps)
3167 gst_caps_unref (caps);
3168 g_value_unset (&bval);
3169 g_value_unset (&sval);
3170
3171 wrong_length:
3172
3173 g_strfreev (fields);
3174
3175 return ret;
3176 }
3177
3178 /***********
3179 * boolean *
3180 ***********/
3181
3182 static gint
gst_value_compare_boolean(const GValue * value1,const GValue * value2)3183 gst_value_compare_boolean (const GValue * value1, const GValue * value2)
3184 {
3185 if ((value1->data[0].v_int != 0) == (value2->data[0].v_int != 0))
3186 return GST_VALUE_EQUAL;
3187 return GST_VALUE_UNORDERED;
3188 }
3189
3190 static gchar *
gst_value_serialize_boolean(const GValue * value)3191 gst_value_serialize_boolean (const GValue * value)
3192 {
3193 if (value->data[0].v_int) {
3194 return g_strdup ("true");
3195 }
3196 return g_strdup ("false");
3197 }
3198
3199 static gboolean
gst_value_deserialize_boolean(GValue * dest,const gchar * s)3200 gst_value_deserialize_boolean (GValue * dest, const gchar * s)
3201 {
3202 gboolean ret = FALSE;
3203
3204 if (g_ascii_strcasecmp (s, "true") == 0 ||
3205 g_ascii_strcasecmp (s, "yes") == 0 ||
3206 g_ascii_strcasecmp (s, "t") == 0 || strcmp (s, "1") == 0) {
3207 g_value_set_boolean (dest, TRUE);
3208 ret = TRUE;
3209 } else if (g_ascii_strcasecmp (s, "false") == 0 ||
3210 g_ascii_strcasecmp (s, "no") == 0 ||
3211 g_ascii_strcasecmp (s, "f") == 0 || strcmp (s, "0") == 0) {
3212 g_value_set_boolean (dest, FALSE);
3213 ret = TRUE;
3214 }
3215
3216 return ret;
3217 }
3218
3219 #define CREATE_SERIALIZATION_START(_type,_macro) \
3220 static gint \
3221 gst_value_compare_ ## _type \
3222 (const GValue * value1, const GValue * value2) \
3223 { \
3224 g ## _type val1 = g_value_get_ ## _type (value1); \
3225 g ## _type val2 = g_value_get_ ## _type (value2); \
3226 if (val1 > val2) \
3227 return GST_VALUE_GREATER_THAN; \
3228 if (val1 < val2) \
3229 return GST_VALUE_LESS_THAN; \
3230 return GST_VALUE_EQUAL; \
3231 } \
3232 \
3233 static gchar * \
3234 gst_value_serialize_ ## _type (const GValue * value) \
3235 { \
3236 GValue val = { 0, }; \
3237 g_value_init (&val, G_TYPE_STRING); \
3238 if (!g_value_transform (value, &val)) \
3239 g_assert_not_reached (); \
3240 /* NO_COPY_MADNESS!!! */ \
3241 return (char *) g_value_get_string (&val); \
3242 }
3243
3244 /* deserialize the given s into to as a gint64.
3245 * check if the result is actually storeable in the given size number of
3246 * bytes.
3247 */
3248 static gboolean
gst_value_deserialize_int_helper(gint64 * to,const gchar * s,gint64 min,gint64 max,gint size)3249 gst_value_deserialize_int_helper (gint64 * to, const gchar * s,
3250 gint64 min, gint64 max, gint size)
3251 {
3252 gboolean ret = FALSE;
3253 gchar *end;
3254 guint64 mask = ~0;
3255
3256 errno = 0;
3257 *to = g_ascii_strtoull (s, &end, 0);
3258 /* a range error is a definitive no-no */
3259 if (errno == ERANGE) {
3260 return FALSE;
3261 }
3262
3263 if (*end == 0) {
3264 ret = TRUE;
3265 } else {
3266 if (g_ascii_strcasecmp (s, "little_endian") == 0) {
3267 *to = G_LITTLE_ENDIAN;
3268 ret = TRUE;
3269 } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {
3270 *to = G_BIG_ENDIAN;
3271 ret = TRUE;
3272 } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {
3273 *to = G_BYTE_ORDER;
3274 ret = TRUE;
3275 } else if (g_ascii_strcasecmp (s, "min") == 0) {
3276 *to = min;
3277 ret = TRUE;
3278 } else if (g_ascii_strcasecmp (s, "max") == 0) {
3279 *to = max;
3280 ret = TRUE;
3281 }
3282 }
3283 if (ret) {
3284 /* by definition, a gint64 fits into a gint64; so ignore those */
3285 if (size != sizeof (mask)) {
3286 if (*to >= 0) {
3287 /* for positive numbers, we create a mask of 1's outside of the range
3288 * and 0's inside the range. An and will thus keep only 1 bits
3289 * outside of the range */
3290 mask <<= (size * 8);
3291 if ((mask & *to) != 0) {
3292 ret = FALSE;
3293 }
3294 } else {
3295 /* for negative numbers, we do a 2's complement version */
3296 mask <<= ((size * 8) - 1);
3297 if ((mask & *to) != mask) {
3298 ret = FALSE;
3299 }
3300 }
3301 }
3302 }
3303 return ret;
3304 }
3305
3306 #define CREATE_SERIALIZATION(_type,_macro) \
3307 CREATE_SERIALIZATION_START(_type,_macro) \
3308 \
3309 static gboolean \
3310 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s) \
3311 { \
3312 gint64 x; \
3313 \
3314 if (gst_value_deserialize_int_helper (&x, s, G_MIN ## _macro, \
3315 G_MAX ## _macro, sizeof (g ## _type))) { \
3316 g_value_set_ ## _type (dest, /*(g ## _type)*/ x); \
3317 return TRUE; \
3318 } else { \
3319 return FALSE; \
3320 } \
3321 }
3322
3323 #define CREATE_USERIALIZATION(_type,_macro) \
3324 CREATE_SERIALIZATION_START(_type,_macro) \
3325 \
3326 static gboolean \
3327 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s) \
3328 { \
3329 gint64 x; \
3330 gchar *end; \
3331 gboolean ret = FALSE; \
3332 \
3333 errno = 0; \
3334 x = g_ascii_strtoull (s, &end, 0); \
3335 /* a range error is a definitive no-no */ \
3336 if (errno == ERANGE) { \
3337 return FALSE; \
3338 } \
3339 /* the cast ensures the range check later on makes sense */ \
3340 x = (g ## _type) x; \
3341 if (*end == 0) { \
3342 ret = TRUE; \
3343 } else { \
3344 if (g_ascii_strcasecmp (s, "little_endian") == 0) { \
3345 x = G_LITTLE_ENDIAN; \
3346 ret = TRUE; \
3347 } else if (g_ascii_strcasecmp (s, "big_endian") == 0) { \
3348 x = G_BIG_ENDIAN; \
3349 ret = TRUE; \
3350 } else if (g_ascii_strcasecmp (s, "byte_order") == 0) { \
3351 x = G_BYTE_ORDER; \
3352 ret = TRUE; \
3353 } else if (g_ascii_strcasecmp (s, "min") == 0) { \
3354 x = 0; \
3355 ret = TRUE; \
3356 } else if (g_ascii_strcasecmp (s, "max") == 0) { \
3357 x = G_MAX ## _macro; \
3358 ret = TRUE; \
3359 } \
3360 } \
3361 if (ret) { \
3362 if (x > G_MAX ## _macro) { \
3363 ret = FALSE; \
3364 } else { \
3365 g_value_set_ ## _type (dest, x); \
3366 } \
3367 } \
3368 return ret; \
3369 }
3370
3371 CREATE_SERIALIZATION (int, INT);
3372 CREATE_SERIALIZATION (int64, INT64);
3373 CREATE_SERIALIZATION (long, LONG);
3374
3375 CREATE_USERIALIZATION (uint, UINT);
3376 CREATE_USERIALIZATION (uint64, UINT64);
3377 CREATE_USERIALIZATION (ulong, ULONG);
3378
3379 /* FIXME 2.0: remove this again, plugins shouldn't have uchar properties */
3380 #ifndef G_MAXUCHAR
3381 #define G_MAXUCHAR 255
3382 #endif
3383 CREATE_USERIALIZATION (uchar, UCHAR);
3384
3385 /**********
3386 * double *
3387 **********/
3388 static gint
gst_value_compare_double(const GValue * value1,const GValue * value2)3389 gst_value_compare_double (const GValue * value1, const GValue * value2)
3390 {
3391 if (value1->data[0].v_double > value2->data[0].v_double)
3392 return GST_VALUE_GREATER_THAN;
3393 if (value1->data[0].v_double < value2->data[0].v_double)
3394 return GST_VALUE_LESS_THAN;
3395 if (value1->data[0].v_double == value2->data[0].v_double)
3396 return GST_VALUE_EQUAL;
3397 return GST_VALUE_UNORDERED;
3398 }
3399
3400 static gchar *
gst_value_serialize_double(const GValue * value)3401 gst_value_serialize_double (const GValue * value)
3402 {
3403 gchar d[G_ASCII_DTOSTR_BUF_SIZE];
3404
3405 g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
3406 return g_strdup (d);
3407 }
3408
3409 static gboolean
gst_value_deserialize_double(GValue * dest,const gchar * s)3410 gst_value_deserialize_double (GValue * dest, const gchar * s)
3411 {
3412 gdouble x;
3413 gboolean ret = FALSE;
3414 gchar *end;
3415
3416 x = g_ascii_strtod (s, &end);
3417 if (*end == 0) {
3418 ret = TRUE;
3419 } else {
3420 if (g_ascii_strcasecmp (s, "min") == 0) {
3421 x = -G_MAXDOUBLE;
3422 ret = TRUE;
3423 } else if (g_ascii_strcasecmp (s, "max") == 0) {
3424 x = G_MAXDOUBLE;
3425 ret = TRUE;
3426 }
3427 }
3428 if (ret) {
3429 g_value_set_double (dest, x);
3430 }
3431 return ret;
3432 }
3433
3434 /*********
3435 * float *
3436 *********/
3437
3438 static gint
gst_value_compare_float(const GValue * value1,const GValue * value2)3439 gst_value_compare_float (const GValue * value1, const GValue * value2)
3440 {
3441 if (value1->data[0].v_float > value2->data[0].v_float)
3442 return GST_VALUE_GREATER_THAN;
3443 if (value1->data[0].v_float < value2->data[0].v_float)
3444 return GST_VALUE_LESS_THAN;
3445 if (value1->data[0].v_float == value2->data[0].v_float)
3446 return GST_VALUE_EQUAL;
3447 return GST_VALUE_UNORDERED;
3448 }
3449
3450 static gchar *
gst_value_serialize_float(const GValue * value)3451 gst_value_serialize_float (const GValue * value)
3452 {
3453 gchar d[G_ASCII_DTOSTR_BUF_SIZE];
3454
3455 g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_float);
3456 return g_strdup (d);
3457 }
3458
3459 static gboolean
gst_value_deserialize_float(GValue * dest,const gchar * s)3460 gst_value_deserialize_float (GValue * dest, const gchar * s)
3461 {
3462 gdouble x;
3463 gboolean ret = FALSE;
3464 gchar *end;
3465
3466 x = g_ascii_strtod (s, &end);
3467 if (*end == 0) {
3468 ret = TRUE;
3469 } else {
3470 if (g_ascii_strcasecmp (s, "min") == 0) {
3471 x = -G_MAXFLOAT;
3472 ret = TRUE;
3473 } else if (g_ascii_strcasecmp (s, "max") == 0) {
3474 x = G_MAXFLOAT;
3475 ret = TRUE;
3476 }
3477 }
3478 if (x > G_MAXFLOAT || x < -G_MAXFLOAT)
3479 ret = FALSE;
3480 if (ret) {
3481 g_value_set_float (dest, (float) x);
3482 }
3483 return ret;
3484 }
3485
3486 /**********
3487 * string *
3488 **********/
3489
3490 static gint
gst_value_compare_string(const GValue * value1,const GValue * value2)3491 gst_value_compare_string (const GValue * value1, const GValue * value2)
3492 {
3493 if (G_UNLIKELY (!value1->data[0].v_pointer || !value2->data[0].v_pointer)) {
3494 /* if only one is NULL, no match - otherwise both NULL == EQUAL */
3495 if (value1->data[0].v_pointer != value2->data[0].v_pointer)
3496 return GST_VALUE_UNORDERED;
3497 } else {
3498 gint x = strcmp (value1->data[0].v_pointer, value2->data[0].v_pointer);
3499
3500 if (x < 0)
3501 return GST_VALUE_LESS_THAN;
3502 if (x > 0)
3503 return GST_VALUE_GREATER_THAN;
3504 }
3505
3506 return GST_VALUE_EQUAL;
3507 }
3508
3509 static gint
gst_string_measure_wrapping(const gchar * s)3510 gst_string_measure_wrapping (const gchar * s)
3511 {
3512 gint len;
3513 gboolean wrap = FALSE;
3514
3515 if (G_UNLIKELY (s == NULL))
3516 return -1;
3517
3518 /* Special case: the actual string NULL needs wrapping */
3519 if (G_UNLIKELY (strcmp (s, "NULL") == 0))
3520 return 4;
3521
3522 len = 0;
3523 while (*s) {
3524 if (GST_ASCII_IS_STRING (*s)) {
3525 len++;
3526 } else if (*s < 0x20 || *s >= 0x7f) {
3527 wrap = TRUE;
3528 len += 4;
3529 } else {
3530 wrap = TRUE;
3531 len += 2;
3532 }
3533 s++;
3534 }
3535
3536 /* Wrap the string if we found something that needs
3537 * wrapping, or the empty string (len == 0) */
3538 return (wrap || len == 0) ? len : -1;
3539 }
3540
3541 static gchar *
gst_string_wrap_inner(const gchar * s,gint len)3542 gst_string_wrap_inner (const gchar * s, gint len)
3543 {
3544 gchar *d, *e;
3545
3546 e = d = g_malloc (len + 3);
3547
3548 *e++ = '\"';
3549 while (*s) {
3550 if (GST_ASCII_IS_STRING (*s)) {
3551 *e++ = *s++;
3552 } else if (*s < 0x20 || *s >= 0x7f) {
3553 *e++ = '\\';
3554 *e++ = '0' + ((*(guchar *) s) >> 6);
3555 *e++ = '0' + (((*s) >> 3) & 0x7);
3556 *e++ = '0' + ((*s++) & 0x7);
3557 } else {
3558 *e++ = '\\';
3559 *e++ = *s++;
3560 }
3561 }
3562 *e++ = '\"';
3563 *e = 0;
3564
3565 g_assert (e - d <= len + 3);
3566 return d;
3567 }
3568
3569 /* Do string wrapping/escaping */
3570 static gchar *
gst_string_wrap(const gchar * s)3571 gst_string_wrap (const gchar * s)
3572 {
3573 gint len = gst_string_measure_wrapping (s);
3574
3575 if (G_LIKELY (len < 0))
3576 return g_strdup (s);
3577
3578 return gst_string_wrap_inner (s, len);
3579 }
3580
3581 /* Same as above, but take ownership of the string */
3582 gchar *
priv_gst_string_take_and_wrap(gchar * s)3583 priv_gst_string_take_and_wrap (gchar * s)
3584 {
3585 gchar *out;
3586 gint len = gst_string_measure_wrapping (s);
3587
3588 if (G_LIKELY (len < 0))
3589 return s;
3590
3591 out = gst_string_wrap_inner (s, len);
3592 g_free (s);
3593
3594 return out;
3595 }
3596
3597 /*
3598 * This function takes a string delimited with double quotes (")
3599 * and unescapes any \xxx octal numbers.
3600 *
3601 * If sequences of \y are found where y is not in the range of
3602 * 0->3, y is copied unescaped.
3603 *
3604 * If \xyy is found where x is an octal number but y is not, an
3605 * error is encountered and %NULL is returned.
3606 *
3607 * the input string must be \0 terminated.
3608 */
3609 static gchar *
gst_string_unwrap(const gchar * s)3610 gst_string_unwrap (const gchar * s)
3611 {
3612 gchar *ret;
3613 gchar *read, *write;
3614
3615 /* NULL string returns NULL */
3616 if (s == NULL)
3617 return NULL;
3618
3619 /* strings not starting with " are invalid */
3620 if (*s != '"')
3621 return NULL;
3622
3623 /* make copy of original string to hold the result. This
3624 * string will always be smaller than the original */
3625 ret = g_strdup (s);
3626 read = ret;
3627 write = ret;
3628
3629 /* need to move to the next position as we parsed the " */
3630 read++;
3631
3632 while (*read) {
3633 if (GST_ASCII_IS_STRING (*read)) {
3634 /* normal chars are just copied */
3635 *write++ = *read++;
3636 } else if (*read == '"') {
3637 /* quote marks end of string */
3638 break;
3639 } else if (*read == '\\') {
3640 /* got an escape char, move to next position to read a tripplet
3641 * of octal numbers */
3642 read++;
3643 /* is the next char a possible first octal number? */
3644 if (*read >= '0' && *read <= '3') {
3645 /* parse other 2 numbers, if one of them is not in the range of
3646 * an octal number, we error. We also catch the case where a zero
3647 * byte is found here. */
3648 if (read[1] < '0' || read[1] > '7' || read[2] < '0' || read[2] > '7')
3649 goto beach;
3650
3651 /* now convert the octal number to a byte again. */
3652 *write++ = ((read[0] - '0') << 6) +
3653 ((read[1] - '0') << 3) + (read[2] - '0');
3654
3655 read += 3;
3656 } else {
3657 /* if we run into a \0 here, we definitely won't get a quote later */
3658 if (*read == 0)
3659 goto beach;
3660
3661 /* else copy \X sequence */
3662 *write++ = *read++;
3663 }
3664 } else {
3665 /* weird character, error */
3666 goto beach;
3667 }
3668 }
3669 /* if the string is not ending in " and zero terminated, we error */
3670 if (*read != '"' || read[1] != '\0')
3671 goto beach;
3672
3673 /* null terminate result string and return */
3674 *write = '\0';
3675 return ret;
3676
3677 beach:
3678 g_free (ret);
3679 return NULL;
3680 }
3681
3682 static gchar *
gst_value_serialize_string(const GValue * value)3683 gst_value_serialize_string (const GValue * value)
3684 {
3685 return gst_string_wrap (value->data[0].v_pointer);
3686 }
3687
3688 static gboolean
gst_value_deserialize_string(GValue * dest,const gchar * s)3689 gst_value_deserialize_string (GValue * dest, const gchar * s)
3690 {
3691 if (G_UNLIKELY (strcmp (s, "NULL") == 0)) {
3692 g_value_set_string (dest, NULL);
3693 return TRUE;
3694 } else if (G_LIKELY (*s != '"' || s[strlen (s) - 1] != '"')) {
3695 if (!g_utf8_validate (s, -1, NULL))
3696 return FALSE;
3697 g_value_set_string (dest, s);
3698 return TRUE;
3699 } else {
3700 /* strings delimited with double quotes should be unwrapped */
3701 gchar *str = gst_string_unwrap (s);
3702 if (G_UNLIKELY (!str))
3703 return FALSE;
3704 g_value_take_string (dest, str);
3705 }
3706
3707 return TRUE;
3708 }
3709
3710 /********
3711 * enum *
3712 ********/
3713
3714 static gint
gst_value_compare_enum(const GValue * value1,const GValue * value2)3715 gst_value_compare_enum (const GValue * value1, const GValue * value2)
3716 {
3717 GEnumValue *en1, *en2;
3718 GEnumClass *klass1 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value1));
3719 GEnumClass *klass2 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value2));
3720
3721 g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
3722 g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
3723 en1 = g_enum_get_value (klass1, g_value_get_enum (value1));
3724 en2 = g_enum_get_value (klass2, g_value_get_enum (value2));
3725 g_type_class_unref (klass1);
3726 g_type_class_unref (klass2);
3727 g_return_val_if_fail (en1, GST_VALUE_UNORDERED);
3728 g_return_val_if_fail (en2, GST_VALUE_UNORDERED);
3729 if (en1->value < en2->value)
3730 return GST_VALUE_LESS_THAN;
3731 if (en1->value > en2->value)
3732 return GST_VALUE_GREATER_THAN;
3733
3734 return GST_VALUE_EQUAL;
3735 }
3736
3737 static gchar *
gst_value_serialize_enum(const GValue * value)3738 gst_value_serialize_enum (const GValue * value)
3739 {
3740 GEnumValue *en;
3741 GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value));
3742
3743 g_return_val_if_fail (klass, NULL);
3744 en = g_enum_get_value (klass, g_value_get_enum (value));
3745 g_type_class_unref (klass);
3746
3747 /* might be one of the custom formats registered later */
3748 if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (value) == GST_TYPE_FORMAT)) {
3749 const GstFormatDefinition *format_def;
3750
3751 format_def = gst_format_get_details ((GstFormat) g_value_get_enum (value));
3752 g_return_val_if_fail (format_def != NULL, NULL);
3753 return g_strdup (format_def->description);
3754 }
3755
3756 g_return_val_if_fail (en, NULL);
3757 return g_strdup (en->value_name);
3758 }
3759
3760 static gint
gst_value_deserialize_enum_iter_cmp(const GValue * format_def_value,const gchar * s)3761 gst_value_deserialize_enum_iter_cmp (const GValue * format_def_value,
3762 const gchar * s)
3763 {
3764 const GstFormatDefinition *format_def =
3765 g_value_get_pointer (format_def_value);
3766
3767 if (g_ascii_strcasecmp (s, format_def->nick) == 0)
3768 return 0;
3769
3770 return g_ascii_strcasecmp (s, format_def->description);
3771 }
3772
3773 static gboolean
gst_value_deserialize_enum(GValue * dest,const gchar * s)3774 gst_value_deserialize_enum (GValue * dest, const gchar * s)
3775 {
3776 GEnumValue *en;
3777 gchar *endptr = NULL;
3778 GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (dest));
3779
3780 g_return_val_if_fail (klass, FALSE);
3781 if (!(en = g_enum_get_value_by_name (klass, s))) {
3782 if (!(en = g_enum_get_value_by_nick (klass, s))) {
3783 gint i = strtol (s, &endptr, 0);
3784
3785 if (endptr && *endptr == '\0') {
3786 en = g_enum_get_value (klass, i);
3787 }
3788 }
3789 }
3790 g_type_class_unref (klass);
3791
3792 /* might be one of the custom formats registered later */
3793 if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (dest) == GST_TYPE_FORMAT)) {
3794 GValue res = { 0, };
3795 const GstFormatDefinition *format_def;
3796 GstIterator *iter;
3797 gboolean found;
3798
3799 iter = gst_format_iterate_definitions ();
3800
3801 found = gst_iterator_find_custom (iter,
3802 (GCompareFunc) gst_value_deserialize_enum_iter_cmp, &res, (gpointer) s);
3803
3804 if (found) {
3805 format_def = g_value_get_pointer (&res);
3806 g_return_val_if_fail (format_def != NULL, FALSE);
3807 g_value_set_enum (dest, (gint) format_def->value);
3808 g_value_unset (&res);
3809 }
3810 gst_iterator_free (iter);
3811 return found;
3812 }
3813
3814 /* enum name/nick not found */
3815 if (en == NULL)
3816 return FALSE;
3817
3818 g_value_set_enum (dest, en->value);
3819 return TRUE;
3820 }
3821
3822 /********
3823 * flags *
3824 ********/
3825
3826 /* we just compare the value here */
3827 static gint
gst_value_compare_gflags(const GValue * value1,const GValue * value2)3828 gst_value_compare_gflags (const GValue * value1, const GValue * value2)
3829 {
3830 guint fl1, fl2;
3831 GFlagsClass *klass1 =
3832 (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value1));
3833 GFlagsClass *klass2 =
3834 (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value2));
3835
3836 g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
3837 g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
3838 fl1 = g_value_get_flags (value1);
3839 fl2 = g_value_get_flags (value2);
3840 g_type_class_unref (klass1);
3841 g_type_class_unref (klass2);
3842 if (fl1 < fl2)
3843 return GST_VALUE_LESS_THAN;
3844 if (fl1 > fl2)
3845 return GST_VALUE_GREATER_THAN;
3846
3847 return GST_VALUE_EQUAL;
3848 }
3849
3850 /* the different flags are serialized separated with a + */
3851 static gchar *
gst_value_serialize_gflags(const GValue * value)3852 gst_value_serialize_gflags (const GValue * value)
3853 {
3854 guint flags;
3855 GFlagsValue *fl;
3856 GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value));
3857 gchar *result, *tmp;
3858 gboolean first = TRUE;
3859
3860 g_return_val_if_fail (klass, NULL);
3861
3862 flags = g_value_get_flags (value);
3863
3864 /* if no flags are set, try to serialize to the _NONE string */
3865 if (!flags) {
3866 fl = g_flags_get_first_value (klass, flags);
3867 if (fl)
3868 return g_strdup (fl->value_name);
3869 else
3870 return g_strdup ("0");
3871 }
3872
3873 /* some flags are set, so serialize one by one */
3874 result = g_strdup ("");
3875 while (flags) {
3876 fl = g_flags_get_first_value (klass, flags);
3877 if (fl != NULL) {
3878 tmp = g_strconcat (result, (first ? "" : "+"), fl->value_name, NULL);
3879 g_free (result);
3880 result = tmp;
3881 first = FALSE;
3882
3883 /* clear flag */
3884 flags &= ~fl->value;
3885 }
3886 }
3887 g_type_class_unref (klass);
3888
3889 return result;
3890 }
3891
3892 static gboolean
gst_value_gflags_str_to_flags(GFlagsClass * klass,const gchar * s,guint * out_flags,guint * out_mask)3893 gst_value_gflags_str_to_flags (GFlagsClass * klass, const gchar * s,
3894 guint * out_flags, guint * out_mask)
3895 {
3896 GFlagsValue *fl;
3897 gchar delimiter;
3898 const gchar *pos = NULL;
3899 const gchar *next;
3900 gchar *cur_str, *endptr;
3901 guint flags = 0;
3902 guint mask = 0;
3903 guint val;
3904
3905 g_return_val_if_fail (klass, FALSE);
3906
3907 /* split into parts delimited with + or / and
3908 * compose the set of flags and mask. */
3909 pos = s;
3910
3911 if (*pos == '\0')
3912 goto done; /* Empty string, nothing to do */
3913
3914 /* As a special case if the first char isn't a delimiter, assume
3915 * it's a '+' - for GFlags strings, which don't start with a
3916 * delimiter, while GFlagSet always will */
3917 if (*pos == '/' || *pos == '+') {
3918 delimiter = *pos;
3919 pos++;
3920 } else {
3921 delimiter = '+';
3922 }
3923
3924 do {
3925 /* Find the next delimiter */
3926 next = pos;
3927 while (*next != '\0' && *next != '+' && *next != '/')
3928 next++;
3929 cur_str = g_strndup (pos, next - pos);
3930
3931 if ((fl = g_flags_get_value_by_name (klass, cur_str)))
3932 val = fl->value;
3933 else if ((fl = g_flags_get_value_by_nick (klass, cur_str)))
3934 val = fl->value;
3935 else {
3936 val = strtoul (cur_str, &endptr, 0);
3937 /* direct numeric value */
3938 if (endptr == NULL || *endptr != '\0') {
3939 g_free (cur_str);
3940 return FALSE; /* Invalid numeric or string we can't convert */
3941 }
3942 }
3943 g_free (cur_str);
3944
3945 if (val) {
3946 mask |= val;
3947 if (delimiter == '+')
3948 flags |= val;
3949 }
3950
3951 /* Advance to the next delimiter */
3952 pos = next;
3953 delimiter = *pos;
3954 pos++;
3955 } while (delimiter != '\0');
3956
3957 done:
3958 if (out_flags)
3959 *out_flags = flags;
3960 if (out_mask)
3961 *out_mask = mask;
3962
3963 return TRUE;
3964 }
3965
3966
3967 static gboolean
gst_value_deserialize_gflags(GValue * dest,const gchar * s)3968 gst_value_deserialize_gflags (GValue * dest, const gchar * s)
3969 {
3970 GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (dest));
3971 gboolean res = FALSE;
3972 guint flags = 0;
3973
3974 if (gst_value_gflags_str_to_flags (klass, s, &flags, NULL)) {
3975 g_value_set_flags (dest, flags);
3976 res = TRUE;
3977 }
3978
3979 g_type_class_unref (klass);
3980
3981 return res;
3982 }
3983
3984 /*********
3985 * gtype *
3986 *********/
3987
3988 static gint
gst_value_compare_gtype(const GValue * value1,const GValue * value2)3989 gst_value_compare_gtype (const GValue * value1, const GValue * value2)
3990 {
3991 if (value1->data[0].v_pointer == value2->data[0].v_pointer)
3992 return GST_VALUE_EQUAL;
3993 return GST_VALUE_UNORDERED;
3994 }
3995
3996 static gchar *
gst_value_serialize_gtype(const GValue * value)3997 gst_value_serialize_gtype (const GValue * value)
3998 {
3999 return g_strdup (g_type_name (g_value_get_gtype (value)));
4000 }
4001
4002 static gboolean
gst_value_deserialize_gtype(GValue * dest,const gchar * s)4003 gst_value_deserialize_gtype (GValue * dest, const gchar * s)
4004 {
4005 GType t = g_type_from_name (s);
4006 gboolean ret = TRUE;
4007
4008 if (t == G_TYPE_INVALID)
4009 ret = FALSE;
4010 if (ret) {
4011 g_value_set_gtype (dest, t);
4012 }
4013 return ret;
4014 }
4015
4016 /****************
4017 * subset *
4018 ****************/
4019
4020 static gboolean
gst_value_is_subset_int_range_int_range(const GValue * value1,const GValue * value2)4021 gst_value_is_subset_int_range_int_range (const GValue * value1,
4022 const GValue * value2)
4023 {
4024 gint gcd;
4025
4026 g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value1), FALSE);
4027 g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value2), FALSE);
4028
4029 if (INT_RANGE_MIN (value1) * INT_RANGE_STEP (value1) <
4030 INT_RANGE_MIN (value2) * INT_RANGE_STEP (value2))
4031 return FALSE;
4032 if (INT_RANGE_MAX (value1) * INT_RANGE_STEP (value1) >
4033 INT_RANGE_MAX (value2) * INT_RANGE_STEP (value2))
4034 return FALSE;
4035
4036 if (INT_RANGE_MIN (value2) == INT_RANGE_MAX (value2)) {
4037 if ((INT_RANGE_MIN (value2) * INT_RANGE_STEP (value2)) %
4038 INT_RANGE_STEP (value1))
4039 return FALSE;
4040 return TRUE;
4041 }
4042
4043 gcd =
4044 gst_util_greatest_common_divisor (INT_RANGE_STEP (value1),
4045 INT_RANGE_STEP (value2));
4046 if (gcd != MIN (INT_RANGE_STEP (value1), INT_RANGE_STEP (value2)))
4047 return FALSE;
4048
4049 return TRUE;
4050 }
4051
4052 static gboolean
gst_value_is_subset_int64_range_int64_range(const GValue * value1,const GValue * value2)4053 gst_value_is_subset_int64_range_int64_range (const GValue * value1,
4054 const GValue * value2)
4055 {
4056 gint64 gcd;
4057
4058 g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value1), FALSE);
4059 g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value2), FALSE);
4060
4061 if (INT64_RANGE_MIN (value1) < INT64_RANGE_MIN (value2))
4062 return FALSE;
4063 if (INT64_RANGE_MAX (value1) > INT64_RANGE_MAX (value2))
4064 return FALSE;
4065
4066 if (INT64_RANGE_MIN (value2) == INT64_RANGE_MAX (value2)) {
4067 if ((INT64_RANGE_MIN (value2) * INT64_RANGE_STEP (value2)) %
4068 INT64_RANGE_STEP (value1))
4069 return FALSE;
4070 return TRUE;
4071 }
4072
4073 gcd =
4074 gst_util_greatest_common_divisor_int64 (INT64_RANGE_STEP (value1),
4075 INT64_RANGE_STEP (value2));
4076 if (gcd != MIN (INT64_RANGE_STEP (value1), INT64_RANGE_STEP (value2)))
4077 return FALSE;
4078
4079 return TRUE;
4080 }
4081
4082 /* A flag set is a subset of another if the superset allows the
4083 * flags of the subset */
4084 static gboolean
gst_value_is_subset_flagset_flagset(const GValue * value1,const GValue * value2)4085 gst_value_is_subset_flagset_flagset (const GValue * value1,
4086 const GValue * value2)
4087 {
4088 guint f1, f2;
4089 guint m1, m2;
4090
4091 g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (value1), FALSE);
4092 g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (value2), FALSE);
4093
4094 f1 = value1->data[0].v_uint;
4095 f2 = value2->data[0].v_uint;
4096
4097 m1 = value1->data[1].v_uint;
4098 m2 = value2->data[1].v_uint;
4099
4100 /* Not a subset if masked bits of superset disagree */
4101 if ((f1 & m1) != (f2 & (m1 & m2)))
4102 return FALSE;
4103
4104 return TRUE;
4105 }
4106
4107 static gboolean
gst_value_is_subset_structure_structure(const GValue * value1,const GValue * value2)4108 gst_value_is_subset_structure_structure (const GValue * value1,
4109 const GValue * value2)
4110 {
4111 const GstStructure *s1, *s2;
4112
4113 g_return_val_if_fail (GST_VALUE_HOLDS_STRUCTURE (value1), FALSE);
4114 g_return_val_if_fail (GST_VALUE_HOLDS_STRUCTURE (value2), FALSE);
4115
4116 s1 = gst_value_get_structure (value1);
4117 s2 = gst_value_get_structure (value2);
4118
4119 return gst_structure_is_subset (s1, s2);
4120 }
4121
4122 /**
4123 * gst_value_is_subset:
4124 * @value1: a #GValue
4125 * @value2: a #GValue
4126 *
4127 * Check that @value1 is a subset of @value2.
4128 *
4129 * Return: %TRUE is @value1 is a subset of @value2
4130 */
4131 gboolean
gst_value_is_subset(const GValue * value1,const GValue * value2)4132 gst_value_is_subset (const GValue * value1, const GValue * value2)
4133 {
4134 /* special case for int/int64 ranges, since we cannot compute
4135 the difference for those when they have different steps,
4136 and it's actually a lot simpler to compute whether a range
4137 is a subset of another. */
4138 if (GST_VALUE_HOLDS_INT_RANGE (value1) && GST_VALUE_HOLDS_INT_RANGE (value2)) {
4139 return gst_value_is_subset_int_range_int_range (value1, value2);
4140 } else if (GST_VALUE_HOLDS_INT64_RANGE (value1)
4141 && GST_VALUE_HOLDS_INT64_RANGE (value2)) {
4142 return gst_value_is_subset_int64_range_int64_range (value1, value2);
4143 } else if (GST_VALUE_HOLDS_FLAG_SET (value1) &&
4144 GST_VALUE_HOLDS_FLAG_SET (value2)) {
4145 return gst_value_is_subset_flagset_flagset (value1, value2);
4146 } else if (GST_VALUE_HOLDS_STRUCTURE (value1)
4147 && GST_VALUE_HOLDS_STRUCTURE (value2)) {
4148 return gst_value_is_subset_structure_structure (value1, value2);
4149 }
4150
4151 /*
4152 * 1 - [1,2] = empty
4153 * -> !subset
4154 *
4155 * [1,2] - 1 = 2
4156 * -> 1 - [1,2] = empty
4157 * -> subset
4158 *
4159 * [1,3] - [1,2] = 3
4160 * -> [1,2] - [1,3] = empty
4161 * -> subset
4162 *
4163 * {1,2} - {1,3} = 2
4164 * -> {1,3} - {1,2} = 3
4165 * -> !subset
4166 *
4167 * First caps subtraction needs to return a non-empty set, second
4168 * subtractions needs to give en empty set.
4169 * Both substractions are switched below, as it's faster that way.
4170 */
4171 if (!gst_value_subtract (NULL, value1, value2)) {
4172 if (gst_value_subtract (NULL, value2, value1)) {
4173 return TRUE;
4174 }
4175 }
4176 return FALSE;
4177 }
4178
4179 /*********
4180 * union *
4181 *********/
4182
4183 static gboolean
gst_value_union_int_int_range(GValue * dest,const GValue * src1,const GValue * src2)4184 gst_value_union_int_int_range (GValue * dest, const GValue * src1,
4185 const GValue * src2)
4186 {
4187 gint v = src1->data[0].v_int;
4188
4189 /* check if it's already in the range */
4190 if (INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2) <= v &&
4191 INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2) >= v &&
4192 v % INT_RANGE_STEP (src2) == 0) {
4193 if (dest)
4194 gst_value_init_and_copy (dest, src2);
4195 return TRUE;
4196 }
4197
4198 /* check if it extends the range */
4199 if (v == (INT_RANGE_MIN (src2) - 1) * INT_RANGE_STEP (src2)) {
4200 if (dest) {
4201 guint64 new_min = INT_RANGE_MIN (src2) - 1;
4202 guint64 new_max = INT_RANGE_MAX (src2);
4203
4204 gst_value_init_and_copy (dest, src2);
4205 dest->data[0].v_uint64 = (new_min << 32) | (new_max);
4206 }
4207 return TRUE;
4208 }
4209 if (v == (INT_RANGE_MAX (src2) + 1) * INT_RANGE_STEP (src2)) {
4210 if (dest) {
4211 guint64 new_min = INT_RANGE_MIN (src2);
4212 guint64 new_max = INT_RANGE_MAX (src2) + 1;
4213
4214 gst_value_init_and_copy (dest, src2);
4215 dest->data[0].v_uint64 = (new_min << 32) | (new_max);
4216 }
4217 return TRUE;
4218 }
4219
4220 return FALSE;
4221 }
4222
4223 static gboolean
gst_value_union_int_range_int_range(GValue * dest,const GValue * src1,const GValue * src2)4224 gst_value_union_int_range_int_range (GValue * dest, const GValue * src1,
4225 const GValue * src2)
4226 {
4227 /* We can union in several special cases:
4228 1 - one is a subset of another
4229 2 - same step and not disjoint
4230 3 - different step, at least one with one value which matches a 'next' or 'previous'
4231 - anything else ?
4232 */
4233
4234 /* 1 - subset */
4235 if (gst_value_is_subset_int_range_int_range (src1, src2)) {
4236 if (dest)
4237 gst_value_init_and_copy (dest, src2);
4238 return TRUE;
4239 }
4240 if (gst_value_is_subset_int_range_int_range (src2, src1)) {
4241 if (dest)
4242 gst_value_init_and_copy (dest, src1);
4243 return TRUE;
4244 }
4245
4246 /* 2 - same step and not disjoint */
4247 if (INT_RANGE_STEP (src1) == INT_RANGE_STEP (src2)) {
4248 if ((INT_RANGE_MIN (src1) <= INT_RANGE_MAX (src2) + 1 &&
4249 INT_RANGE_MAX (src1) >= INT_RANGE_MIN (src2) - 1) ||
4250 (INT_RANGE_MIN (src2) <= INT_RANGE_MAX (src1) + 1 &&
4251 INT_RANGE_MAX (src2) >= INT_RANGE_MIN (src1) - 1)) {
4252 if (dest) {
4253 gint step = INT_RANGE_STEP (src1);
4254 gint min = step * MIN (INT_RANGE_MIN (src1), INT_RANGE_MIN (src2));
4255 gint max = step * MAX (INT_RANGE_MAX (src1), INT_RANGE_MAX (src2));
4256 g_value_init (dest, GST_TYPE_INT_RANGE);
4257 gst_value_set_int_range_step (dest, min, max, step);
4258 }
4259 return TRUE;
4260 }
4261 }
4262
4263 /* 3 - single value matches next or previous */
4264 if (INT_RANGE_STEP (src1) != INT_RANGE_STEP (src2)) {
4265 gint n1 = INT_RANGE_MAX (src1) - INT_RANGE_MIN (src1) + 1;
4266 gint n2 = INT_RANGE_MAX (src2) - INT_RANGE_MIN (src2) + 1;
4267 if (n1 == 1 || n2 == 1) {
4268 const GValue *range_value = NULL;
4269 gint scalar = 0;
4270 if (n1 == 1) {
4271 range_value = src2;
4272 scalar = INT_RANGE_MIN (src1) * INT_RANGE_STEP (src1);
4273 } else if (n2 == 1) {
4274 range_value = src1;
4275 scalar = INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2);
4276 }
4277
4278 if (scalar ==
4279 (INT_RANGE_MIN (range_value) - 1) * INT_RANGE_STEP (range_value)) {
4280 if (dest) {
4281 guint64 new_min = (guint)
4282 ((INT_RANGE_MIN (range_value) -
4283 1) * INT_RANGE_STEP (range_value));
4284 guint64 new_max = (guint)
4285 (INT_RANGE_MAX (range_value) * INT_RANGE_STEP (range_value));
4286
4287 gst_value_init_and_copy (dest, range_value);
4288 dest->data[0].v_uint64 = (new_min << 32) | (new_max);
4289 }
4290 return TRUE;
4291 } else if (scalar ==
4292 (INT_RANGE_MAX (range_value) + 1) * INT_RANGE_STEP (range_value)) {
4293 if (dest) {
4294 guint64 new_min = (guint)
4295 (INT_RANGE_MIN (range_value) * INT_RANGE_STEP (range_value));
4296 guint64 new_max = (guint)
4297 ((INT_RANGE_MAX (range_value) +
4298 1) * INT_RANGE_STEP (range_value));
4299 gst_value_init_and_copy (dest, range_value);
4300 dest->data[0].v_uint64 = (new_min << 32) | (new_max);
4301 }
4302 return TRUE;
4303 }
4304 }
4305 }
4306
4307 /* If we get there, we did not find a way to make a union that can be
4308 represented with our simplistic model. */
4309 return FALSE;
4310 }
4311
4312 static gboolean
gst_value_union_flagset_flagset(GValue * dest,const GValue * src1,const GValue * src2)4313 gst_value_union_flagset_flagset (GValue * dest, const GValue * src1,
4314 const GValue * src2)
4315 {
4316 /* We can union 2 flag sets where they do not disagree on
4317 * required (masked) flag bits */
4318 guint64 f1, f2;
4319 guint64 m1, m2;
4320
4321 g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (src1), FALSE);
4322 g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (src2), FALSE);
4323
4324 f1 = src1->data[0].v_uint;
4325 f2 = src2->data[0].v_uint;
4326
4327 m1 = src1->data[1].v_uint;
4328 m2 = src2->data[1].v_uint;
4329
4330 /* Can't union if masked bits disagree */
4331 if ((f1 & (m1 & m2)) != (f2 & (m1 & m2)))
4332 return FALSE;
4333
4334 if (dest) {
4335 g_value_init (dest, GST_TYPE_FLAG_SET);
4336 /* Copy masked bits from src2 to src1 */
4337 f1 &= ~m2;
4338 f1 |= (f2 & m2);
4339 m1 |= m2;
4340 gst_value_set_flagset (dest, f1, m1);
4341 }
4342
4343 return TRUE;
4344 }
4345
4346 /* iterating over the result taking the union with the other structure's value */
4347 static gboolean
structure_field_union_into(GQuark field_id,GValue * val,gpointer user_data)4348 structure_field_union_into (GQuark field_id, GValue * val, gpointer user_data)
4349 {
4350 GstStructure *other = user_data;
4351 const GValue *other_value;
4352 GValue res_value = G_VALUE_INIT;
4353
4354 other_value = gst_structure_id_get_value (other, field_id);
4355 /* no value in the other struct, just keep this value */
4356 if (!other_value)
4357 return TRUE;
4358
4359 if (!gst_value_union (&res_value, val, other_value))
4360 return FALSE;
4361
4362 g_value_unset (val);
4363 gst_value_move (val, &res_value);
4364 return TRUE;
4365 }
4366
4367 /* iterating over the other source structure adding missing values */
4368 static gboolean
structure_field_union_from(GQuark field_id,const GValue * other_val,gpointer user_data)4369 structure_field_union_from (GQuark field_id, const GValue * other_val,
4370 gpointer user_data)
4371 {
4372 GstStructure *result = user_data;
4373 const GValue *result_value;
4374
4375 result_value = gst_structure_id_get_value (result, field_id);
4376 if (!result_value)
4377 gst_structure_id_set_value (result, field_id, other_val);
4378
4379 return TRUE;
4380 }
4381
4382 static gboolean
gst_value_union_structure_structure(GValue * dest,const GValue * src1,const GValue * src2)4383 gst_value_union_structure_structure (GValue * dest, const GValue * src1,
4384 const GValue * src2)
4385 {
4386 const GstStructure *s1, *s2;
4387 GstStructure *result;
4388 gboolean ret;
4389
4390 g_return_val_if_fail (GST_VALUE_HOLDS_STRUCTURE (src1), FALSE);
4391 g_return_val_if_fail (GST_VALUE_HOLDS_STRUCTURE (src2), FALSE);
4392
4393 s1 = gst_value_get_structure (src1);
4394 s2 = gst_value_get_structure (src2);
4395
4396 /* Can't join two structures with different names into a single structure */
4397 if (!gst_structure_has_name (s1, gst_structure_get_name (s2))) {
4398 gst_value_list_concat (dest, src1, src2);
4399 return TRUE;
4400 }
4401
4402 result = gst_structure_copy (s1);
4403 ret =
4404 gst_structure_map_in_place (result, structure_field_union_into,
4405 (gpointer) s2);
4406 if (!ret)
4407 goto out;
4408 ret =
4409 gst_structure_foreach (s2, structure_field_union_from, (gpointer) result);
4410
4411 if (ret) {
4412 g_value_init (dest, GST_TYPE_STRUCTURE);
4413 gst_value_set_structure (dest, result);
4414 }
4415
4416 out:
4417 gst_structure_free (result);
4418 return ret;
4419 }
4420
4421 /****************
4422 * intersection *
4423 ****************/
4424
4425 static gboolean
gst_value_intersect_int_int_range(GValue * dest,const GValue * src1,const GValue * src2)4426 gst_value_intersect_int_int_range (GValue * dest, const GValue * src1,
4427 const GValue * src2)
4428 {
4429 if (INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2) <= src1->data[0].v_int &&
4430 INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2) >= src1->data[0].v_int &&
4431 src1->data[0].v_int % INT_RANGE_STEP (src2) == 0) {
4432 if (dest)
4433 gst_value_init_and_copy (dest, src1);
4434 return TRUE;
4435 }
4436
4437 return FALSE;
4438 }
4439
4440 static gboolean
gst_value_intersect_int_range_int_range(GValue * dest,const GValue * src1,const GValue * src2)4441 gst_value_intersect_int_range_int_range (GValue * dest, const GValue * src1,
4442 const GValue * src2)
4443 {
4444 gint min;
4445 gint max;
4446 gint step;
4447
4448 step =
4449 INT_RANGE_STEP (src1) /
4450 gst_util_greatest_common_divisor (INT_RANGE_STEP (src1),
4451 INT_RANGE_STEP (src2));
4452 if (G_MAXINT32 / INT_RANGE_STEP (src2) < step)
4453 return FALSE;
4454 step *= INT_RANGE_STEP (src2);
4455
4456 min =
4457 MAX (INT_RANGE_MIN (src1) * INT_RANGE_STEP (src1),
4458 INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2));
4459 min = (min + step - 1) / step * step;
4460 max =
4461 MIN (INT_RANGE_MAX (src1) * INT_RANGE_STEP (src1),
4462 INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2));
4463 max = max / step * step;
4464
4465 if (min < max) {
4466 if (dest) {
4467 g_value_init (dest, GST_TYPE_INT_RANGE);
4468 gst_value_set_int_range_step (dest, min, max, step);
4469 }
4470 return TRUE;
4471 }
4472 if (min == max) {
4473 if (dest) {
4474 g_value_init (dest, G_TYPE_INT);
4475 g_value_set_int (dest, min);
4476 }
4477 return TRUE;
4478 }
4479
4480 return FALSE;
4481 }
4482
4483 #define INT64_RANGE_MIN_VAL(v) (INT64_RANGE_MIN (v) * INT64_RANGE_STEP (v))
4484 #define INT64_RANGE_MAX_VAL(v) (INT64_RANGE_MAX (v) * INT64_RANGE_STEP (v))
4485
4486 static gboolean
gst_value_intersect_int64_int64_range(GValue * dest,const GValue * src1,const GValue * src2)4487 gst_value_intersect_int64_int64_range (GValue * dest, const GValue * src1,
4488 const GValue * src2)
4489 {
4490 if (INT64_RANGE_MIN_VAL (src2) <= src1->data[0].v_int64 &&
4491 INT64_RANGE_MAX_VAL (src2) >= src1->data[0].v_int64 &&
4492 src1->data[0].v_int64 % INT64_RANGE_STEP (src2) == 0) {
4493 if (dest)
4494 gst_value_init_and_copy (dest, src1);
4495 return TRUE;
4496 }
4497
4498 return FALSE;
4499 }
4500
4501 static gboolean
gst_value_intersect_int64_range_int64_range(GValue * dest,const GValue * src1,const GValue * src2)4502 gst_value_intersect_int64_range_int64_range (GValue * dest, const GValue * src1,
4503 const GValue * src2)
4504 {
4505 gint64 min;
4506 gint64 max;
4507 gint64 step;
4508
4509 step =
4510 INT64_RANGE_STEP (src1) /
4511 gst_util_greatest_common_divisor_int64 (INT64_RANGE_STEP (src1),
4512 INT64_RANGE_STEP (src2));
4513 if (G_MAXINT64 / INT64_RANGE_STEP (src2) < step)
4514 return FALSE;
4515 step *= INT64_RANGE_STEP (src2);
4516
4517 min =
4518 MAX (INT64_RANGE_MIN (src1) * INT64_RANGE_STEP (src1),
4519 INT64_RANGE_MIN (src2) * INT64_RANGE_STEP (src2));
4520 min = (min + step - 1) / step * step;
4521 max =
4522 MIN (INT64_RANGE_MAX (src1) * INT64_RANGE_STEP (src1),
4523 INT64_RANGE_MAX (src2) * INT64_RANGE_STEP (src2));
4524 max = max / step * step;
4525
4526 if (min < max) {
4527 if (dest) {
4528 g_value_init (dest, GST_TYPE_INT64_RANGE);
4529 gst_value_set_int64_range_step (dest, min, max, step);
4530 }
4531 return TRUE;
4532 }
4533 if (min == max) {
4534 if (dest) {
4535 g_value_init (dest, G_TYPE_INT64);
4536 g_value_set_int64 (dest, min);
4537 }
4538 return TRUE;
4539 }
4540
4541 return FALSE;
4542 }
4543
4544 static gboolean
gst_value_intersect_double_double_range(GValue * dest,const GValue * src1,const GValue * src2)4545 gst_value_intersect_double_double_range (GValue * dest, const GValue * src1,
4546 const GValue * src2)
4547 {
4548 if (src2->data[0].v_double <= src1->data[0].v_double &&
4549 src2->data[1].v_double >= src1->data[0].v_double) {
4550 if (dest)
4551 gst_value_init_and_copy (dest, src1);
4552 return TRUE;
4553 }
4554
4555 return FALSE;
4556 }
4557
4558 static gboolean
gst_value_intersect_double_range_double_range(GValue * dest,const GValue * src1,const GValue * src2)4559 gst_value_intersect_double_range_double_range (GValue * dest,
4560 const GValue * src1, const GValue * src2)
4561 {
4562 gdouble min;
4563 gdouble max;
4564
4565 min = MAX (src1->data[0].v_double, src2->data[0].v_double);
4566 max = MIN (src1->data[1].v_double, src2->data[1].v_double);
4567
4568 if (min < max) {
4569 if (dest) {
4570 g_value_init (dest, GST_TYPE_DOUBLE_RANGE);
4571 gst_value_set_double_range (dest, min, max);
4572 }
4573 return TRUE;
4574 }
4575 if (min == max) {
4576 if (dest) {
4577 g_value_init (dest, G_TYPE_DOUBLE);
4578 g_value_set_int (dest, (int) min);
4579 }
4580 return TRUE;
4581 }
4582
4583 return FALSE;
4584 }
4585
4586 static gboolean
gst_value_intersect_list(GValue * dest,const GValue * value1,const GValue * value2)4587 gst_value_intersect_list (GValue * dest, const GValue * value1,
4588 const GValue * value2)
4589 {
4590 guint i, size;
4591 GValue intersection = { 0, };
4592 gboolean ret = FALSE;
4593
4594 size = VALUE_LIST_SIZE (value1);
4595 for (i = 0; i < size; i++) {
4596 const GValue *cur = VALUE_LIST_GET_VALUE (value1, i);
4597
4598 /* quicker version when we don't need the resulting set */
4599 if (!dest) {
4600 if (gst_value_intersect (NULL, cur, value2)) {
4601 ret = TRUE;
4602 break;
4603 }
4604 continue;
4605 }
4606
4607 if (gst_value_intersect (&intersection, cur, value2)) {
4608 /* append value */
4609 if (!ret) {
4610 gst_value_move (dest, &intersection);
4611 ret = TRUE;
4612 } else if (GST_VALUE_HOLDS_LIST (dest)) {
4613 _gst_value_list_append_and_take_value (dest, &intersection);
4614 } else {
4615 GValue temp;
4616
4617 gst_value_move (&temp, dest);
4618 gst_value_list_merge (dest, &temp, &intersection);
4619 g_value_unset (&temp);
4620 g_value_unset (&intersection);
4621 }
4622 }
4623 }
4624
4625 return ret;
4626 }
4627
4628 static gboolean
gst_value_intersect_array(GValue * dest,const GValue * src1,const GValue * src2)4629 gst_value_intersect_array (GValue * dest, const GValue * src1,
4630 const GValue * src2)
4631 {
4632 guint size;
4633 guint n;
4634 GValue val = { 0 };
4635
4636 /* only works on similar-sized arrays */
4637 size = gst_value_array_get_size (src1);
4638 if (size != gst_value_array_get_size (src2))
4639 return FALSE;
4640
4641 /* quicker value when we don't need the resulting set */
4642 if (!dest) {
4643 for (n = 0; n < size; n++) {
4644 if (!gst_value_intersect (NULL, gst_value_array_get_value (src1, n),
4645 gst_value_array_get_value (src2, n))) {
4646 return FALSE;
4647 }
4648 }
4649 return TRUE;
4650 }
4651
4652 g_value_init (dest, GST_TYPE_ARRAY);
4653
4654 for (n = 0; n < size; n++) {
4655 if (!gst_value_intersect (&val, gst_value_array_get_value (src1, n),
4656 gst_value_array_get_value (src2, n))) {
4657 g_value_unset (dest);
4658 return FALSE;
4659 }
4660 _gst_value_array_append_and_take_value (dest, &val);
4661 }
4662
4663 return TRUE;
4664 }
4665
4666 static gboolean
gst_value_intersect_fraction_fraction_range(GValue * dest,const GValue * src1,const GValue * src2)4667 gst_value_intersect_fraction_fraction_range (GValue * dest, const GValue * src1,
4668 const GValue * src2)
4669 {
4670 gint res1, res2;
4671 GValue *vals;
4672 GstValueCompareFunc compare;
4673
4674 vals = src2->data[0].v_pointer;
4675
4676 if (vals == NULL)
4677 return FALSE;
4678
4679 if ((compare = gst_value_get_compare_func (src1))) {
4680 res1 = gst_value_compare_with_func (&vals[0], src1, compare);
4681 res2 = gst_value_compare_with_func (&vals[1], src1, compare);
4682
4683 if ((res1 == GST_VALUE_EQUAL || res1 == GST_VALUE_LESS_THAN) &&
4684 (res2 == GST_VALUE_EQUAL || res2 == GST_VALUE_GREATER_THAN)) {
4685 if (dest)
4686 gst_value_init_and_copy (dest, src1);
4687 return TRUE;
4688 }
4689 }
4690
4691 return FALSE;
4692 }
4693
4694 static gboolean
gst_value_intersect_fraction_range_fraction_range(GValue * dest,const GValue * src1,const GValue * src2)4695 gst_value_intersect_fraction_range_fraction_range (GValue * dest,
4696 const GValue * src1, const GValue * src2)
4697 {
4698 GValue *min;
4699 GValue *max;
4700 gint res;
4701 GValue *vals1, *vals2;
4702 GstValueCompareFunc compare;
4703
4704 vals1 = src1->data[0].v_pointer;
4705 vals2 = src2->data[0].v_pointer;
4706 g_return_val_if_fail (vals1 != NULL && vals2 != NULL, FALSE);
4707
4708 if ((compare = gst_value_get_compare_func (&vals1[0]))) {
4709 /* min = MAX (src1.start, src2.start) */
4710 res = gst_value_compare_with_func (&vals1[0], &vals2[0], compare);
4711 g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
4712 if (res == GST_VALUE_LESS_THAN)
4713 min = &vals2[0]; /* Take the max of the 2 */
4714 else
4715 min = &vals1[0];
4716
4717 /* max = MIN (src1.end, src2.end) */
4718 res = gst_value_compare_with_func (&vals1[1], &vals2[1], compare);
4719 g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
4720 if (res == GST_VALUE_GREATER_THAN)
4721 max = &vals2[1]; /* Take the min of the 2 */
4722 else
4723 max = &vals1[1];
4724
4725 res = gst_value_compare_with_func (min, max, compare);
4726 g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
4727 if (res == GST_VALUE_LESS_THAN) {
4728 if (dest) {
4729 g_value_init (dest, GST_TYPE_FRACTION_RANGE);
4730 vals1 = dest->data[0].v_pointer;
4731 g_value_copy (min, &vals1[0]);
4732 g_value_copy (max, &vals1[1]);
4733 }
4734 return TRUE;
4735 }
4736 if (res == GST_VALUE_EQUAL) {
4737 if (dest)
4738 gst_value_init_and_copy (dest, min);
4739 return TRUE;
4740 }
4741 }
4742
4743 return FALSE;
4744 }
4745
4746 /* Two flagsets intersect if the masked bits in both
4747 * flagsets are exactly equal */
4748 static gboolean
gst_value_intersect_flagset_flagset(GValue * dest,const GValue * src1,const GValue * src2)4749 gst_value_intersect_flagset_flagset (GValue * dest,
4750 const GValue * src1, const GValue * src2)
4751 {
4752 guint f1, f2;
4753 guint m1, m2;
4754 GType type1, type2, flagset_type;
4755
4756 g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (src1), FALSE);
4757 g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (src2), FALSE);
4758
4759 f1 = src1->data[0].v_uint;
4760 f2 = src2->data[0].v_uint;
4761
4762 m1 = src1->data[1].v_uint;
4763 m2 = src2->data[1].v_uint;
4764
4765 /* Don't intersect if masked bits disagree */
4766 if ((f1 & (m1 & m2)) != (f2 & (m1 & m2)))
4767 return FALSE;
4768
4769 /* Allow intersection with the generic FlagSet type, on one
4770 * side, but not 2 different subtypes - that makes no sense */
4771 type1 = G_VALUE_TYPE (src1);
4772 type2 = G_VALUE_TYPE (src2);
4773 flagset_type = GST_TYPE_FLAG_SET;
4774
4775 if (type1 != type2 && type1 != flagset_type && type2 != flagset_type)
4776 return FALSE;
4777
4778 if (dest) {
4779 GType dest_type;
4780
4781 /* Prefer an output type that matches a sub-type,
4782 * rather than the generic type */
4783 if (type1 != flagset_type)
4784 dest_type = type1;
4785 else
4786 dest_type = type2;
4787
4788 g_value_init (dest, dest_type);
4789
4790 /* The compatible set is all the bits from src1 that it
4791 * cares about and all the bits from src2 that it cares
4792 * about. */
4793 dest->data[0].v_uint = (f1 & m1) | (f2 & m2);
4794 dest->data[1].v_uint = m1 | m2;
4795 }
4796
4797 return TRUE;
4798 }
4799
4800 static gboolean
gst_value_intersect_structure_structure(GValue * dest,const GValue * src1,const GValue * src2)4801 gst_value_intersect_structure_structure (GValue * dest,
4802 const GValue * src1, const GValue * src2)
4803 {
4804 const GstStructure *s1, *s2;
4805 GstStructure *d1;
4806
4807 s1 = gst_value_get_structure (src1);
4808 s2 = gst_value_get_structure (src2);
4809
4810 d1 = gst_structure_intersect (s1, s2);
4811 if (!d1)
4812 return FALSE;
4813
4814 if (dest) {
4815 g_value_init (dest, GST_TYPE_STRUCTURE);
4816 gst_value_set_structure (dest, d1);
4817 }
4818
4819 gst_structure_free (d1);
4820 return TRUE;
4821 }
4822
4823 /***************
4824 * subtraction *
4825 ***************/
4826
4827 static gboolean
gst_value_subtract_int_int_range(GValue * dest,const GValue * minuend,const GValue * subtrahend)4828 gst_value_subtract_int_int_range (GValue * dest, const GValue * minuend,
4829 const GValue * subtrahend)
4830 {
4831 gint min = gst_value_get_int_range_min (subtrahend);
4832 gint max = gst_value_get_int_range_max (subtrahend);
4833 gint step = gst_value_get_int_range_step (subtrahend);
4834 gint val = g_value_get_int (minuend);
4835
4836 if (step == 0)
4837 return FALSE;
4838
4839 /* subtracting a range from an int only works if the int is not in the
4840 * range */
4841 if (val < min || val > max || val % step) {
4842 /* and the result is the int */
4843 if (dest)
4844 gst_value_init_and_copy (dest, minuend);
4845 return TRUE;
4846 }
4847 return FALSE;
4848 }
4849
4850 /* creates a new int range based on input values.
4851 */
4852 static gboolean
gst_value_create_new_range(GValue * dest,gint min1,gint max1,gint min2,gint max2,gint step)4853 gst_value_create_new_range (GValue * dest, gint min1, gint max1, gint min2,
4854 gint max2, gint step)
4855 {
4856 GValue v1 = { 0, };
4857 GValue v2 = { 0, };
4858 GValue *pv1, *pv2; /* yeah, hungarian! */
4859
4860 g_return_val_if_fail (step > 0, FALSE);
4861 g_return_val_if_fail (min1 % step == 0, FALSE);
4862 g_return_val_if_fail (max1 % step == 0, FALSE);
4863 g_return_val_if_fail (min2 % step == 0, FALSE);
4864 g_return_val_if_fail (max2 % step == 0, FALSE);
4865
4866 if (min1 <= max1 && min2 <= max2) {
4867 pv1 = &v1;
4868 pv2 = &v2;
4869 } else if (min1 <= max1) {
4870 pv1 = dest;
4871 pv2 = NULL;
4872 } else if (min2 <= max2) {
4873 pv1 = NULL;
4874 pv2 = dest;
4875 } else {
4876 return FALSE;
4877 }
4878
4879 if (!dest)
4880 return TRUE;
4881
4882 if (min1 < max1) {
4883 g_value_init (pv1, GST_TYPE_INT_RANGE);
4884 gst_value_set_int_range_step (pv1, min1, max1, step);
4885 } else if (min1 == max1) {
4886 g_value_init (pv1, G_TYPE_INT);
4887 g_value_set_int (pv1, min1);
4888 }
4889 if (min2 < max2) {
4890 g_value_init (pv2, GST_TYPE_INT_RANGE);
4891 gst_value_set_int_range_step (pv2, min2, max2, step);
4892 } else if (min2 == max2) {
4893 g_value_init (pv2, G_TYPE_INT);
4894 g_value_set_int (pv2, min2);
4895 }
4896
4897 if (min1 <= max1 && min2 <= max2) {
4898 gst_value_list_concat_and_take_values (dest, pv1, pv2);
4899 }
4900 return TRUE;
4901 }
4902
4903 static gboolean
gst_value_subtract_int_range_int(GValue * dest,const GValue * minuend,const GValue * subtrahend)4904 gst_value_subtract_int_range_int (GValue * dest, const GValue * minuend,
4905 const GValue * subtrahend)
4906 {
4907 gint min = gst_value_get_int_range_min (minuend);
4908 gint max = gst_value_get_int_range_max (minuend);
4909 gint step = gst_value_get_int_range_step (minuend);
4910 gint val = g_value_get_int (subtrahend);
4911
4912 g_return_val_if_fail (min < max, FALSE);
4913
4914 if (step == 0)
4915 return FALSE;
4916
4917 /* value is outside of the range, return range unchanged */
4918 if (val < min || val > max || val % step) {
4919 if (dest)
4920 gst_value_init_and_copy (dest, minuend);
4921 return TRUE;
4922 } else {
4923 /* max must be MAXINT too as val <= max */
4924 if (val >= G_MAXINT - step + 1) {
4925 max -= step;
4926 val -= step;
4927 }
4928 /* min must be MININT too as val >= max */
4929 if (val <= G_MININT + step - 1) {
4930 min += step;
4931 val += step;
4932 }
4933 if (dest)
4934 gst_value_create_new_range (dest, min, val - step, val + step, max, step);
4935 }
4936 return TRUE;
4937 }
4938
4939 static gboolean
gst_value_subtract_int_range_int_range(GValue * dest,const GValue * minuend,const GValue * subtrahend)4940 gst_value_subtract_int_range_int_range (GValue * dest, const GValue * minuend,
4941 const GValue * subtrahend)
4942 {
4943 gint min1 = gst_value_get_int_range_min (minuend);
4944 gint max1 = gst_value_get_int_range_max (minuend);
4945 gint step1 = gst_value_get_int_range_step (minuend);
4946 gint min2 = gst_value_get_int_range_min (subtrahend);
4947 gint max2 = gst_value_get_int_range_max (subtrahend);
4948 gint step2 = gst_value_get_int_range_step (subtrahend);
4949 gint step;
4950
4951 if (step1 != step2) {
4952 /* ENOIMPL */
4953 g_assert (FALSE);
4954 return FALSE;
4955 }
4956 step = step1;
4957
4958 if (step == 0)
4959 return FALSE;
4960
4961 if (max2 >= max1 && min2 <= min1) {
4962 return FALSE;
4963 } else if (max2 >= max1) {
4964 return gst_value_create_new_range (dest, min1, MIN (min2 - step, max1),
4965 step, 0, step);
4966 } else if (min2 <= min1) {
4967 return gst_value_create_new_range (dest, MAX (max2 + step, min1), max1,
4968 step, 0, step);
4969 } else {
4970 return gst_value_create_new_range (dest, min1, MIN (min2 - step, max1),
4971 MAX (max2 + step, min1), max1, step);
4972 }
4973 }
4974
4975 static gboolean
gst_value_subtract_int64_int64_range(GValue * dest,const GValue * minuend,const GValue * subtrahend)4976 gst_value_subtract_int64_int64_range (GValue * dest, const GValue * minuend,
4977 const GValue * subtrahend)
4978 {
4979 gint64 min = gst_value_get_int64_range_min (subtrahend);
4980 gint64 max = gst_value_get_int64_range_max (subtrahend);
4981 gint64 step = gst_value_get_int64_range_step (subtrahend);
4982 gint64 val = g_value_get_int64 (minuend);
4983
4984 if (step == 0)
4985 return FALSE;
4986 /* subtracting a range from an int64 only works if the int64 is not in the
4987 * range */
4988 if (val < min || val > max || val % step) {
4989 /* and the result is the int64 */
4990 if (dest)
4991 gst_value_init_and_copy (dest, minuend);
4992 return TRUE;
4993 }
4994 return FALSE;
4995 }
4996
4997 /* creates a new int64 range based on input values.
4998 */
4999 static gboolean
gst_value_create_new_int64_range(GValue * dest,gint64 min1,gint64 max1,gint64 min2,gint64 max2,gint64 step)5000 gst_value_create_new_int64_range (GValue * dest, gint64 min1, gint64 max1,
5001 gint64 min2, gint64 max2, gint64 step)
5002 {
5003 GValue v1 = { 0, };
5004 GValue v2 = { 0, };
5005 GValue *pv1, *pv2; /* yeah, hungarian! */
5006
5007 g_return_val_if_fail (step > 0, FALSE);
5008 g_return_val_if_fail (min1 % step == 0, FALSE);
5009 g_return_val_if_fail (max1 % step == 0, FALSE);
5010 g_return_val_if_fail (min2 % step == 0, FALSE);
5011 g_return_val_if_fail (max2 % step == 0, FALSE);
5012
5013 if (min1 <= max1 && min2 <= max2) {
5014 pv1 = &v1;
5015 pv2 = &v2;
5016 } else if (min1 <= max1) {
5017 pv1 = dest;
5018 pv2 = NULL;
5019 } else if (min2 <= max2) {
5020 pv1 = NULL;
5021 pv2 = dest;
5022 } else {
5023 return FALSE;
5024 }
5025
5026 if (!dest)
5027 return TRUE;
5028
5029 if (min1 < max1) {
5030 g_value_init (pv1, GST_TYPE_INT64_RANGE);
5031 gst_value_set_int64_range_step (pv1, min1, max1, step);
5032 } else if (min1 == max1) {
5033 g_value_init (pv1, G_TYPE_INT64);
5034 g_value_set_int64 (pv1, min1);
5035 }
5036 if (min2 < max2) {
5037 g_value_init (pv2, GST_TYPE_INT64_RANGE);
5038 gst_value_set_int64_range_step (pv2, min2, max2, step);
5039 } else if (min2 == max2) {
5040 g_value_init (pv2, G_TYPE_INT64);
5041 g_value_set_int64 (pv2, min2);
5042 }
5043
5044 if (min1 <= max1 && min2 <= max2) {
5045 gst_value_list_concat_and_take_values (dest, pv1, pv2);
5046 }
5047 return TRUE;
5048 }
5049
5050 static gboolean
gst_value_subtract_int64_range_int64(GValue * dest,const GValue * minuend,const GValue * subtrahend)5051 gst_value_subtract_int64_range_int64 (GValue * dest, const GValue * minuend,
5052 const GValue * subtrahend)
5053 {
5054 gint64 min = gst_value_get_int64_range_min (minuend);
5055 gint64 max = gst_value_get_int64_range_max (minuend);
5056 gint64 step = gst_value_get_int64_range_step (minuend);
5057 gint64 val = g_value_get_int64 (subtrahend);
5058
5059 g_return_val_if_fail (min < max, FALSE);
5060
5061 if (step == 0)
5062 return FALSE;
5063
5064 /* value is outside of the range, return range unchanged */
5065 if (val < min || val > max || val % step) {
5066 if (dest)
5067 gst_value_init_and_copy (dest, minuend);
5068 return TRUE;
5069 } else {
5070 /* max must be MAXINT64 too as val <= max */
5071 if (val >= G_MAXINT64 - step + 1) {
5072 max -= step;
5073 val -= step;
5074 }
5075 /* min must be MININT64 too as val >= max */
5076 if (val <= G_MININT64 + step - 1) {
5077 min += step;
5078 val += step;
5079 }
5080 if (dest)
5081 gst_value_create_new_int64_range (dest, min, val - step, val + step, max,
5082 step);
5083 }
5084 return TRUE;
5085 }
5086
5087 static gboolean
gst_value_subtract_int64_range_int64_range(GValue * dest,const GValue * minuend,const GValue * subtrahend)5088 gst_value_subtract_int64_range_int64_range (GValue * dest,
5089 const GValue * minuend, const GValue * subtrahend)
5090 {
5091 gint64 min1 = gst_value_get_int64_range_min (minuend);
5092 gint64 max1 = gst_value_get_int64_range_max (minuend);
5093 gint64 step1 = gst_value_get_int64_range_step (minuend);
5094 gint64 min2 = gst_value_get_int64_range_min (subtrahend);
5095 gint64 max2 = gst_value_get_int64_range_max (subtrahend);
5096 gint64 step2 = gst_value_get_int64_range_step (subtrahend);
5097 gint64 step;
5098
5099 if (step1 != step2) {
5100 /* ENOIMPL */
5101 g_assert (FALSE);
5102 return FALSE;
5103 }
5104
5105 if (step1 == 0)
5106 return FALSE;
5107
5108 step = step1;
5109
5110 if (max2 >= max1 && min2 <= min1) {
5111 return FALSE;
5112 } else if (max2 >= max1) {
5113 return gst_value_create_new_int64_range (dest, min1, MIN (min2 - step,
5114 max1), step, 0, step);
5115 } else if (min2 <= min1) {
5116 return gst_value_create_new_int64_range (dest, MAX (max2 + step, min1),
5117 max1, step, 0, step);
5118 } else {
5119 return gst_value_create_new_int64_range (dest, min1, MIN (min2 - step,
5120 max1), MAX (max2 + step, min1), max1, step);
5121 }
5122 }
5123
5124 static gboolean
gst_value_subtract_double_double_range(GValue * dest,const GValue * minuend,const GValue * subtrahend)5125 gst_value_subtract_double_double_range (GValue * dest, const GValue * minuend,
5126 const GValue * subtrahend)
5127 {
5128 gdouble min = gst_value_get_double_range_min (subtrahend);
5129 gdouble max = gst_value_get_double_range_max (subtrahend);
5130 gdouble val = g_value_get_double (minuend);
5131
5132 if (val < min || val > max) {
5133 if (dest)
5134 gst_value_init_and_copy (dest, minuend);
5135 return TRUE;
5136 }
5137 return FALSE;
5138 }
5139
5140 static gboolean
gst_value_subtract_double_range_double(GValue * dest,const GValue * minuend,const GValue * subtrahend)5141 gst_value_subtract_double_range_double (GValue * dest, const GValue * minuend,
5142 const GValue * subtrahend)
5143 {
5144 /* since we don't have open ranges, we cannot create a hole in
5145 * a double range. We return the original range */
5146 if (dest)
5147 gst_value_init_and_copy (dest, minuend);
5148 return TRUE;
5149 }
5150
5151 static gboolean
gst_value_subtract_double_range_double_range(GValue * dest,const GValue * minuend,const GValue * subtrahend)5152 gst_value_subtract_double_range_double_range (GValue * dest,
5153 const GValue * minuend, const GValue * subtrahend)
5154 {
5155 /* since we don't have open ranges, we have to approximate */
5156 /* done like with ints */
5157 gdouble min1 = gst_value_get_double_range_min (minuend);
5158 gdouble max2 = gst_value_get_double_range_max (minuend);
5159 gdouble max1 = MIN (gst_value_get_double_range_min (subtrahend), max2);
5160 gdouble min2 = MAX (gst_value_get_double_range_max (subtrahend), min1);
5161 GValue v1 = { 0, };
5162 GValue v2 = { 0, };
5163 GValue *pv1, *pv2; /* yeah, hungarian! */
5164
5165 if (min1 < max1 && min2 < max2) {
5166 pv1 = &v1;
5167 pv2 = &v2;
5168 } else if (min1 < max1) {
5169 pv1 = dest;
5170 pv2 = NULL;
5171 } else if (min2 < max2) {
5172 pv1 = NULL;
5173 pv2 = dest;
5174 } else {
5175 return FALSE;
5176 }
5177
5178 if (!dest)
5179 return TRUE;
5180
5181 if (min1 < max1) {
5182 g_value_init (pv1, GST_TYPE_DOUBLE_RANGE);
5183 gst_value_set_double_range (pv1, min1, max1);
5184 }
5185 if (min2 < max2) {
5186 g_value_init (pv2, GST_TYPE_DOUBLE_RANGE);
5187 gst_value_set_double_range (pv2, min2, max2);
5188 }
5189
5190 if (min1 < max1 && min2 < max2) {
5191 gst_value_list_concat_and_take_values (dest, pv1, pv2);
5192 }
5193 return TRUE;
5194 }
5195
5196 static gboolean
gst_value_subtract_from_list(GValue * dest,const GValue * minuend,const GValue * subtrahend)5197 gst_value_subtract_from_list (GValue * dest, const GValue * minuend,
5198 const GValue * subtrahend)
5199 {
5200 guint i, size;
5201 GValue subtraction = { 0, };
5202 gboolean ret = FALSE;
5203
5204 size = VALUE_LIST_SIZE (minuend);
5205 for (i = 0; i < size; i++) {
5206 const GValue *cur = VALUE_LIST_GET_VALUE (minuend, i);
5207
5208 /* quicker version when we can discard the result */
5209 if (!dest) {
5210 if (gst_value_subtract (NULL, cur, subtrahend)) {
5211 ret = TRUE;
5212 break;
5213 }
5214 continue;
5215 }
5216
5217 if (gst_value_subtract (&subtraction, cur, subtrahend)) {
5218 if (!ret) {
5219 gst_value_move (dest, &subtraction);
5220 ret = TRUE;
5221 } else if (G_VALUE_TYPE (dest) == GST_TYPE_LIST
5222 && G_VALUE_TYPE (&subtraction) != GST_TYPE_LIST) {
5223 _gst_value_list_append_and_take_value (dest, &subtraction);
5224 } else {
5225 GValue temp;
5226
5227 gst_value_move (&temp, dest);
5228 gst_value_list_concat_and_take_values (dest, &temp, &subtraction);
5229 }
5230 }
5231 }
5232 return ret;
5233 }
5234
5235 static gboolean
gst_value_subtract_list(GValue * dest,const GValue * minuend,const GValue * subtrahend)5236 gst_value_subtract_list (GValue * dest, const GValue * minuend,
5237 const GValue * subtrahend)
5238 {
5239 guint i, size;
5240 GValue data[2] = { {0,}, {0,} };
5241 GValue *subtraction = &data[0], *result = &data[1];
5242
5243 gst_value_init_and_copy (result, minuend);
5244 size = VALUE_LIST_SIZE (subtrahend);
5245 for (i = 0; i < size; i++) {
5246 const GValue *cur = VALUE_LIST_GET_VALUE (subtrahend, i);
5247
5248 if (gst_value_subtract (subtraction, result, cur)) {
5249 GValue *temp = result;
5250
5251 result = subtraction;
5252 subtraction = temp;
5253 g_value_unset (subtraction);
5254 } else {
5255 g_value_unset (result);
5256 return FALSE;
5257 }
5258 }
5259 if (dest) {
5260 gst_value_move (dest, result);
5261 } else {
5262 g_value_unset (result);
5263 }
5264 return TRUE;
5265 }
5266
5267 static gboolean
gst_value_subtract_fraction_fraction_range(GValue * dest,const GValue * minuend,const GValue * subtrahend)5268 gst_value_subtract_fraction_fraction_range (GValue * dest,
5269 const GValue * minuend, const GValue * subtrahend)
5270 {
5271 const GValue *min = gst_value_get_fraction_range_min (subtrahend);
5272 const GValue *max = gst_value_get_fraction_range_max (subtrahend);
5273 GstValueCompareFunc compare;
5274
5275 if ((compare = gst_value_get_compare_func (minuend))) {
5276 /* subtracting a range from an fraction only works if the fraction
5277 * is not in the range */
5278 if (gst_value_compare_with_func (minuend, min, compare) ==
5279 GST_VALUE_LESS_THAN ||
5280 gst_value_compare_with_func (minuend, max, compare) ==
5281 GST_VALUE_GREATER_THAN) {
5282 /* and the result is the value */
5283 if (dest)
5284 gst_value_init_and_copy (dest, minuend);
5285 return TRUE;
5286 }
5287 }
5288 return FALSE;
5289 }
5290
5291 static gboolean
gst_value_subtract_fraction_range_fraction(GValue * dest,const GValue * minuend,const GValue * subtrahend)5292 gst_value_subtract_fraction_range_fraction (GValue * dest,
5293 const GValue * minuend, const GValue * subtrahend)
5294 {
5295 /* since we don't have open ranges, we cannot create a hole in
5296 * a range. We return the original range */
5297 if (dest)
5298 gst_value_init_and_copy (dest, minuend);
5299 return TRUE;
5300 }
5301
5302 static gboolean
gst_value_subtract_fraction_range_fraction_range(GValue * dest,const GValue * minuend,const GValue * subtrahend)5303 gst_value_subtract_fraction_range_fraction_range (GValue * dest,
5304 const GValue * minuend, const GValue * subtrahend)
5305 {
5306 /* since we don't have open ranges, we have to approximate */
5307 /* done like with ints and doubles. Creates a list of 2 fraction ranges */
5308 const GValue *min1 = gst_value_get_fraction_range_min (minuend);
5309 const GValue *max2 = gst_value_get_fraction_range_max (minuend);
5310 const GValue *max1 = gst_value_get_fraction_range_min (subtrahend);
5311 const GValue *min2 = gst_value_get_fraction_range_max (subtrahend);
5312 gint cmp1, cmp2;
5313 GValue v1 = { 0, };
5314 GValue v2 = { 0, };
5315 GValue *pv1, *pv2; /* yeah, hungarian! */
5316 GstValueCompareFunc compare;
5317
5318 g_return_val_if_fail (min1 != NULL && max1 != NULL, FALSE);
5319 g_return_val_if_fail (min2 != NULL && max2 != NULL, FALSE);
5320
5321 compare = gst_value_get_compare_func (min1);
5322 g_return_val_if_fail (compare, FALSE);
5323
5324 cmp1 = gst_value_compare_with_func (max2, max1, compare);
5325 g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
5326 if (cmp1 == GST_VALUE_LESS_THAN)
5327 max1 = max2;
5328 cmp1 = gst_value_compare_with_func (min1, min2, compare);
5329 g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
5330 if (cmp1 == GST_VALUE_GREATER_THAN)
5331 min2 = min1;
5332
5333 cmp1 = gst_value_compare_with_func (min1, max1, compare);
5334 cmp2 = gst_value_compare_with_func (min2, max2, compare);
5335
5336 if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
5337 pv1 = &v1;
5338 pv2 = &v2;
5339 } else if (cmp1 == GST_VALUE_LESS_THAN) {
5340 pv1 = dest;
5341 pv2 = NULL;
5342 } else if (cmp2 == GST_VALUE_LESS_THAN) {
5343 pv1 = NULL;
5344 pv2 = dest;
5345 } else {
5346 return FALSE;
5347 }
5348
5349 if (!dest)
5350 return TRUE;
5351
5352 if (cmp1 == GST_VALUE_LESS_THAN) {
5353 g_value_init (pv1, GST_TYPE_FRACTION_RANGE);
5354 gst_value_set_fraction_range (pv1, min1, max1);
5355 }
5356 if (cmp2 == GST_VALUE_LESS_THAN) {
5357 g_value_init (pv2, GST_TYPE_FRACTION_RANGE);
5358 gst_value_set_fraction_range (pv2, min2, max2);
5359 }
5360
5361 if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
5362 gst_value_list_concat_and_take_values (dest, pv1, pv2);
5363 }
5364 return TRUE;
5365 }
5366
5367 /**************
5368 * comparison *
5369 **************/
5370
5371 /*
5372 * gst_value_get_compare_func:
5373 * @value1: a value to get the compare function for
5374 *
5375 * Determines the compare function to be used with values of the same type as
5376 * @value1. The function can be given to gst_value_compare_with_func().
5377 *
5378 * Returns: A #GstValueCompareFunc value
5379 */
5380 static GstValueCompareFunc
gst_value_get_compare_func(const GValue * value1)5381 gst_value_get_compare_func (const GValue * value1)
5382 {
5383 GstValueTable *table, *best = NULL;
5384 guint i;
5385 GType type1;
5386
5387 type1 = G_VALUE_TYPE (value1);
5388
5389 /* this is a fast check */
5390 best = gst_value_hash_lookup_type (type1);
5391
5392 /* slower checks */
5393 if (G_UNLIKELY (!best || !best->compare)) {
5394 guint len = gst_value_table->len;
5395
5396 best = NULL;
5397 for (i = 0; i < len; i++) {
5398 table = &g_array_index (gst_value_table, GstValueTable, i);
5399 if (table->compare && g_type_is_a (type1, table->type)) {
5400 if (!best || g_type_is_a (table->type, best->type))
5401 best = table;
5402 }
5403 }
5404 }
5405 if (G_LIKELY (best))
5406 return best->compare;
5407
5408 return NULL;
5409 }
5410
5411 static inline gboolean
gst_value_can_compare_unchecked(const GValue * value1,const GValue * value2)5412 gst_value_can_compare_unchecked (const GValue * value1, const GValue * value2)
5413 {
5414 if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
5415 return FALSE;
5416
5417 return gst_value_get_compare_func (value1) != NULL;
5418 }
5419
5420 /**
5421 * gst_value_can_compare:
5422 * @value1: a value to compare
5423 * @value2: another value to compare
5424 *
5425 * Determines if @value1 and @value2 can be compared.
5426 *
5427 * Returns: %TRUE if the values can be compared
5428 */
5429 gboolean
gst_value_can_compare(const GValue * value1,const GValue * value2)5430 gst_value_can_compare (const GValue * value1, const GValue * value2)
5431 {
5432 g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
5433 g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
5434
5435 return gst_value_can_compare_unchecked (value1, value2);
5436 }
5437
5438 static gboolean
gst_value_list_equals_range(const GValue * list,const GValue * value)5439 gst_value_list_equals_range (const GValue * list, const GValue * value)
5440 {
5441 const GValue *first;
5442 guint list_size, n;
5443
5444 g_assert (G_IS_VALUE (list));
5445 g_assert (G_IS_VALUE (value));
5446 g_assert (GST_VALUE_HOLDS_LIST (list));
5447
5448 /* TODO: compare against an empty list ? No type though... */
5449 list_size = VALUE_LIST_SIZE (list);
5450 if (list_size == 0)
5451 return FALSE;
5452
5453 /* compare the basic types - they have to match */
5454 first = VALUE_LIST_GET_VALUE (list, 0);
5455 #define CHECK_TYPES(type,prefix) \
5456 (prefix##_VALUE_HOLDS_##type(first) && GST_VALUE_HOLDS_##type##_RANGE (value))
5457 if (CHECK_TYPES (INT, G)) {
5458 const gint rmin = gst_value_get_int_range_min (value);
5459 const gint rmax = gst_value_get_int_range_max (value);
5460 const gint rstep = gst_value_get_int_range_step (value);
5461 if (rstep == 0)
5462 return FALSE;
5463 /* note: this will overflow for min 0 and max INT_MAX, but this
5464 would only be equal to a list of INT_MAX elements, which seems
5465 very unlikely */
5466 if (list_size != rmax / rstep - rmin / rstep + 1)
5467 return FALSE;
5468 for (n = 0; n < list_size; ++n) {
5469 gint v = g_value_get_int (VALUE_LIST_GET_VALUE (list, n));
5470 if (v < rmin || v > rmax || v % rstep) {
5471 return FALSE;
5472 }
5473 }
5474 return TRUE;
5475 } else if (CHECK_TYPES (INT64, G)) {
5476 const gint64 rmin = gst_value_get_int64_range_min (value);
5477 const gint64 rmax = gst_value_get_int64_range_max (value);
5478 const gint64 rstep = gst_value_get_int64_range_step (value);
5479 GST_DEBUG ("List/range of int64s");
5480 if (rstep == 0)
5481 return FALSE;
5482 if (list_size != rmax / rstep - rmin / rstep + 1)
5483 return FALSE;
5484 for (n = 0; n < list_size; ++n) {
5485 gint64 v = g_value_get_int64 (VALUE_LIST_GET_VALUE (list, n));
5486 if (v < rmin || v > rmax || v % rstep)
5487 return FALSE;
5488 }
5489 return TRUE;
5490 }
5491 #undef CHECK_TYPES
5492
5493 /* other combinations don't make sense for equality */
5494 return FALSE;
5495 }
5496
5497 /* "Pure" variant of gst_value_compare which is guaranteed to
5498 * not have list arguments and therefore does basic comparisons
5499 */
5500 static inline gint
_gst_value_compare_nolist(const GValue * value1,const GValue * value2)5501 _gst_value_compare_nolist (const GValue * value1, const GValue * value2)
5502 {
5503 GstValueCompareFunc compare;
5504
5505 if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
5506 return GST_VALUE_UNORDERED;
5507
5508 compare = gst_value_get_compare_func (value1);
5509 if (compare) {
5510 return compare (value1, value2);
5511 }
5512
5513 g_critical ("unable to compare values of type %s\n",
5514 g_type_name (G_VALUE_TYPE (value1)));
5515 return GST_VALUE_UNORDERED;
5516 }
5517
5518 /**
5519 * gst_value_compare:
5520 * @value1: a value to compare
5521 * @value2: another value to compare
5522 *
5523 * Compares @value1 and @value2. If @value1 and @value2 cannot be
5524 * compared, the function returns GST_VALUE_UNORDERED. Otherwise,
5525 * if @value1 is greater than @value2, GST_VALUE_GREATER_THAN is returned.
5526 * If @value1 is less than @value2, GST_VALUE_LESS_THAN is returned.
5527 * If the values are equal, GST_VALUE_EQUAL is returned.
5528 *
5529 * Returns: comparison result
5530 */
5531 gint
gst_value_compare(const GValue * value1,const GValue * value2)5532 gst_value_compare (const GValue * value1, const GValue * value2)
5533 {
5534 gboolean value1_is_list;
5535 gboolean value2_is_list;
5536
5537 g_return_val_if_fail (G_IS_VALUE (value1), GST_VALUE_LESS_THAN);
5538 g_return_val_if_fail (G_IS_VALUE (value2), GST_VALUE_GREATER_THAN);
5539
5540 value1_is_list = G_VALUE_TYPE (value1) == GST_TYPE_LIST;
5541 value2_is_list = G_VALUE_TYPE (value2) == GST_TYPE_LIST;
5542
5543 /* Special cases: lists and scalar values ("{ 1 }" and "1" are equal),
5544 as well as lists and ranges ("{ 1, 2 }" and "[ 1, 2 ]" are equal) */
5545 if (value1_is_list && !value2_is_list) {
5546 gint i, n, ret;
5547
5548 if (gst_value_list_equals_range (value1, value2)) {
5549 return GST_VALUE_EQUAL;
5550 }
5551
5552 n = gst_value_list_get_size (value1);
5553 if (n == 0)
5554 return GST_VALUE_UNORDERED;
5555
5556 for (i = 0; i < n; i++) {
5557 const GValue *elt;
5558
5559 elt = gst_value_list_get_value (value1, i);
5560 ret = gst_value_compare (elt, value2);
5561 if (ret != GST_VALUE_EQUAL && n == 1)
5562 return ret;
5563 else if (ret != GST_VALUE_EQUAL)
5564 return GST_VALUE_UNORDERED;
5565 }
5566
5567 return GST_VALUE_EQUAL;
5568 } else if (value2_is_list && !value1_is_list) {
5569 gint i, n, ret;
5570
5571 if (gst_value_list_equals_range (value2, value1)) {
5572 return GST_VALUE_EQUAL;
5573 }
5574
5575 n = gst_value_list_get_size (value2);
5576 if (n == 0)
5577 return GST_VALUE_UNORDERED;
5578
5579 for (i = 0; i < n; i++) {
5580 const GValue *elt;
5581
5582 elt = gst_value_list_get_value (value2, i);
5583 ret = gst_value_compare (elt, value1);
5584 if (ret != GST_VALUE_EQUAL && n == 1)
5585 return ret;
5586 else if (ret != GST_VALUE_EQUAL)
5587 return GST_VALUE_UNORDERED;
5588 }
5589
5590 return GST_VALUE_EQUAL;
5591 }
5592
5593 /* And now handle the generic case */
5594 return _gst_value_compare_nolist (value1, value2);
5595 }
5596
5597 /*
5598 * gst_value_compare_with_func:
5599 * @value1: a value to compare
5600 * @value2: another value to compare
5601 * @compare: compare function
5602 *
5603 * Compares @value1 and @value2 using the @compare function. Works like
5604 * gst_value_compare() but allows to save time determining the compare function
5605 * a multiple times.
5606 *
5607 * Returns: comparison result
5608 */
5609 static gint
gst_value_compare_with_func(const GValue * value1,const GValue * value2,GstValueCompareFunc compare)5610 gst_value_compare_with_func (const GValue * value1, const GValue * value2,
5611 GstValueCompareFunc compare)
5612 {
5613 g_assert (compare);
5614
5615 if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
5616 return GST_VALUE_UNORDERED;
5617
5618 return compare (value1, value2);
5619 }
5620
5621 /* union */
5622
5623 /**
5624 * gst_value_can_union:
5625 * @value1: a value to union
5626 * @value2: another value to union
5627 *
5628 * Determines if @value1 and @value2 can be non-trivially unioned.
5629 * Any two values can be trivially unioned by adding both of them
5630 * to a GstValueList. However, certain types have the possibility
5631 * to be unioned in a simpler way. For example, an integer range
5632 * and an integer can be unioned if the integer is a subset of the
5633 * integer range. If there is the possibility that two values can
5634 * be unioned, this function returns %TRUE.
5635 *
5636 * Returns: %TRUE if there is a function allowing the two values to
5637 * be unioned.
5638 */
5639 gboolean
gst_value_can_union(const GValue * value1,const GValue * value2)5640 gst_value_can_union (const GValue * value1, const GValue * value2)
5641 {
5642 GstValueUnionInfo *union_info;
5643 guint i, len;
5644
5645 g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
5646 g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
5647
5648 len = gst_value_union_funcs->len;
5649
5650 for (i = 0; i < len; i++) {
5651 union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
5652 if (union_info->type1 == G_VALUE_TYPE (value1) &&
5653 union_info->type2 == G_VALUE_TYPE (value2))
5654 return TRUE;
5655 if (union_info->type1 == G_VALUE_TYPE (value2) &&
5656 union_info->type2 == G_VALUE_TYPE (value1))
5657 return TRUE;
5658 }
5659
5660 return FALSE;
5661 }
5662
5663 /**
5664 * gst_value_union:
5665 * @dest: (out caller-allocates): the destination value
5666 * @value1: a value to union
5667 * @value2: another value to union
5668 *
5669 * Creates a GValue corresponding to the union of @value1 and @value2.
5670 *
5671 * Returns: %TRUE if the union succeeded.
5672 */
5673 gboolean
gst_value_union(GValue * dest,const GValue * value1,const GValue * value2)5674 gst_value_union (GValue * dest, const GValue * value1, const GValue * value2)
5675 {
5676 const GstValueUnionInfo *union_info;
5677 guint i, len;
5678 GType type1, type2;
5679
5680 g_return_val_if_fail (dest != NULL, FALSE);
5681 g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
5682 g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
5683 g_return_val_if_fail (gst_value_list_or_array_are_compatible (value1, value2),
5684 FALSE);
5685
5686 len = gst_value_union_funcs->len;
5687 type1 = G_VALUE_TYPE (value1);
5688 type2 = G_VALUE_TYPE (value2);
5689
5690 for (i = 0; i < len; i++) {
5691 union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
5692 if (union_info->type1 == type1 && union_info->type2 == type2) {
5693 return union_info->func (dest, value1, value2);
5694 }
5695 if (union_info->type1 == type2 && union_info->type2 == type1) {
5696 return union_info->func (dest, value2, value1);
5697 }
5698 }
5699
5700 gst_value_list_concat (dest, value1, value2);
5701 return TRUE;
5702 }
5703
5704 /* gst_value_register_union_func: (skip)
5705 * @type1: a type to union
5706 * @type2: another type to union
5707 * @func: a function that implements creating a union between the two types
5708 *
5709 * Registers a union function that can create a union between #GValue items
5710 * of the type @type1 and @type2.
5711 *
5712 * Union functions should be registered at startup before any pipelines are
5713 * started, as gst_value_register_union_func() is not thread-safe and cannot
5714 * be used at the same time as gst_value_union() or gst_value_can_union().
5715 */
5716 static void
gst_value_register_union_func(GType type1,GType type2,GstValueUnionFunc func)5717 gst_value_register_union_func (GType type1, GType type2, GstValueUnionFunc func)
5718 {
5719 GstValueUnionInfo union_info;
5720
5721 union_info.type1 = type1;
5722 union_info.type2 = type2;
5723 union_info.func = func;
5724
5725 g_array_append_val (gst_value_union_funcs, union_info);
5726 }
5727
5728 /* intersection */
5729
5730 /**
5731 * gst_value_can_intersect:
5732 * @value1: a value to intersect
5733 * @value2: another value to intersect
5734 *
5735 * Determines if intersecting two values will produce a valid result.
5736 * Two values will produce a valid intersection if they have the same
5737 * type.
5738 *
5739 * Returns: %TRUE if the values can intersect
5740 */
5741 gboolean
gst_value_can_intersect(const GValue * value1,const GValue * value2)5742 gst_value_can_intersect (const GValue * value1, const GValue * value2)
5743 {
5744 GstValueIntersectInfo *intersect_info;
5745 guint i, len;
5746 GType type1, type2;
5747
5748 g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
5749 g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
5750
5751 type1 = G_VALUE_TYPE (value1);
5752 type2 = G_VALUE_TYPE (value2);
5753
5754 /* practically all GstValue types have a compare function (_can_compare=TRUE)
5755 * GstStructure and GstCaps have not, but are intersectable */
5756 if (type1 == type2)
5757 return TRUE;
5758
5759 /* special cases */
5760 if (type1 == GST_TYPE_LIST || type2 == GST_TYPE_LIST)
5761 return TRUE;
5762
5763 if (G_UNLIKELY (GST_VALUE_HOLDS_FLAG_SET (value1) &&
5764 GST_VALUE_HOLDS_FLAG_SET (value2))) {
5765 GType type1, type2, flagset_type;
5766
5767 type1 = G_VALUE_TYPE (value1);
5768 type2 = G_VALUE_TYPE (value2);
5769 flagset_type = GST_TYPE_FLAG_SET;
5770
5771 /* Allow intersection with the generic FlagSet type, on one
5772 * side, but not 2 different subtypes - that makes no sense */
5773 if (type1 == type2 || type1 == flagset_type || type2 == flagset_type)
5774 return TRUE;
5775 }
5776
5777 /* check registered intersect functions */
5778 len = gst_value_intersect_funcs->len;
5779 for (i = 0; i < len; i++) {
5780 intersect_info = &g_array_index (gst_value_intersect_funcs,
5781 GstValueIntersectInfo, i);
5782 if ((intersect_info->type1 == type1 && intersect_info->type2 == type2) ||
5783 (intersect_info->type1 == type2 && intersect_info->type2 == type1))
5784 return TRUE;
5785 }
5786
5787 return gst_value_can_compare_unchecked (value1, value2);
5788 }
5789
5790 /**
5791 * gst_value_intersect:
5792 * @dest: (out caller-allocates) (transfer full) (allow-none):
5793 * a uninitialized #GValue that will hold the calculated
5794 * intersection value. May be %NULL if the resulting set if not
5795 * needed.
5796 * @value1: a value to intersect
5797 * @value2: another value to intersect
5798 *
5799 * Calculates the intersection of two values. If the values have
5800 * a non-empty intersection, the value representing the intersection
5801 * is placed in @dest, unless %NULL. If the intersection is non-empty,
5802 * @dest is not modified.
5803 *
5804 * Returns: %TRUE if the intersection is non-empty
5805 */
5806 gboolean
gst_value_intersect(GValue * dest,const GValue * value1,const GValue * value2)5807 gst_value_intersect (GValue * dest, const GValue * value1,
5808 const GValue * value2)
5809 {
5810 GstValueIntersectInfo *intersect_info;
5811 guint i, len;
5812 GType type1, type2;
5813
5814 g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
5815 g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
5816
5817 type1 = G_VALUE_TYPE (value1);
5818 type2 = G_VALUE_TYPE (value2);
5819
5820 /* special cases first */
5821 if (type1 == GST_TYPE_LIST)
5822 return gst_value_intersect_list (dest, value1, value2);
5823 if (type2 == GST_TYPE_LIST)
5824 return gst_value_intersect_list (dest, value2, value1);
5825
5826 if (_gst_value_compare_nolist (value1, value2) == GST_VALUE_EQUAL) {
5827 if (dest)
5828 gst_value_init_and_copy (dest, value1);
5829 return TRUE;
5830 }
5831
5832 len = gst_value_intersect_funcs->len;
5833 for (i = 0; i < len; i++) {
5834 intersect_info = &g_array_index (gst_value_intersect_funcs,
5835 GstValueIntersectInfo, i);
5836 if (intersect_info->type1 == type1 && intersect_info->type2 == type2) {
5837 return intersect_info->func (dest, value1, value2);
5838 }
5839 if (intersect_info->type1 == type2 && intersect_info->type2 == type1) {
5840 return intersect_info->func (dest, value2, value1);
5841 }
5842 }
5843
5844 /* Failed to find a direct intersection, check if these are
5845 * GstFlagSet sub-types. */
5846 if (G_UNLIKELY (GST_VALUE_HOLDS_FLAG_SET (value1) &&
5847 GST_VALUE_HOLDS_FLAG_SET (value2))) {
5848 return gst_value_intersect_flagset_flagset (dest, value1, value2);
5849 }
5850
5851 return FALSE;
5852 }
5853
5854
5855
5856 /* gst_value_register_intersect_func: (skip)
5857 * @type1: the first type to intersect
5858 * @type2: the second type to intersect
5859 * @func: the intersection function
5860 *
5861 * Registers a function that is called to calculate the intersection
5862 * of the values having the types @type1 and @type2.
5863 *
5864 * Intersect functions should be registered at startup before any pipelines are
5865 * started, as gst_value_register_intersect_func() is not thread-safe and
5866 * cannot be used at the same time as gst_value_intersect() or
5867 * gst_value_can_intersect().
5868 */
5869 static void
gst_value_register_intersect_func(GType type1,GType type2,GstValueIntersectFunc func)5870 gst_value_register_intersect_func (GType type1, GType type2,
5871 GstValueIntersectFunc func)
5872 {
5873 GstValueIntersectInfo intersect_info;
5874
5875 intersect_info.type1 = type1;
5876 intersect_info.type2 = type2;
5877 intersect_info.func = func;
5878
5879 g_array_append_val (gst_value_intersect_funcs, intersect_info);
5880 }
5881
5882
5883 /* subtraction */
5884
5885 /**
5886 * gst_value_subtract:
5887 * @dest: (out caller-allocates) (allow-none): the destination value
5888 * for the result if the subtraction is not empty. May be %NULL,
5889 * in which case the resulting set will not be computed, which can
5890 * give a fair speedup.
5891 * @minuend: the value to subtract from
5892 * @subtrahend: the value to subtract
5893 *
5894 * Subtracts @subtrahend from @minuend and stores the result in @dest.
5895 * Note that this means subtraction as in sets, not as in mathematics.
5896 *
5897 * Returns: %TRUE if the subtraction is not empty
5898 */
5899 gboolean
gst_value_subtract(GValue * dest,const GValue * minuend,const GValue * subtrahend)5900 gst_value_subtract (GValue * dest, const GValue * minuend,
5901 const GValue * subtrahend)
5902 {
5903 GstValueSubtractInfo *info;
5904 guint i, len;
5905 GType mtype, stype;
5906
5907 g_return_val_if_fail (G_IS_VALUE (minuend), FALSE);
5908 g_return_val_if_fail (G_IS_VALUE (subtrahend), FALSE);
5909
5910 mtype = G_VALUE_TYPE (minuend);
5911 stype = G_VALUE_TYPE (subtrahend);
5912
5913 /* special cases first */
5914 if (mtype == GST_TYPE_LIST)
5915 return gst_value_subtract_from_list (dest, minuend, subtrahend);
5916 if (stype == GST_TYPE_LIST)
5917 return gst_value_subtract_list (dest, minuend, subtrahend);
5918
5919 len = gst_value_subtract_funcs->len;
5920 for (i = 0; i < len; i++) {
5921 info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
5922 if (info->minuend == mtype && info->subtrahend == stype) {
5923 return info->func (dest, minuend, subtrahend);
5924 }
5925 }
5926
5927 if (_gst_value_compare_nolist (minuend, subtrahend) != GST_VALUE_EQUAL) {
5928 if (dest)
5929 gst_value_init_and_copy (dest, minuend);
5930 return TRUE;
5931 }
5932
5933 return FALSE;
5934 }
5935
5936 #if 0
5937 gboolean
5938 gst_value_subtract (GValue * dest, const GValue * minuend,
5939 const GValue * subtrahend)
5940 {
5941 gboolean ret = gst_value_subtract2 (dest, minuend, subtrahend);
5942
5943 g_printerr ("\"%s\" - \"%s\" = \"%s\"\n", gst_value_serialize (minuend),
5944 gst_value_serialize (subtrahend),
5945 ret ? gst_value_serialize (dest) : "---");
5946 return ret;
5947 }
5948 #endif
5949
5950 /**
5951 * gst_value_can_subtract:
5952 * @minuend: the value to subtract from
5953 * @subtrahend: the value to subtract
5954 *
5955 * Checks if it's possible to subtract @subtrahend from @minuend.
5956 *
5957 * Returns: %TRUE if a subtraction is possible
5958 */
5959 gboolean
gst_value_can_subtract(const GValue * minuend,const GValue * subtrahend)5960 gst_value_can_subtract (const GValue * minuend, const GValue * subtrahend)
5961 {
5962 GstValueSubtractInfo *info;
5963 guint i, len;
5964 GType mtype, stype;
5965
5966 g_return_val_if_fail (G_IS_VALUE (minuend), FALSE);
5967 g_return_val_if_fail (G_IS_VALUE (subtrahend), FALSE);
5968
5969 mtype = G_VALUE_TYPE (minuend);
5970 stype = G_VALUE_TYPE (subtrahend);
5971
5972 /* special cases */
5973 if (mtype == GST_TYPE_LIST || stype == GST_TYPE_LIST)
5974 return TRUE;
5975 if (mtype == GST_TYPE_STRUCTURE || stype == GST_TYPE_STRUCTURE)
5976 return FALSE;
5977
5978 len = gst_value_subtract_funcs->len;
5979 for (i = 0; i < len; i++) {
5980 info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
5981 if (info->minuend == mtype && info->subtrahend == stype)
5982 return TRUE;
5983 }
5984
5985 return gst_value_can_compare_unchecked (minuend, subtrahend);
5986 }
5987
5988 /* gst_value_register_subtract_func: (skip)
5989 * @minuend_type: type of the minuend
5990 * @subtrahend_type: type of the subtrahend
5991 * @func: function to use
5992 *
5993 * Registers @func as a function capable of subtracting the values of
5994 * @subtrahend_type from values of @minuend_type.
5995 *
5996 * Subtract functions should be registered at startup before any pipelines are
5997 * started, as gst_value_register_subtract_func() is not thread-safe and
5998 * cannot be used at the same time as gst_value_subtract().
5999 */
6000 static void
gst_value_register_subtract_func(GType minuend_type,GType subtrahend_type,GstValueSubtractFunc func)6001 gst_value_register_subtract_func (GType minuend_type, GType subtrahend_type,
6002 GstValueSubtractFunc func)
6003 {
6004 GstValueSubtractInfo info;
6005
6006 g_return_if_fail (!gst_type_is_fixed (minuend_type)
6007 || !gst_type_is_fixed (subtrahend_type));
6008
6009 info.minuend = minuend_type;
6010 info.subtrahend = subtrahend_type;
6011 info.func = func;
6012
6013 g_array_append_val (gst_value_subtract_funcs, info);
6014 }
6015
6016 /**
6017 * gst_value_register:
6018 * @table: structure containing functions to register
6019 *
6020 * Registers functions to perform calculations on #GValue items of a given
6021 * type. Each type can only be added once.
6022 */
6023 void
gst_value_register(const GstValueTable * table)6024 gst_value_register (const GstValueTable * table)
6025 {
6026 GstValueTable *found;
6027
6028 g_return_if_fail (table != NULL);
6029
6030 g_array_append_val (gst_value_table, *table);
6031
6032 found = gst_value_hash_lookup_type (table->type);
6033 if (found)
6034 g_warning ("adding type %s multiple times", g_type_name (table->type));
6035
6036 /* FIXME: we're not really doing the const justice, we assume the table is
6037 * static */
6038 gst_value_hash_add_type (table->type, table);
6039 }
6040
6041 /**
6042 * gst_value_init_and_copy:
6043 * @dest: (out caller-allocates): the target value
6044 * @src: the source value
6045 *
6046 * Initialises the target value to be of the same type as source and then copies
6047 * the contents from source to target.
6048 */
6049 void
gst_value_init_and_copy(GValue * dest,const GValue * src)6050 gst_value_init_and_copy (GValue * dest, const GValue * src)
6051 {
6052 g_return_if_fail (G_IS_VALUE (src));
6053 g_return_if_fail (dest != NULL);
6054
6055 g_value_init (dest, G_VALUE_TYPE (src));
6056 g_value_copy (src, dest);
6057 }
6058
6059 /* move src into dest and clear src */
6060 static void
gst_value_move(GValue * dest,GValue * src)6061 gst_value_move (GValue * dest, GValue * src)
6062 {
6063 g_assert (G_IS_VALUE (src));
6064 g_assert (dest != NULL);
6065
6066 *dest = *src;
6067 memset (src, 0, sizeof (GValue));
6068 }
6069
6070 /**
6071 * gst_value_serialize:
6072 * @value: a #GValue to serialize
6073 *
6074 * tries to transform the given @value into a string representation that allows
6075 * getting back this string later on using gst_value_deserialize().
6076 *
6077 * Free-function: g_free
6078 *
6079 * Returns: (transfer full) (nullable): the serialization for @value
6080 * or %NULL if none exists
6081 */
6082 gchar *
gst_value_serialize(const GValue * value)6083 gst_value_serialize (const GValue * value)
6084 {
6085 guint i, len;
6086 GValue s_val = { 0 };
6087 GstValueTable *table, *best;
6088 gchar *s;
6089 GType type;
6090
6091 g_return_val_if_fail (G_IS_VALUE (value), NULL);
6092
6093 type = G_VALUE_TYPE (value);
6094
6095 best = gst_value_hash_lookup_type (type);
6096
6097 if (G_UNLIKELY (!best || !best->serialize)) {
6098 len = gst_value_table->len;
6099 best = NULL;
6100 for (i = 0; i < len; i++) {
6101 table = &g_array_index (gst_value_table, GstValueTable, i);
6102 if (table->serialize && g_type_is_a (type, table->type)) {
6103 if (!best || g_type_is_a (table->type, best->type))
6104 best = table;
6105 }
6106 }
6107 }
6108 if (G_LIKELY (best))
6109 return best->serialize (value);
6110
6111 g_value_init (&s_val, G_TYPE_STRING);
6112 if (g_value_transform (value, &s_val)) {
6113 s = gst_string_wrap (g_value_get_string (&s_val));
6114 } else {
6115 s = NULL;
6116 }
6117 g_value_unset (&s_val);
6118
6119 return s;
6120 }
6121
6122 /**
6123 * gst_value_deserialize:
6124 * @dest: (out caller-allocates): #GValue to fill with contents of
6125 * deserialization
6126 * @src: string to deserialize
6127 *
6128 * Tries to deserialize a string into the type specified by the given GValue.
6129 * If the operation succeeds, %TRUE is returned, %FALSE otherwise.
6130 *
6131 * Returns: %TRUE on success
6132 */
6133 gboolean
gst_value_deserialize(GValue * dest,const gchar * src)6134 gst_value_deserialize (GValue * dest, const gchar * src)
6135 {
6136 GstValueTable *table, *best;
6137 guint i, len;
6138 GType type;
6139
6140 g_return_val_if_fail (src != NULL, FALSE);
6141 g_return_val_if_fail (G_IS_VALUE (dest), FALSE);
6142
6143 type = G_VALUE_TYPE (dest);
6144
6145 best = gst_value_hash_lookup_type (type);
6146 if (G_UNLIKELY (!best || !best->deserialize)) {
6147 len = gst_value_table->len;
6148 best = NULL;
6149 for (i = 0; i < len; i++) {
6150 table = &g_array_index (gst_value_table, GstValueTable, i);
6151 if (table->deserialize && g_type_is_a (type, table->type)) {
6152 if (!best || g_type_is_a (table->type, best->type))
6153 best = table;
6154 }
6155 }
6156 }
6157 if (G_LIKELY (best))
6158 return best->deserialize (dest, src);
6159
6160 return FALSE;
6161 }
6162
6163 static gboolean
structure_field_is_fixed(GQuark field_id,const GValue * val,gpointer user_data)6164 structure_field_is_fixed (GQuark field_id, const GValue * val,
6165 gpointer user_data)
6166 {
6167 return gst_value_is_fixed (val);
6168 }
6169
6170 /**
6171 * gst_value_is_fixed:
6172 * @value: the #GValue to check
6173 *
6174 * Tests if the given GValue, if available in a GstStructure (or any other
6175 * container) contains a "fixed" (which means: one value) or an "unfixed"
6176 * (which means: multiple possible values, such as data lists or data
6177 * ranges) value.
6178 *
6179 * Returns: true if the value is "fixed".
6180 */
6181
6182 gboolean
gst_value_is_fixed(const GValue * value)6183 gst_value_is_fixed (const GValue * value)
6184 {
6185 GType type;
6186
6187 g_return_val_if_fail (G_IS_VALUE (value), FALSE);
6188
6189 type = G_VALUE_TYPE (value);
6190
6191 /* the most common types are just basic plain glib types */
6192 if (type <= G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
6193 return TRUE;
6194 }
6195
6196 if (type == GST_TYPE_ARRAY) {
6197 gint size, n;
6198 const GValue *kid;
6199
6200 /* check recursively */
6201 size = gst_value_array_get_size (value);
6202 for (n = 0; n < size; n++) {
6203 kid = gst_value_array_get_value (value, n);
6204 if (!gst_value_is_fixed (kid))
6205 return FALSE;
6206 }
6207 return TRUE;
6208 } else if (GST_VALUE_HOLDS_FLAG_SET (value)) {
6209 /* Flagsets are only fixed if there are no 'don't care' bits */
6210 return (gst_value_get_flagset_mask (value) == GST_FLAG_SET_MASK_EXACT);
6211 } else if (GST_VALUE_HOLDS_STRUCTURE (value)) {
6212 return gst_structure_foreach (gst_value_get_structure (value),
6213 structure_field_is_fixed, NULL);
6214 }
6215 return gst_type_is_fixed (type);
6216 }
6217
6218 /**
6219 * gst_value_fixate:
6220 * @dest: the #GValue destination
6221 * @src: the #GValue to fixate
6222 *
6223 * Fixate @src into a new value @dest.
6224 * For ranges, the first element is taken. For lists and arrays, the
6225 * first item is fixated and returned.
6226 * If @src is already fixed, this function returns %FALSE.
6227 *
6228 * Returns: %TRUE if @dest contains a fixated version of @src.
6229 */
6230 gboolean
gst_value_fixate(GValue * dest,const GValue * src)6231 gst_value_fixate (GValue * dest, const GValue * src)
6232 {
6233 g_return_val_if_fail (G_IS_VALUE (src), FALSE);
6234 g_return_val_if_fail (dest != NULL, FALSE);
6235
6236 if (G_VALUE_TYPE (src) == GST_TYPE_INT_RANGE) {
6237 g_value_init (dest, G_TYPE_INT);
6238 g_value_set_int (dest, gst_value_get_int_range_min (src));
6239 } else if (G_VALUE_TYPE (src) == GST_TYPE_DOUBLE_RANGE) {
6240 g_value_init (dest, G_TYPE_DOUBLE);
6241 g_value_set_double (dest, gst_value_get_double_range_min (src));
6242 } else if (G_VALUE_TYPE (src) == GST_TYPE_FRACTION_RANGE) {
6243 gst_value_init_and_copy (dest, gst_value_get_fraction_range_min (src));
6244 } else if (G_VALUE_TYPE (src) == GST_TYPE_LIST) {
6245 GValue temp = { 0 };
6246
6247 /* list could be empty */
6248 if (gst_value_list_get_size (src) <= 0)
6249 return FALSE;
6250
6251 gst_value_init_and_copy (&temp, gst_value_list_get_value (src, 0));
6252
6253 if (!gst_value_fixate (dest, &temp)) {
6254 gst_value_move (dest, &temp);
6255 } else {
6256 g_value_unset (&temp);
6257 }
6258 } else if (G_VALUE_TYPE (src) == GST_TYPE_ARRAY) {
6259 gboolean res = FALSE;
6260 guint n, len;
6261
6262 len = gst_value_array_get_size (src);
6263 g_value_init (dest, GST_TYPE_ARRAY);
6264 for (n = 0; n < len; n++) {
6265 GValue kid = { 0 };
6266 const GValue *orig_kid = gst_value_array_get_value (src, n);
6267
6268 if (!gst_value_fixate (&kid, orig_kid))
6269 gst_value_init_and_copy (&kid, orig_kid);
6270 else
6271 res = TRUE;
6272 _gst_value_array_append_and_take_value (dest, &kid);
6273 }
6274
6275 if (!res)
6276 g_value_unset (dest);
6277
6278 return res;
6279 } else if (GST_VALUE_HOLDS_FLAG_SET (src)) {
6280 guint flags;
6281
6282 if (gst_value_get_flagset_mask (src) == GST_FLAG_SET_MASK_EXACT)
6283 return FALSE; /* Already fixed */
6284
6285 flags = gst_value_get_flagset_flags (src);
6286 g_value_init (dest, G_VALUE_TYPE (src));
6287 gst_value_set_flagset (dest, flags, GST_FLAG_SET_MASK_EXACT);
6288 return TRUE;
6289 } else if (GST_VALUE_HOLDS_STRUCTURE (src)) {
6290 const GstStructure *str = (GstStructure *) gst_value_get_structure (src);
6291 GstStructure *kid;
6292
6293 if (!str)
6294 return FALSE;
6295
6296 kid = gst_structure_copy (str);
6297 gst_structure_fixate (kid);
6298 g_value_init (dest, GST_TYPE_STRUCTURE);
6299 gst_value_set_structure (dest, kid);
6300 gst_structure_free (kid);
6301 return TRUE;
6302 } else {
6303 return FALSE;
6304 }
6305 return TRUE;
6306 }
6307
6308
6309 /************
6310 * fraction *
6311 ************/
6312
6313 /* helper functions */
6314 static void
gst_value_init_fraction(GValue * value)6315 gst_value_init_fraction (GValue * value)
6316 {
6317 value->data[0].v_int = 0;
6318 value->data[1].v_int = 1;
6319 }
6320
6321 static void
gst_value_copy_fraction(const GValue * src_value,GValue * dest_value)6322 gst_value_copy_fraction (const GValue * src_value, GValue * dest_value)
6323 {
6324 dest_value->data[0].v_int = src_value->data[0].v_int;
6325 dest_value->data[1].v_int = src_value->data[1].v_int;
6326 }
6327
6328 static gchar *
gst_value_collect_fraction(GValue * value,guint n_collect_values,GTypeCValue * collect_values,guint collect_flags)6329 gst_value_collect_fraction (GValue * value, guint n_collect_values,
6330 GTypeCValue * collect_values, guint collect_flags)
6331 {
6332 if (n_collect_values != 2)
6333 return g_strdup_printf ("not enough value locations for `%s' passed",
6334 G_VALUE_TYPE_NAME (value));
6335 if (collect_values[1].v_int == 0)
6336 return g_strdup_printf ("passed '0' as denominator for `%s'",
6337 G_VALUE_TYPE_NAME (value));
6338 if (collect_values[0].v_int < -G_MAXINT)
6339 return
6340 g_strdup_printf
6341 ("passed value smaller than -G_MAXINT as numerator for `%s'",
6342 G_VALUE_TYPE_NAME (value));
6343 if (collect_values[1].v_int < -G_MAXINT)
6344 return
6345 g_strdup_printf
6346 ("passed value smaller than -G_MAXINT as denominator for `%s'",
6347 G_VALUE_TYPE_NAME (value));
6348
6349 gst_value_set_fraction (value,
6350 collect_values[0].v_int, collect_values[1].v_int);
6351
6352 return NULL;
6353 }
6354
6355 static gchar *
gst_value_lcopy_fraction(const GValue * value,guint n_collect_values,GTypeCValue * collect_values,guint collect_flags)6356 gst_value_lcopy_fraction (const GValue * value, guint n_collect_values,
6357 GTypeCValue * collect_values, guint collect_flags)
6358 {
6359 gint *numerator = collect_values[0].v_pointer;
6360 gint *denominator = collect_values[1].v_pointer;
6361
6362 if (!numerator)
6363 return g_strdup_printf ("numerator for `%s' passed as NULL",
6364 G_VALUE_TYPE_NAME (value));
6365 if (!denominator)
6366 return g_strdup_printf ("denominator for `%s' passed as NULL",
6367 G_VALUE_TYPE_NAME (value));
6368
6369 *numerator = value->data[0].v_int;
6370 *denominator = value->data[1].v_int;
6371
6372 return NULL;
6373 }
6374
6375 /**
6376 * gst_value_set_fraction:
6377 * @value: a GValue initialized to #GST_TYPE_FRACTION
6378 * @numerator: the numerator of the fraction
6379 * @denominator: the denominator of the fraction
6380 *
6381 * Sets @value to the fraction specified by @numerator over @denominator.
6382 * The fraction gets reduced to the smallest numerator and denominator,
6383 * and if necessary the sign is moved to the numerator.
6384 */
6385 void
gst_value_set_fraction(GValue * value,gint numerator,gint denominator)6386 gst_value_set_fraction (GValue * value, gint numerator, gint denominator)
6387 {
6388 gint gcd = 0;
6389
6390 g_return_if_fail (GST_VALUE_HOLDS_FRACTION (value));
6391 g_return_if_fail (denominator != 0);
6392 g_return_if_fail (denominator >= -G_MAXINT);
6393 g_return_if_fail (numerator >= -G_MAXINT);
6394
6395 /* normalize sign */
6396 if (denominator < 0) {
6397 numerator = -numerator;
6398 denominator = -denominator;
6399 }
6400
6401 /* check for reduction */
6402 gcd = gst_util_greatest_common_divisor (numerator, denominator);
6403 if (gcd) {
6404 numerator /= gcd;
6405 denominator /= gcd;
6406 }
6407
6408 g_assert (denominator > 0);
6409
6410 value->data[0].v_int = numerator;
6411 value->data[1].v_int = denominator;
6412 }
6413
6414 /**
6415 * gst_value_get_fraction_numerator:
6416 * @value: a GValue initialized to #GST_TYPE_FRACTION
6417 *
6418 * Gets the numerator of the fraction specified by @value.
6419 *
6420 * Returns: the numerator of the fraction.
6421 */
6422 gint
gst_value_get_fraction_numerator(const GValue * value)6423 gst_value_get_fraction_numerator (const GValue * value)
6424 {
6425 g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 0);
6426
6427 return value->data[0].v_int;
6428 }
6429
6430 /**
6431 * gst_value_get_fraction_denominator:
6432 * @value: a GValue initialized to #GST_TYPE_FRACTION
6433 *
6434 * Gets the denominator of the fraction specified by @value.
6435 *
6436 * Returns: the denominator of the fraction.
6437 */
6438 gint
gst_value_get_fraction_denominator(const GValue * value)6439 gst_value_get_fraction_denominator (const GValue * value)
6440 {
6441 g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 1);
6442
6443 return value->data[1].v_int;
6444 }
6445
6446 /**
6447 * gst_value_fraction_multiply:
6448 * @product: a GValue initialized to #GST_TYPE_FRACTION
6449 * @factor1: a GValue initialized to #GST_TYPE_FRACTION
6450 * @factor2: a GValue initialized to #GST_TYPE_FRACTION
6451 *
6452 * Multiplies the two #GValue items containing a #GST_TYPE_FRACTION and sets
6453 * @product to the product of the two fractions.
6454 *
6455 * Returns: %FALSE in case of an error (like integer overflow), %TRUE otherwise.
6456 */
6457 gboolean
gst_value_fraction_multiply(GValue * product,const GValue * factor1,const GValue * factor2)6458 gst_value_fraction_multiply (GValue * product, const GValue * factor1,
6459 const GValue * factor2)
6460 {
6461 gint n1, n2, d1, d2;
6462 gint res_n, res_d;
6463
6464 g_return_val_if_fail (product != NULL, FALSE);
6465 g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor1), FALSE);
6466 g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor2), FALSE);
6467
6468 n1 = factor1->data[0].v_int;
6469 n2 = factor2->data[0].v_int;
6470 d1 = factor1->data[1].v_int;
6471 d2 = factor2->data[1].v_int;
6472
6473 if (!gst_util_fraction_multiply (n1, d1, n2, d2, &res_n, &res_d))
6474 return FALSE;
6475
6476 gst_value_set_fraction (product, res_n, res_d);
6477
6478 return TRUE;
6479 }
6480
6481 /**
6482 * gst_value_fraction_subtract:
6483 * @dest: a GValue initialized to #GST_TYPE_FRACTION
6484 * @minuend: a GValue initialized to #GST_TYPE_FRACTION
6485 * @subtrahend: a GValue initialized to #GST_TYPE_FRACTION
6486 *
6487 * Subtracts the @subtrahend from the @minuend and sets @dest to the result.
6488 *
6489 * Returns: %FALSE in case of an error (like integer overflow), %TRUE otherwise.
6490 */
6491 gboolean
gst_value_fraction_subtract(GValue * dest,const GValue * minuend,const GValue * subtrahend)6492 gst_value_fraction_subtract (GValue * dest,
6493 const GValue * minuend, const GValue * subtrahend)
6494 {
6495 gint n1, n2, d1, d2;
6496 gint res_n, res_d;
6497
6498 g_return_val_if_fail (dest != NULL, FALSE);
6499 g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (minuend), FALSE);
6500 g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (subtrahend), FALSE);
6501
6502 n1 = minuend->data[0].v_int;
6503 n2 = subtrahend->data[0].v_int;
6504 d1 = minuend->data[1].v_int;
6505 d2 = subtrahend->data[1].v_int;
6506
6507 if (!gst_util_fraction_add (n1, d1, -n2, d2, &res_n, &res_d))
6508 return FALSE;
6509 gst_value_set_fraction (dest, res_n, res_d);
6510
6511 return TRUE;
6512 }
6513
6514 static gchar *
gst_value_serialize_fraction(const GValue * value)6515 gst_value_serialize_fraction (const GValue * value)
6516 {
6517 gint32 numerator = value->data[0].v_int;
6518 gint32 denominator = value->data[1].v_int;
6519 gboolean positive = TRUE;
6520
6521 /* get the sign and make components absolute */
6522 if (numerator < 0) {
6523 numerator = -numerator;
6524 positive = !positive;
6525 }
6526 if (denominator < 0) {
6527 denominator = -denominator;
6528 positive = !positive;
6529 }
6530
6531 return g_strdup_printf ("%s%d/%d",
6532 positive ? "" : "-", numerator, denominator);
6533 }
6534
6535 static gboolean
gst_value_deserialize_fraction(GValue * dest,const gchar * s)6536 gst_value_deserialize_fraction (GValue * dest, const gchar * s)
6537 {
6538 gint num, den;
6539 gint num_chars;
6540
6541 if (G_UNLIKELY (s == NULL))
6542 return FALSE;
6543
6544 if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_FRACTION (dest)))
6545 return FALSE;
6546
6547 if (sscanf (s, "%d/%d%n", &num, &den, &num_chars) >= 2) {
6548 if (s[num_chars] != 0)
6549 return FALSE;
6550 if (den == 0)
6551 return FALSE;
6552
6553 gst_value_set_fraction (dest, num, den);
6554 return TRUE;
6555 } else if (g_ascii_strcasecmp (s, "1/max") == 0) {
6556 gst_value_set_fraction (dest, 1, G_MAXINT);
6557 return TRUE;
6558 } else if (sscanf (s, "%d%n", &num, &num_chars) >= 1) {
6559 if (s[num_chars] != 0)
6560 return FALSE;
6561 gst_value_set_fraction (dest, num, 1);
6562 return TRUE;
6563 } else if (g_ascii_strcasecmp (s, "min") == 0) {
6564 gst_value_set_fraction (dest, -G_MAXINT, 1);
6565 return TRUE;
6566 } else if (g_ascii_strcasecmp (s, "max") == 0) {
6567 gst_value_set_fraction (dest, G_MAXINT, 1);
6568 return TRUE;
6569 }
6570
6571 return FALSE;
6572 }
6573
6574 static void
gst_value_transform_fraction_string(const GValue * src_value,GValue * dest_value)6575 gst_value_transform_fraction_string (const GValue * src_value,
6576 GValue * dest_value)
6577 {
6578 dest_value->data[0].v_pointer = gst_value_serialize_fraction (src_value);
6579 }
6580
6581 static void
gst_value_transform_string_fraction(const GValue * src_value,GValue * dest_value)6582 gst_value_transform_string_fraction (const GValue * src_value,
6583 GValue * dest_value)
6584 {
6585 if (!gst_value_deserialize_fraction (dest_value,
6586 src_value->data[0].v_pointer))
6587 /* If the deserialize fails, ensure we leave the fraction in a
6588 * valid, if incorrect, state */
6589 gst_value_set_fraction (dest_value, 0, 1);
6590 }
6591
6592 static void
gst_value_transform_double_fraction(const GValue * src_value,GValue * dest_value)6593 gst_value_transform_double_fraction (const GValue * src_value,
6594 GValue * dest_value)
6595 {
6596 gdouble src = g_value_get_double (src_value);
6597 gint n, d;
6598
6599 gst_util_double_to_fraction (src, &n, &d);
6600 gst_value_set_fraction (dest_value, n, d);
6601 }
6602
6603 static void
gst_value_transform_float_fraction(const GValue * src_value,GValue * dest_value)6604 gst_value_transform_float_fraction (const GValue * src_value,
6605 GValue * dest_value)
6606 {
6607 gfloat src = g_value_get_float (src_value);
6608 gint n, d;
6609
6610 gst_util_double_to_fraction (src, &n, &d);
6611 gst_value_set_fraction (dest_value, n, d);
6612 }
6613
6614 static void
gst_value_transform_fraction_double(const GValue * src_value,GValue * dest_value)6615 gst_value_transform_fraction_double (const GValue * src_value,
6616 GValue * dest_value)
6617 {
6618 dest_value->data[0].v_double = ((double) src_value->data[0].v_int) /
6619 ((double) src_value->data[1].v_int);
6620 }
6621
6622 static void
gst_value_transform_fraction_float(const GValue * src_value,GValue * dest_value)6623 gst_value_transform_fraction_float (const GValue * src_value,
6624 GValue * dest_value)
6625 {
6626 dest_value->data[0].v_float = ((float) src_value->data[0].v_int) /
6627 ((float) src_value->data[1].v_int);
6628 }
6629
6630 static gint
gst_value_compare_fraction(const GValue * value1,const GValue * value2)6631 gst_value_compare_fraction (const GValue * value1, const GValue * value2)
6632 {
6633 gint n1, n2;
6634 gint d1, d2;
6635 gint ret;
6636
6637 n1 = value1->data[0].v_int;
6638 n2 = value2->data[0].v_int;
6639 d1 = value1->data[1].v_int;
6640 d2 = value2->data[1].v_int;
6641
6642 /* fractions are reduced when set, so we can quickly see if they're equal */
6643 if (n1 == n2 && d1 == d2)
6644 return GST_VALUE_EQUAL;
6645
6646 if (d1 == 0 && d2 == 0)
6647 return GST_VALUE_UNORDERED;
6648 else if (d1 == 0)
6649 return GST_VALUE_GREATER_THAN;
6650 else if (d2 == 0)
6651 return GST_VALUE_LESS_THAN;
6652
6653 ret = gst_util_fraction_compare (n1, d1, n2, d2);
6654 if (ret == -1)
6655 return GST_VALUE_LESS_THAN;
6656 else if (ret == 1)
6657 return GST_VALUE_GREATER_THAN;
6658
6659 /* Equality can't happen here because we check for that
6660 * first already */
6661 g_return_val_if_reached (GST_VALUE_UNORDERED);
6662 }
6663
6664 /*********
6665 * GDate *
6666 *********/
6667
6668 static gint
gst_value_compare_date(const GValue * value1,const GValue * value2)6669 gst_value_compare_date (const GValue * value1, const GValue * value2)
6670 {
6671 const GDate *date1 = (const GDate *) g_value_get_boxed (value1);
6672 const GDate *date2 = (const GDate *) g_value_get_boxed (value2);
6673 guint32 j1, j2;
6674
6675 if (date1 == date2)
6676 return GST_VALUE_EQUAL;
6677
6678 if ((date1 == NULL || !g_date_valid (date1))
6679 && (date2 != NULL && g_date_valid (date2))) {
6680 return GST_VALUE_LESS_THAN;
6681 }
6682
6683 if ((date2 == NULL || !g_date_valid (date2))
6684 && (date1 != NULL && g_date_valid (date1))) {
6685 return GST_VALUE_GREATER_THAN;
6686 }
6687
6688 if (date1 == NULL || date2 == NULL || !g_date_valid (date1)
6689 || !g_date_valid (date2)) {
6690 return GST_VALUE_UNORDERED;
6691 }
6692
6693 j1 = g_date_get_julian (date1);
6694 j2 = g_date_get_julian (date2);
6695
6696 if (j1 == j2)
6697 return GST_VALUE_EQUAL;
6698 else if (j1 < j2)
6699 return GST_VALUE_LESS_THAN;
6700 else
6701 return GST_VALUE_GREATER_THAN;
6702 }
6703
6704 static gchar *
gst_value_serialize_date(const GValue * val)6705 gst_value_serialize_date (const GValue * val)
6706 {
6707 const GDate *date = (const GDate *) g_value_get_boxed (val);
6708
6709 if (date == NULL || !g_date_valid (date))
6710 return g_strdup ("9999-99-99");
6711
6712 return g_strdup_printf ("%04u-%02u-%02u", g_date_get_year (date),
6713 g_date_get_month (date), g_date_get_day (date));
6714 }
6715
6716 static gboolean
gst_value_deserialize_date(GValue * dest,const gchar * s)6717 gst_value_deserialize_date (GValue * dest, const gchar * s)
6718 {
6719 guint year, month, day;
6720
6721 if (!s || sscanf (s, "%04u-%02u-%02u", &year, &month, &day) != 3)
6722 return FALSE;
6723
6724 if (!g_date_valid_dmy (day, month, year))
6725 return FALSE;
6726
6727 g_value_take_boxed (dest, g_date_new_dmy (day, month, year));
6728 return TRUE;
6729 }
6730
6731 /*************
6732 * GstDateTime *
6733 *************/
6734
6735 static gint
gst_value_compare_date_time(const GValue * value1,const GValue * value2)6736 gst_value_compare_date_time (const GValue * value1, const GValue * value2)
6737 {
6738 const GstDateTime *date1 = (const GstDateTime *) g_value_get_boxed (value1);
6739 const GstDateTime *date2 = (const GstDateTime *) g_value_get_boxed (value2);
6740
6741 if (date1 == date2)
6742 return GST_VALUE_EQUAL;
6743
6744 if ((date1 == NULL) && (date2 != NULL)) {
6745 return GST_VALUE_LESS_THAN;
6746 }
6747 if ((date2 == NULL) && (date1 != NULL)) {
6748 return GST_VALUE_LESS_THAN;
6749 }
6750
6751 /* returns GST_VALUE_* */
6752 return __gst_date_time_compare (date1, date2);
6753 }
6754
6755 static gchar *
gst_value_serialize_date_time(const GValue * val)6756 gst_value_serialize_date_time (const GValue * val)
6757 {
6758 GstDateTime *date = (GstDateTime *) g_value_get_boxed (val);
6759
6760 if (date == NULL)
6761 return g_strdup ("null");
6762
6763 return __gst_date_time_serialize (date, TRUE);
6764 }
6765
6766 static gboolean
gst_value_deserialize_date_time(GValue * dest,const gchar * s)6767 gst_value_deserialize_date_time (GValue * dest, const gchar * s)
6768 {
6769 GstDateTime *datetime;
6770
6771 if (!s || strcmp (s, "null") == 0) {
6772 return FALSE;
6773 }
6774
6775 datetime = gst_date_time_new_from_iso8601_string (s);
6776 if (datetime != NULL) {
6777 g_value_take_boxed (dest, datetime);
6778 return TRUE;
6779 }
6780 GST_WARNING ("Failed to deserialize date time string '%s'", s);
6781 return FALSE;
6782 }
6783
6784 static void
gst_value_transform_date_string(const GValue * src_value,GValue * dest_value)6785 gst_value_transform_date_string (const GValue * src_value, GValue * dest_value)
6786 {
6787 dest_value->data[0].v_pointer = gst_value_serialize_date (src_value);
6788 }
6789
6790 static void
gst_value_transform_string_date(const GValue * src_value,GValue * dest_value)6791 gst_value_transform_string_date (const GValue * src_value, GValue * dest_value)
6792 {
6793 gst_value_deserialize_date (dest_value, src_value->data[0].v_pointer);
6794 }
6795
6796
6797 /************
6798 * bitmask *
6799 ************/
6800
6801 /* helper functions */
6802 static void
gst_value_init_bitmask(GValue * value)6803 gst_value_init_bitmask (GValue * value)
6804 {
6805 value->data[0].v_uint64 = 0;
6806 }
6807
6808 static void
gst_value_copy_bitmask(const GValue * src_value,GValue * dest_value)6809 gst_value_copy_bitmask (const GValue * src_value, GValue * dest_value)
6810 {
6811 dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
6812 }
6813
6814 static gchar *
gst_value_collect_bitmask(GValue * value,guint n_collect_values,GTypeCValue * collect_values,guint collect_flags)6815 gst_value_collect_bitmask (GValue * value, guint n_collect_values,
6816 GTypeCValue * collect_values, guint collect_flags)
6817 {
6818 if (n_collect_values != 1)
6819 return g_strdup_printf ("not enough value locations for `%s' passed",
6820 G_VALUE_TYPE_NAME (value));
6821
6822 gst_value_set_bitmask (value, (guint64) collect_values[0].v_int64);
6823
6824 return NULL;
6825 }
6826
6827 static gchar *
gst_value_lcopy_bitmask(const GValue * value,guint n_collect_values,GTypeCValue * collect_values,guint collect_flags)6828 gst_value_lcopy_bitmask (const GValue * value, guint n_collect_values,
6829 GTypeCValue * collect_values, guint collect_flags)
6830 {
6831 guint64 *bitmask = collect_values[0].v_pointer;
6832
6833 if (!bitmask)
6834 return g_strdup_printf ("value for `%s' passed as NULL",
6835 G_VALUE_TYPE_NAME (value));
6836
6837 *bitmask = value->data[0].v_uint64;
6838
6839 return NULL;
6840 }
6841
6842 /**
6843 * gst_value_set_bitmask:
6844 * @value: a GValue initialized to #GST_TYPE_BITMASK
6845 * @bitmask: the bitmask
6846 *
6847 * Sets @value to the bitmask specified by @bitmask.
6848 */
6849 void
gst_value_set_bitmask(GValue * value,guint64 bitmask)6850 gst_value_set_bitmask (GValue * value, guint64 bitmask)
6851 {
6852 g_return_if_fail (GST_VALUE_HOLDS_BITMASK (value));
6853
6854 value->data[0].v_uint64 = bitmask;
6855 }
6856
6857 /**
6858 * gst_value_get_bitmask:
6859 * @value: a GValue initialized to #GST_TYPE_BITMASK
6860 *
6861 * Gets the bitmask specified by @value.
6862 *
6863 * Returns: the bitmask.
6864 */
6865 guint64
gst_value_get_bitmask(const GValue * value)6866 gst_value_get_bitmask (const GValue * value)
6867 {
6868 g_return_val_if_fail (GST_VALUE_HOLDS_BITMASK (value), 0);
6869
6870 return value->data[0].v_uint64;
6871 }
6872
6873 static gchar *
gst_value_serialize_bitmask(const GValue * value)6874 gst_value_serialize_bitmask (const GValue * value)
6875 {
6876 guint64 bitmask = value->data[0].v_uint64;
6877
6878 return g_strdup_printf ("0x%016" G_GINT64_MODIFIER "x", bitmask);
6879 }
6880
6881 static gboolean
gst_value_deserialize_bitmask(GValue * dest,const gchar * s)6882 gst_value_deserialize_bitmask (GValue * dest, const gchar * s)
6883 {
6884 gchar *endptr = NULL;
6885 guint64 val;
6886
6887 if (G_UNLIKELY (s == NULL))
6888 return FALSE;
6889
6890 if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_BITMASK (dest)))
6891 return FALSE;
6892
6893 errno = 0;
6894 val = g_ascii_strtoull (s, &endptr, 16);
6895 if (val == G_MAXUINT64 && (errno == ERANGE || errno == EINVAL))
6896 return FALSE;
6897 if (val == 0 && endptr == s)
6898 return FALSE;
6899
6900 gst_value_set_bitmask (dest, val);
6901
6902 return TRUE;
6903 }
6904
6905 static void
gst_value_transform_bitmask_string(const GValue * src_value,GValue * dest_value)6906 gst_value_transform_bitmask_string (const GValue * src_value,
6907 GValue * dest_value)
6908 {
6909 dest_value->data[0].v_pointer = gst_value_serialize_bitmask (src_value);
6910 }
6911
6912 static void
gst_value_transform_string_bitmask(const GValue * src_value,GValue * dest_value)6913 gst_value_transform_string_bitmask (const GValue * src_value,
6914 GValue * dest_value)
6915 {
6916 if (!gst_value_deserialize_bitmask (dest_value, src_value->data[0].v_pointer))
6917 gst_value_set_bitmask (dest_value, 0);
6918 }
6919
6920 static void
gst_value_transform_uint64_bitmask(const GValue * src_value,GValue * dest_value)6921 gst_value_transform_uint64_bitmask (const GValue * src_value,
6922 GValue * dest_value)
6923 {
6924 dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
6925 }
6926
6927 static void
gst_value_transform_bitmask_uint64(const GValue * src_value,GValue * dest_value)6928 gst_value_transform_bitmask_uint64 (const GValue * src_value,
6929 GValue * dest_value)
6930 {
6931 dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
6932 }
6933
6934 static gint
gst_value_compare_bitmask(const GValue * value1,const GValue * value2)6935 gst_value_compare_bitmask (const GValue * value1, const GValue * value2)
6936 {
6937 guint64 v1, v2;
6938
6939 v1 = value1->data[0].v_uint64;
6940 v2 = value2->data[0].v_uint64;
6941
6942 if (v1 == v2)
6943 return GST_VALUE_EQUAL;
6944
6945 return GST_VALUE_UNORDERED;
6946 }
6947
6948 /************
6949 * flagset *
6950 ************/
6951
6952 /* helper functions */
6953 static void
gst_value_init_flagset(GValue * value)6954 gst_value_init_flagset (GValue * value)
6955 {
6956 value->data[0].v_uint = 0;
6957 value->data[1].v_uint = 0;
6958 }
6959
6960 static void
gst_value_copy_flagset(const GValue * src_value,GValue * dest_value)6961 gst_value_copy_flagset (const GValue * src_value, GValue * dest_value)
6962 {
6963 dest_value->data[0].v_uint = src_value->data[0].v_uint;
6964 dest_value->data[1].v_uint = src_value->data[1].v_uint;
6965 }
6966
6967 static gchar *
gst_value_collect_flagset(GValue * value,guint n_collect_values,GTypeCValue * collect_values,guint collect_flags)6968 gst_value_collect_flagset (GValue * value, guint n_collect_values,
6969 GTypeCValue * collect_values, guint collect_flags)
6970 {
6971 if (n_collect_values != 2)
6972 return g_strdup_printf ("not enough value locations for `%s' passed",
6973 G_VALUE_TYPE_NAME (value));
6974
6975 gst_value_set_flagset (value,
6976 (guint) collect_values[0].v_int, (guint) collect_values[1].v_int);
6977
6978 return NULL;
6979 }
6980
6981 static gchar *
gst_value_lcopy_flagset(const GValue * value,guint n_collect_values,GTypeCValue * collect_values,guint collect_flags)6982 gst_value_lcopy_flagset (const GValue * value, guint n_collect_values,
6983 GTypeCValue * collect_values, guint collect_flags)
6984 {
6985 guint *flags = collect_values[0].v_pointer;
6986 guint *mask = collect_values[1].v_pointer;
6987
6988 *flags = value->data[0].v_uint;
6989 *mask = value->data[1].v_uint;
6990
6991 return NULL;
6992 }
6993
6994 /**
6995 * gst_value_set_flagset:
6996 * @value: a GValue initialized to %GST_TYPE_FLAG_SET
6997 * @flags: The value of the flags set or unset
6998 * @mask: The mask indicate which flags bits must match for comparisons
6999 *
7000 * Sets @value to the flags and mask values provided in @flags and @mask.
7001 * The @flags value indicates the values of flags, the @mask represents
7002 * which bits in the flag value have been set, and which are "don't care"
7003 *
7004 * Since: 1.6
7005 */
7006 void
gst_value_set_flagset(GValue * value,guint flags,guint mask)7007 gst_value_set_flagset (GValue * value, guint flags, guint mask)
7008 {
7009 g_return_if_fail (GST_VALUE_HOLDS_FLAG_SET (value));
7010
7011 /* Normalise and only keep flags mentioned in the mask */
7012 value->data[0].v_uint = flags & mask;
7013 value->data[1].v_uint = mask;
7014 }
7015
7016 /**
7017 * gst_value_get_flagset_flags:
7018 * @value: a GValue initialized to #GST_TYPE_FLAG_SET
7019 *
7020 * Retrieve the flags field of a GstFlagSet @value.
7021 *
7022 * Returns: the flags field of the flagset instance.
7023 *
7024 * Since: 1.6
7025 */
7026 guint
gst_value_get_flagset_flags(const GValue * value)7027 gst_value_get_flagset_flags (const GValue * value)
7028 {
7029 g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (value), 0);
7030
7031 return value->data[0].v_uint;
7032 }
7033
7034 /**
7035 * gst_value_get_flagset_mask:
7036 * @value: a GValue initialized to #GST_TYPE_FLAG_SET
7037 *
7038 * Retrieve the mask field of a GstFlagSet @value.
7039 *
7040 * Returns: the mask field of the flagset instance.
7041 *
7042 * Since: 1.6
7043 */
7044 guint
gst_value_get_flagset_mask(const GValue * value)7045 gst_value_get_flagset_mask (const GValue * value)
7046 {
7047 g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (value), 1);
7048
7049 return value->data[1].v_uint;
7050 }
7051
7052 static gchar *
gst_value_serialize_flagset(const GValue * value)7053 gst_value_serialize_flagset (const GValue * value)
7054 {
7055 guint flags = value->data[0].v_uint;
7056 guint mask = value->data[1].v_uint;
7057 GstFlagSetClass *set_klass =
7058 (GstFlagSetClass *) g_type_class_ref (G_VALUE_TYPE (value));
7059 gchar *result;
7060
7061 result = g_strdup_printf ("%x:%x", flags, mask);
7062
7063 /* If this flag set class has an associated GFlags GType, and some
7064 * bits in the mask, serialize the bits in human-readable form to
7065 * aid debugging */
7066 if (mask && set_klass->flags_type) {
7067 GFlagsClass *flags_klass =
7068 (GFlagsClass *) (g_type_class_ref (set_klass->flags_type));
7069 GFlagsValue *fl;
7070 gchar *tmp;
7071 gboolean first = TRUE;
7072
7073 g_return_val_if_fail (flags_klass, NULL);
7074
7075 /* some bits in the mask are set, so serialize one by one, according
7076 * to whether that bit is set or cleared in the flags value */
7077 while (mask) {
7078 fl = g_flags_get_first_value (flags_klass, mask);
7079 if (fl == NULL) {
7080 /* No more bits match in the flags mask - time to stop */
7081 mask = 0;
7082 break;
7083 }
7084
7085 tmp = g_strconcat (result,
7086 first ? ":" : "",
7087 (flags & fl->value) ? "+" : "/", fl->value_nick, NULL);
7088 g_free (result);
7089 result = tmp;
7090 first = FALSE;
7091
7092 /* clear flag */
7093 mask &= ~fl->value;
7094 }
7095 g_type_class_unref (flags_klass);
7096
7097 }
7098 g_type_class_unref (set_klass);
7099
7100 return result;
7101 }
7102
7103 static gboolean
is_valid_flags_string(const gchar * s)7104 is_valid_flags_string (const gchar * s)
7105 {
7106 /* We're looking to match +this/that+other-thing/not-this-thing type strings */
7107 return g_regex_match_simple ("^([\\+\\/][\\w\\d-]+)+$", s, G_REGEX_CASELESS,
7108 0);
7109 }
7110
7111 static gboolean
gst_value_deserialize_flagset(GValue * dest,const gchar * s)7112 gst_value_deserialize_flagset (GValue * dest, const gchar * s)
7113 {
7114 gboolean res = FALSE;
7115 guint flags, mask;
7116 gchar *cur, *next;
7117
7118 if (G_UNLIKELY (s == NULL))
7119 return FALSE;
7120
7121 if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_FLAG_SET (dest)))
7122 return FALSE;
7123
7124 /* Flagset strings look like %x:%x - hex flags : hex bitmask,
7125 * 32-bit each, or like a concatenated list of flag nicks,
7126 * with either '+' or '/' in front. The first form
7127 * may optionally be followed by ':' and a set of text flag descriptions
7128 * for easier debugging */
7129
7130 /* Try and interpret as hex form first, as it's the most efficient */
7131 /* Read the flags first */
7132 flags = strtoul (s, &next, 16);
7133 if (G_UNLIKELY ((flags == 0 && errno == EINVAL) || s == next))
7134 goto try_as_flags_string;
7135 /* Next char should be a colon */
7136 if (next[0] == ':')
7137 next++;
7138
7139 /* Read the mask */
7140 cur = next;
7141 mask = strtoul (cur, &next, 16);
7142 if (G_UNLIKELY ((mask == 0 && errno == EINVAL) || cur == next))
7143 goto try_as_flags_string;
7144
7145 /* Next char should be NULL terminator, or a ':'. If ':', we need the flag string after */
7146 if (G_UNLIKELY (next[0] == 0)) {
7147 res = TRUE;
7148 goto done;
7149 }
7150
7151 if (next[0] != ':')
7152 return FALSE;
7153
7154 s = next + 1;
7155
7156 if (g_str_equal (g_type_name (G_VALUE_TYPE (dest)), "GstFlagSet")) {
7157 /* If we're parsing a generic flag set, that can mean we're guessing
7158 * at the type in deserialising a GstStructure so at least check that
7159 * we have a valid-looking string, so we don't cause deserialisation of
7160 * other types of strings like 00:01:00:00 - https://bugzilla.gnome.org/show_bug.cgi?id=779755 */
7161 if (is_valid_flags_string (s)) {
7162 res = TRUE;
7163 goto done;
7164 }
7165 return FALSE;
7166 }
7167
7168 /* Otherwise, we already got a hex string for a valid non-generic flagset type */
7169 res = TRUE;
7170 goto done;
7171
7172 try_as_flags_string:
7173
7174 {
7175 const gchar *set_class = g_type_name (G_VALUE_TYPE (dest));
7176 GFlagsClass *flags_klass = NULL;
7177 const gchar *end;
7178
7179 if (g_str_equal (set_class, "GstFlagSet")) {
7180 /* There's no hope to parse the fields of generic flag set if we didn't already
7181 * catch a hex-string above */
7182 return FALSE;
7183 }
7184
7185 /* Flags class is the FlagSet class with 'Set' removed from the end */
7186 end = g_strrstr (set_class, "Set");
7187
7188 if (end != NULL) {
7189 gchar *class_name = g_strndup (set_class, end - set_class);
7190 GType flags_type = g_type_from_name (class_name);
7191 if (flags_type == 0) {
7192 GST_TRACE ("Looking for dynamic type %s", class_name);
7193 gst_dynamic_type_factory_load (class_name);
7194 }
7195
7196 if (flags_type != 0) {
7197 flags_klass = g_type_class_ref (flags_type);
7198 GST_TRACE ("Going to parse %s as %s", s, class_name);
7199 }
7200 g_free (class_name);
7201 }
7202
7203 if (flags_klass) {
7204 res = gst_value_gflags_str_to_flags (flags_klass, s, &flags, &mask);
7205 g_type_class_unref (flags_klass);
7206 }
7207 }
7208
7209 done:
7210 if (res)
7211 gst_value_set_flagset (dest, flags, mask);
7212 return res;
7213
7214 }
7215
7216 static void
gst_value_transform_flagset_string(const GValue * src_value,GValue * dest_value)7217 gst_value_transform_flagset_string (const GValue * src_value,
7218 GValue * dest_value)
7219 {
7220 dest_value->data[0].v_pointer = gst_value_serialize_flagset (src_value);
7221 }
7222
7223 static void
gst_value_transform_string_flagset(const GValue * src_value,GValue * dest_value)7224 gst_value_transform_string_flagset (const GValue * src_value,
7225 GValue * dest_value)
7226 {
7227 if (!gst_value_deserialize_flagset (dest_value, src_value->data[0].v_pointer)) {
7228 /* If the deserialize fails, ensure we leave the flags in a
7229 * valid, if incorrect, state */
7230 gst_value_set_flagset (dest_value, 0, 0);
7231 }
7232 }
7233
7234 static gint
gst_value_compare_flagset(const GValue * value1,const GValue * value2)7235 gst_value_compare_flagset (const GValue * value1, const GValue * value2)
7236 {
7237 guint v1, v2;
7238 guint m1, m2;
7239
7240 v1 = value1->data[0].v_uint;
7241 v2 = value2->data[0].v_uint;
7242
7243 m1 = value1->data[1].v_uint;
7244 m2 = value2->data[1].v_uint;
7245
7246 if (v1 == v2 && m1 == m2)
7247 return GST_VALUE_EQUAL;
7248
7249 return GST_VALUE_UNORDERED;
7250 }
7251
7252 /***********************
7253 * GstAllocationParams *
7254 ***********************/
7255 static gint
gst_value_compare_allocation_params(const GValue * value1,const GValue * value2)7256 gst_value_compare_allocation_params (const GValue * value1,
7257 const GValue * value2)
7258 {
7259 GstAllocationParams *v1, *v2;
7260
7261 v1 = value1->data[0].v_pointer;
7262 v2 = value2->data[0].v_pointer;
7263
7264 if (v1 == NULL && v1 == v2)
7265 return GST_VALUE_EQUAL;
7266
7267 if (v1 == NULL || v2 == NULL)
7268 return GST_VALUE_UNORDERED;
7269
7270 if (v1->flags == v2->flags && v1->align == v2->align &&
7271 v1->prefix == v2->prefix && v1->padding == v2->padding)
7272 return GST_VALUE_EQUAL;
7273
7274 return GST_VALUE_UNORDERED;
7275 }
7276
7277
7278 /************
7279 * GObject *
7280 ************/
7281
7282 static gint
gst_value_compare_object(const GValue * value1,const GValue * value2)7283 gst_value_compare_object (const GValue * value1, const GValue * value2)
7284 {
7285 gpointer v1, v2;
7286
7287 v1 = value1->data[0].v_pointer;
7288 v2 = value2->data[0].v_pointer;
7289
7290 if (v1 == v2)
7291 return GST_VALUE_EQUAL;
7292
7293 return GST_VALUE_UNORDERED;
7294 }
7295
7296 static void
gst_value_transform_object_string(const GValue * src_value,GValue * dest_value)7297 gst_value_transform_object_string (const GValue * src_value,
7298 GValue * dest_value)
7299 {
7300 GstObject *obj;
7301 gchar *str;
7302
7303 obj = g_value_get_object (src_value);
7304 if (obj) {
7305 str =
7306 g_strdup_printf ("(%s) %s", G_OBJECT_TYPE_NAME (obj),
7307 GST_OBJECT_NAME (obj));
7308 } else {
7309 str = g_strdup ("NULL");
7310 }
7311
7312 dest_value->data[0].v_pointer = str;
7313 }
7314
7315 static GTypeInfo _info = {
7316 0, NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, NULL,
7317 };
7318
7319 static GTypeFundamentalInfo _finfo = {
7320 0
7321 };
7322
7323 #define FUNC_VALUE_GET_TYPE_CLASSED(type, name, csize, flags) \
7324 GType _gst_ ## type ## _type = 0; \
7325 \
7326 GType gst_ ## type ## _get_type (void) \
7327 { \
7328 static volatile GType gst_ ## type ## _type = 0; \
7329 \
7330 if (g_once_init_enter (&gst_ ## type ## _type)) { \
7331 GType _type; \
7332 _info.class_size = csize; \
7333 _finfo.type_flags = flags; \
7334 _info.value_table = & _gst_ ## type ## _value_table; \
7335 _type = g_type_register_fundamental ( \
7336 g_type_fundamental_next (), \
7337 name, &_info, &_finfo, 0); \
7338 _gst_ ## type ## _type = _type; \
7339 g_once_init_leave(&gst_ ## type ## _type, _type); \
7340 } \
7341 \
7342 return gst_ ## type ## _type; \
7343 }
7344
7345 #define FUNC_VALUE_GET_TYPE(type, name) \
7346 FUNC_VALUE_GET_TYPE_CLASSED(type, name, 0, 0)
7347
7348 static const GTypeValueTable _gst_int_range_value_table = {
7349 gst_value_init_int_range,
7350 NULL,
7351 gst_value_copy_int_range,
7352 NULL,
7353 (char *) "ii",
7354 gst_value_collect_int_range, (char *) "pp", gst_value_lcopy_int_range
7355 };
7356
7357 FUNC_VALUE_GET_TYPE (int_range, "GstIntRange");
7358
7359 static const GTypeValueTable _gst_int64_range_value_table = {
7360 gst_value_init_int64_range,
7361 gst_value_free_int64_range,
7362 gst_value_copy_int64_range,
7363 NULL,
7364 (char *) "qq",
7365 gst_value_collect_int64_range,
7366 (char *) "pp", gst_value_lcopy_int64_range
7367 };
7368
7369 FUNC_VALUE_GET_TYPE (int64_range, "GstInt64Range");
7370
7371 static const GTypeValueTable _gst_double_range_value_table = {
7372 gst_value_init_double_range,
7373 NULL,
7374 gst_value_copy_double_range,
7375 NULL,
7376 (char *) "dd",
7377 gst_value_collect_double_range,
7378 (char *) "pp", gst_value_lcopy_double_range
7379 };
7380
7381 FUNC_VALUE_GET_TYPE (double_range, "GstDoubleRange");
7382
7383 static const GTypeValueTable _gst_fraction_range_value_table = {
7384 gst_value_init_fraction_range,
7385 gst_value_free_fraction_range,
7386 gst_value_copy_fraction_range,
7387 NULL,
7388 (char *) "iiii",
7389 gst_value_collect_fraction_range,
7390 (char *) "pppp", gst_value_lcopy_fraction_range
7391 };
7392
7393 FUNC_VALUE_GET_TYPE (fraction_range, "GstFractionRange");
7394
7395 static const GTypeValueTable _gst_value_list_value_table = {
7396 gst_value_init_list_or_array,
7397 gst_value_free_list_or_array,
7398 gst_value_copy_list_or_array,
7399 gst_value_list_or_array_peek_pointer,
7400 (char *) "p",
7401 gst_value_collect_list_or_array,
7402 (char *) "p", gst_value_lcopy_list_or_array
7403 };
7404
7405 FUNC_VALUE_GET_TYPE (value_list, "GstValueList");
7406
7407 static const GTypeValueTable _gst_value_array_value_table = {
7408 gst_value_init_list_or_array,
7409 gst_value_free_list_or_array,
7410 gst_value_copy_list_or_array,
7411 gst_value_list_or_array_peek_pointer,
7412 (char *) "p",
7413 gst_value_collect_list_or_array,
7414 (char *) "p", gst_value_lcopy_list_or_array
7415 };
7416
7417 FUNC_VALUE_GET_TYPE (value_array, "GstValueArray");
7418
7419 static const GTypeValueTable _gst_fraction_value_table = {
7420 gst_value_init_fraction,
7421 NULL,
7422 gst_value_copy_fraction,
7423 NULL,
7424 (char *) "ii",
7425 gst_value_collect_fraction, (char *) "pp", gst_value_lcopy_fraction
7426 };
7427
7428 FUNC_VALUE_GET_TYPE (fraction, "GstFraction");
7429
7430 static const GTypeValueTable _gst_bitmask_value_table = {
7431 gst_value_init_bitmask,
7432 NULL,
7433 gst_value_copy_bitmask,
7434 NULL,
7435 (char *) "q",
7436 gst_value_collect_bitmask, (char *) "p", gst_value_lcopy_bitmask
7437 };
7438
7439 FUNC_VALUE_GET_TYPE (bitmask, "GstBitmask");
7440
7441 static const GTypeValueTable _gst_flagset_value_table = {
7442 gst_value_init_flagset,
7443 NULL,
7444 gst_value_copy_flagset,
7445 NULL,
7446 (char *) "ii",
7447 gst_value_collect_flagset, (char *) "pp", gst_value_lcopy_flagset
7448 };
7449
7450 FUNC_VALUE_GET_TYPE_CLASSED (flagset, "GstFlagSet",
7451 sizeof (GstFlagSetClass), G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_DERIVABLE);
7452
7453 GType
gst_g_thread_get_type(void)7454 gst_g_thread_get_type (void)
7455 {
7456 return G_TYPE_THREAD;
7457 }
7458
7459 #define SERIAL_VTABLE(t,c,s,d) { t, c, s, d }
7460
7461 #define REGISTER_SERIALIZATION_CONST(_gtype, _type) \
7462 G_STMT_START { \
7463 static const GstValueTable gst_value = \
7464 SERIAL_VTABLE (_gtype, gst_value_compare_ ## _type, \
7465 gst_value_serialize_ ## _type, gst_value_deserialize_ ## _type); \
7466 gst_value_register (&gst_value); \
7467 } G_STMT_END
7468
7469 #define REGISTER_SERIALIZATION(_gtype, _type) \
7470 G_STMT_START { \
7471 static GstValueTable gst_value = \
7472 SERIAL_VTABLE (0, gst_value_compare_ ## _type, \
7473 gst_value_serialize_ ## _type, gst_value_deserialize_ ## _type); \
7474 gst_value.type = _gtype; \
7475 gst_value_register (&gst_value); \
7476 } G_STMT_END
7477
7478 #define REGISTER_SERIALIZATION_NO_COMPARE(_gtype, _type) \
7479 G_STMT_START { \
7480 static GstValueTable gst_value = \
7481 SERIAL_VTABLE (0, NULL, \
7482 gst_value_serialize_ ## _type, gst_value_deserialize_ ## _type); \
7483 gst_value.type = _gtype; \
7484 gst_value_register (&gst_value); \
7485 } G_STMT_END
7486
7487 #define REGISTER_SERIALIZATION_COMPARE_ONLY(_gtype, _type) \
7488 G_STMT_START { \
7489 static GstValueTable gst_value = \
7490 SERIAL_VTABLE (0, gst_value_compare_ ## _type, \
7491 NULL, NULL); \
7492 gst_value.type = _gtype; \
7493 gst_value_register (&gst_value); \
7494 } G_STMT_END
7495
7496 /* These initial sizes are used for the tables
7497 * below, and save a couple of reallocs at startup */
7498
7499 static const gint GST_VALUE_TABLE_DEFAULT_SIZE = 40;
7500 static const gint GST_VALUE_UNION_TABLE_DEFAULT_SIZE = 8;
7501 static const gint GST_VALUE_INTERSECT_TABLE_DEFAULT_SIZE = 16;
7502 static const gint GST_VALUE_SUBTRACT_TABLE_DEFAULT_SIZE = 16;
7503
7504 void
_priv_gst_value_initialize(void)7505 _priv_gst_value_initialize (void)
7506 {
7507 gst_value_table =
7508 g_array_sized_new (FALSE, FALSE, sizeof (GstValueTable),
7509 GST_VALUE_TABLE_DEFAULT_SIZE);
7510 gst_value_hash = g_hash_table_new (NULL, NULL);
7511 gst_value_union_funcs = g_array_sized_new (FALSE, FALSE,
7512 sizeof (GstValueUnionInfo), GST_VALUE_UNION_TABLE_DEFAULT_SIZE);
7513 gst_value_intersect_funcs = g_array_sized_new (FALSE, FALSE,
7514 sizeof (GstValueIntersectInfo), GST_VALUE_INTERSECT_TABLE_DEFAULT_SIZE);
7515 gst_value_subtract_funcs = g_array_sized_new (FALSE, FALSE,
7516 sizeof (GstValueSubtractInfo), GST_VALUE_SUBTRACT_TABLE_DEFAULT_SIZE);
7517
7518 REGISTER_SERIALIZATION (gst_int_range_get_type (), int_range);
7519 REGISTER_SERIALIZATION (gst_int64_range_get_type (), int64_range);
7520 REGISTER_SERIALIZATION (gst_double_range_get_type (), double_range);
7521 REGISTER_SERIALIZATION (gst_fraction_range_get_type (), fraction_range);
7522 REGISTER_SERIALIZATION (gst_value_list_get_type (), value_list);
7523 REGISTER_SERIALIZATION (gst_value_array_get_type (), value_array);
7524 REGISTER_SERIALIZATION (g_value_array_get_type (), g_value_array);
7525 REGISTER_SERIALIZATION (gst_buffer_get_type (), buffer);
7526 REGISTER_SERIALIZATION (gst_sample_get_type (), sample);
7527 REGISTER_SERIALIZATION (gst_fraction_get_type (), fraction);
7528 REGISTER_SERIALIZATION (gst_caps_get_type (), caps);
7529 REGISTER_SERIALIZATION (gst_tag_list_get_type (), tag_list);
7530 REGISTER_SERIALIZATION (G_TYPE_DATE, date);
7531 REGISTER_SERIALIZATION (gst_date_time_get_type (), date_time);
7532 REGISTER_SERIALIZATION (gst_bitmask_get_type (), bitmask);
7533 REGISTER_SERIALIZATION (gst_structure_get_type (), structure);
7534 REGISTER_SERIALIZATION (gst_flagset_get_type (), flagset);
7535
7536 REGISTER_SERIALIZATION_NO_COMPARE (gst_segment_get_type (), segment);
7537 REGISTER_SERIALIZATION_NO_COMPARE (gst_caps_features_get_type (),
7538 caps_features);
7539
7540 REGISTER_SERIALIZATION_COMPARE_ONLY (gst_allocation_params_get_type (),
7541 allocation_params);
7542 REGISTER_SERIALIZATION_COMPARE_ONLY (G_TYPE_OBJECT, object);
7543
7544 REGISTER_SERIALIZATION_CONST (G_TYPE_DOUBLE, double);
7545 REGISTER_SERIALIZATION_CONST (G_TYPE_FLOAT, float);
7546
7547 REGISTER_SERIALIZATION_CONST (G_TYPE_STRING, string);
7548 REGISTER_SERIALIZATION_CONST (G_TYPE_BOOLEAN, boolean);
7549 REGISTER_SERIALIZATION_CONST (G_TYPE_ENUM, enum);
7550
7551 REGISTER_SERIALIZATION_CONST (G_TYPE_FLAGS, gflags);
7552
7553 REGISTER_SERIALIZATION_CONST (G_TYPE_INT, int);
7554
7555 REGISTER_SERIALIZATION_CONST (G_TYPE_INT64, int64);
7556 REGISTER_SERIALIZATION_CONST (G_TYPE_LONG, long);
7557
7558 REGISTER_SERIALIZATION_CONST (G_TYPE_UINT, uint);
7559 REGISTER_SERIALIZATION_CONST (G_TYPE_UINT64, uint64);
7560 REGISTER_SERIALIZATION_CONST (G_TYPE_ULONG, ulong);
7561
7562 REGISTER_SERIALIZATION_CONST (G_TYPE_UCHAR, uchar);
7563
7564 REGISTER_SERIALIZATION (G_TYPE_GTYPE, gtype);
7565
7566 g_value_register_transform_func (GST_TYPE_INT_RANGE, G_TYPE_STRING,
7567 gst_value_transform_int_range_string);
7568 g_value_register_transform_func (GST_TYPE_INT64_RANGE, G_TYPE_STRING,
7569 gst_value_transform_int64_range_string);
7570 g_value_register_transform_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_STRING,
7571 gst_value_transform_double_range_string);
7572 g_value_register_transform_func (GST_TYPE_FRACTION_RANGE, G_TYPE_STRING,
7573 gst_value_transform_fraction_range_string);
7574 g_value_register_transform_func (GST_TYPE_LIST, G_TYPE_STRING,
7575 gst_value_transform_list_string);
7576 g_value_register_transform_func (GST_TYPE_LIST, G_TYPE_VALUE_ARRAY,
7577 gst_value_transform_any_list_g_value_array);
7578 g_value_register_transform_func (GST_TYPE_ARRAY, G_TYPE_STRING,
7579 gst_value_transform_array_string);
7580 g_value_register_transform_func (GST_TYPE_ARRAY, G_TYPE_VALUE_ARRAY,
7581 gst_value_transform_any_list_g_value_array);
7582 g_value_register_transform_func (G_TYPE_VALUE_ARRAY, G_TYPE_STRING,
7583 gst_value_transform_g_value_array_string);
7584 g_value_register_transform_func (G_TYPE_VALUE_ARRAY, GST_TYPE_ARRAY,
7585 gst_value_transform_g_value_array_any_list);
7586 g_value_register_transform_func (G_TYPE_VALUE_ARRAY, GST_TYPE_LIST,
7587 gst_value_transform_g_value_array_any_list);
7588 g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_STRING,
7589 gst_value_transform_fraction_string);
7590 g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_FRACTION,
7591 gst_value_transform_string_fraction);
7592 g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_DOUBLE,
7593 gst_value_transform_fraction_double);
7594 g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_FLOAT,
7595 gst_value_transform_fraction_float);
7596 g_value_register_transform_func (G_TYPE_DOUBLE, GST_TYPE_FRACTION,
7597 gst_value_transform_double_fraction);
7598 g_value_register_transform_func (G_TYPE_FLOAT, GST_TYPE_FRACTION,
7599 gst_value_transform_float_fraction);
7600 g_value_register_transform_func (G_TYPE_DATE, G_TYPE_STRING,
7601 gst_value_transform_date_string);
7602 g_value_register_transform_func (G_TYPE_STRING, G_TYPE_DATE,
7603 gst_value_transform_string_date);
7604 g_value_register_transform_func (GST_TYPE_OBJECT, G_TYPE_STRING,
7605 gst_value_transform_object_string);
7606 g_value_register_transform_func (GST_TYPE_BITMASK, G_TYPE_UINT64,
7607 gst_value_transform_bitmask_uint64);
7608 g_value_register_transform_func (GST_TYPE_BITMASK, G_TYPE_STRING,
7609 gst_value_transform_bitmask_string);
7610 g_value_register_transform_func (G_TYPE_UINT64, GST_TYPE_BITMASK,
7611 gst_value_transform_uint64_bitmask);
7612 g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_BITMASK,
7613 gst_value_transform_string_bitmask);
7614
7615 g_value_register_transform_func (GST_TYPE_FLAG_SET, G_TYPE_STRING,
7616 gst_value_transform_flagset_string);
7617 g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_FLAG_SET,
7618 gst_value_transform_string_flagset);
7619
7620 gst_value_register_intersect_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
7621 gst_value_intersect_int_int_range);
7622 gst_value_register_intersect_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
7623 gst_value_intersect_int_range_int_range);
7624 gst_value_register_intersect_func (G_TYPE_INT64, GST_TYPE_INT64_RANGE,
7625 gst_value_intersect_int64_int64_range);
7626 gst_value_register_intersect_func (GST_TYPE_INT64_RANGE,
7627 GST_TYPE_INT64_RANGE, gst_value_intersect_int64_range_int64_range);
7628 gst_value_register_intersect_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
7629 gst_value_intersect_double_double_range);
7630 gst_value_register_intersect_func (GST_TYPE_DOUBLE_RANGE,
7631 GST_TYPE_DOUBLE_RANGE, gst_value_intersect_double_range_double_range);
7632 gst_value_register_intersect_func (GST_TYPE_ARRAY, GST_TYPE_ARRAY,
7633 gst_value_intersect_array);
7634 gst_value_register_intersect_func (GST_TYPE_FRACTION,
7635 GST_TYPE_FRACTION_RANGE, gst_value_intersect_fraction_fraction_range);
7636 gst_value_register_intersect_func (GST_TYPE_FRACTION_RANGE,
7637 GST_TYPE_FRACTION_RANGE,
7638 gst_value_intersect_fraction_range_fraction_range);
7639 gst_value_register_intersect_func (GST_TYPE_FLAG_SET, GST_TYPE_FLAG_SET,
7640 gst_value_intersect_flagset_flagset);
7641 gst_value_register_intersect_func (GST_TYPE_STRUCTURE, GST_TYPE_STRUCTURE,
7642 gst_value_intersect_structure_structure);
7643
7644 gst_value_register_subtract_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
7645 gst_value_subtract_int_int_range);
7646 gst_value_register_subtract_func (GST_TYPE_INT_RANGE, G_TYPE_INT,
7647 gst_value_subtract_int_range_int);
7648 gst_value_register_subtract_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
7649 gst_value_subtract_int_range_int_range);
7650 gst_value_register_subtract_func (G_TYPE_INT64, GST_TYPE_INT64_RANGE,
7651 gst_value_subtract_int64_int64_range);
7652 gst_value_register_subtract_func (GST_TYPE_INT64_RANGE, G_TYPE_INT64,
7653 gst_value_subtract_int64_range_int64);
7654 gst_value_register_subtract_func (GST_TYPE_INT64_RANGE,
7655 GST_TYPE_INT64_RANGE, gst_value_subtract_int64_range_int64_range);
7656 gst_value_register_subtract_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
7657 gst_value_subtract_double_double_range);
7658 gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_DOUBLE,
7659 gst_value_subtract_double_range_double);
7660 gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE,
7661 GST_TYPE_DOUBLE_RANGE, gst_value_subtract_double_range_double_range);
7662 gst_value_register_subtract_func (GST_TYPE_FRACTION,
7663 GST_TYPE_FRACTION_RANGE, gst_value_subtract_fraction_fraction_range);
7664 gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE,
7665 GST_TYPE_FRACTION, gst_value_subtract_fraction_range_fraction);
7666 gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE,
7667 GST_TYPE_FRACTION_RANGE,
7668 gst_value_subtract_fraction_range_fraction_range);
7669
7670 /* see bug #317246, #64994, #65041 */
7671 {
7672 volatile GType date_type = G_TYPE_DATE;
7673
7674 g_type_name (date_type);
7675 }
7676
7677 gst_value_register_union_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
7678 gst_value_union_int_int_range);
7679 gst_value_register_union_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
7680 gst_value_union_int_range_int_range);
7681 gst_value_register_union_func (GST_TYPE_FLAG_SET, GST_TYPE_FLAG_SET,
7682 gst_value_union_flagset_flagset);
7683 gst_value_register_union_func (GST_TYPE_STRUCTURE, GST_TYPE_STRUCTURE,
7684 gst_value_union_structure_structure);
7685
7686 #if GST_VERSION_NANO == 1
7687 /* If building from git master, check starting array sizes matched actual size
7688 * so we can keep the defines in sync and save a few reallocs on startup */
7689 if (gst_value_table->len > GST_VALUE_TABLE_DEFAULT_SIZE) {
7690 GST_ERROR ("Wrong initial gst_value_table size. "
7691 "Please set GST_VALUE_TABLE_DEFAULT_SIZE to %u in gstvalue.c",
7692 gst_value_table->len);
7693 }
7694 if (gst_value_union_funcs->len > GST_VALUE_UNION_TABLE_DEFAULT_SIZE) {
7695 GST_ERROR ("Wrong initial gst_value_union_funcs table size. "
7696 "Please set GST_VALUE_UNION_TABLE_DEFAULT_SIZE to %u in gstvalue.c",
7697 gst_value_union_funcs->len);
7698 }
7699 if (gst_value_intersect_funcs->len > GST_VALUE_INTERSECT_TABLE_DEFAULT_SIZE) {
7700 GST_ERROR ("Wrong initial gst_value_intersect_funcs table size. "
7701 "Please set GST_VALUE_INTERSECT_TABLE_DEFAULT_SIZE to %u in gstvalue.c",
7702 gst_value_intersect_funcs->len);
7703 }
7704 if (gst_value_subtract_funcs->len > GST_VALUE_SUBTRACT_TABLE_DEFAULT_SIZE) {
7705 GST_ERROR ("Wrong initial gst_value_subtract_funcs table size. "
7706 "Please set GST_VALUE_SUBTRACT_TABLE_DEFAULT_SIZE to %u in gstvalue.c",
7707 gst_value_subtract_funcs->len);
7708 }
7709 #endif
7710
7711 #if 0
7712 /* Implement these if needed */
7713 gst_value_register_union_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
7714 gst_value_union_fraction_fraction_range);
7715 gst_value_register_union_func (GST_TYPE_FRACTION_RANGE,
7716 GST_TYPE_FRACTION_RANGE, gst_value_union_fraction_range_fraction_range);
7717 #endif
7718 }
7719
7720 static void
gst_flagset_class_init(gpointer g_class,gpointer class_data)7721 gst_flagset_class_init (gpointer g_class, gpointer class_data)
7722 {
7723 GstFlagSetClass *f_class = (GstFlagSetClass *) (g_class);
7724 f_class->flags_type = (GType) GPOINTER_TO_SIZE (class_data);
7725 }
7726
7727 /**
7728 * gst_flagset_register:
7729 * @flags_type: a #GType of a #G_TYPE_FLAGS type.
7730 *
7731 * Create a new sub-class of #GST_TYPE_FLAG_SET
7732 * which will pretty-print the human-readable flags
7733 * when serializing, for easier debugging.
7734 *
7735 * Since: 1.6
7736 */
7737 GType
gst_flagset_register(GType flags_type)7738 gst_flagset_register (GType flags_type)
7739 {
7740 GTypeInfo info = {
7741 sizeof (GstFlagSetClass),
7742 NULL, NULL,
7743 (GClassInitFunc) gst_flagset_class_init,
7744 NULL, GSIZE_TO_POINTER (flags_type), 0, 0, NULL, NULL
7745 };
7746 GType t;
7747 gchar *class_name;
7748
7749 g_return_val_if_fail (G_TYPE_IS_FLAGS (flags_type), 0);
7750
7751 class_name = g_strdup_printf ("%sSet", g_type_name (flags_type));
7752
7753 t = g_type_register_static (GST_TYPE_FLAG_SET,
7754 g_intern_string (class_name), &info, 0);
7755 g_free (class_name);
7756
7757 return t;
7758 }
7759