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