1 /*
2 * Copyright (C) 2011 Igalia S.L.
3 *
4 * Contact: Iago Toral Quiroga <itoral@igalia.com>
5 *
6 * Authors: Juan A. Suarez Romero <jasuarez@igalia.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; version 2.1 of
11 * the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 *
23 */
24
25 /**
26 * SECTION:grl-related-keys
27 * @short_description: A class where to store related metadata keys.
28 * @see_also: #GrlRegistry, #GrlData
29 *
30 * When handling media keys, like artist, URI, mime-type, and so on, some of
31 * these keys are somewhat related: they do not make sense if they are not
32 * accompanied by other keys.
33 *
34 * For instance, media URI and and mime-type are related keys: mime-type does
35 * not make sense if it is not accompanied by an URI. Moreover, for each URI
36 * value, there is a corresponding mime-type value.
37 *
38 * #GrlRelatedKeys stores related keys and their values in one place, so user
39 * can handle them in one shot.
40 */
41
42 #include "grl-related-keys.h"
43 #include "grl-log.h"
44 #include "grl-registry-priv.h"
45
46 struct _GrlRelatedKeysPrivate {
47 GHashTable *data;
48 };
49
50 static void grl_related_keys_finalize (GObject *object);
51 static void free_value (GValue *val);
52
53 /* ================ GrlRelatedKeys GObject ================ */
54
55 G_DEFINE_TYPE_WITH_PRIVATE (GrlRelatedKeys, grl_related_keys, G_TYPE_OBJECT);
56
57 static void
grl_related_keys_class_init(GrlRelatedKeysClass * klass)58 grl_related_keys_class_init (GrlRelatedKeysClass *klass)
59 {
60 GObjectClass *gobject_class = (GObjectClass *)klass;
61
62 gobject_class->finalize = grl_related_keys_finalize;
63 }
64
65 static void
grl_related_keys_init(GrlRelatedKeys * self)66 grl_related_keys_init (GrlRelatedKeys *self)
67 {
68 self->priv = grl_related_keys_get_instance_private (self);
69 self->priv->data = g_hash_table_new_full (g_direct_hash,
70 g_direct_equal,
71 NULL,
72 (GDestroyNotify) free_value);
73 }
74
75 static void
grl_related_keys_finalize(GObject * object)76 grl_related_keys_finalize (GObject *object)
77 {
78 g_hash_table_unref (GRL_RELATED_KEYS (object)->priv->data);
79 G_OBJECT_CLASS (grl_related_keys_parent_class)->finalize (object);
80 }
81
82 /* ================ Utitilies ================ */
83
84 static void
free_value(GValue * val)85 free_value (GValue *val)
86 {
87 if (val) {
88 g_value_unset (val);
89 g_free (val);
90 }
91 }
92
93 /* ================ API ================ */
94
95 /**
96 * grl_related_keys_new:
97 *
98 * Creates a new #GrlRelatedKeys instance that can be used to store related
99 * keys and their values.
100 *
101 * Returns: a new object.
102 *
103 * Since: 0.1.10
104 **/
105 GrlRelatedKeys *
grl_related_keys_new(void)106 grl_related_keys_new (void)
107 {
108 return g_object_new (GRL_TYPE_RELATED_KEYS, NULL);
109 }
110
111 /**
112 * grl_related_keys_new_valist:
113 * @key: first key
114 * @args: #va_list of value, followed by (key,value) pairs to insert
115 *
116 * Creates a new #GrlRelatedKeys containing pairs of (key, value). Finish the
117 * list with %NULL.
118 *
119 * In case of a binary-type key, the expected element is (key, value, size).
120 *
121 * value type will be extracted from key information.
122 *
123 * Returns: a new #GrlRelatedKeys
124 *
125 * Since: 0.1.10
126 **/
127 GrlRelatedKeys *
grl_related_keys_new_valist(GrlKeyID key,va_list args)128 grl_related_keys_new_valist (GrlKeyID key,
129 va_list args)
130 {
131 GType key_type;
132 GrlKeyID next_key;
133 GrlRelatedKeys *prop;
134 gpointer next_value;
135
136 prop = grl_related_keys_new ();
137
138 next_key = key;
139 while (next_key) {
140 key_type = GRL_METADATA_KEY_GET_TYPE (next_key);
141 if (key_type == G_TYPE_STRING) {
142 grl_related_keys_set_string (prop, next_key, va_arg (args, gchar *));
143 } else if (key_type == G_TYPE_INT) {
144 grl_related_keys_set_int (prop, next_key, va_arg (args, gint));
145 } else if (key_type == G_TYPE_FLOAT) {
146 grl_related_keys_set_float (prop, next_key, va_arg (args, double));
147 } else if (key_type == G_TYPE_BOOLEAN) {
148 grl_related_keys_set_boolean (prop, next_key, va_arg (args, gboolean));
149 } else if (key_type == G_TYPE_BYTE_ARRAY) {
150 next_value = va_arg (args, gpointer);
151 grl_related_keys_set_binary (prop,
152 next_key,
153 next_value,
154 va_arg (args, gsize));
155 } else {
156 GRL_WARNING ("related key type '%s' not handled",
157 g_type_name (key_type));
158 }
159 next_key = va_arg (args, GrlKeyID);
160 }
161
162 return prop;
163 }
164
165 /**
166 * grl_related_keys_new_with_keys: (skip)
167 * @key: first key
168 * @...: value, following by list of (key, value)
169 *
170 * Creates a initial #GrlRelatedKeys containing the list of (key, value)
171 * pairs. Finish the list with %NULL.
172 *
173 * For more information see #grl_related_keys_new_valist.
174 *
175 * Returns: a new #GrlRelatedKeys
176 *
177 * Since: 0.1.10
178 **/
179 GrlRelatedKeys *
grl_related_keys_new_with_keys(GrlKeyID key,...)180 grl_related_keys_new_with_keys (GrlKeyID key,
181 ...)
182 {
183 GrlRelatedKeys *prop;
184 va_list args;
185
186 va_start (args, key);
187 prop = grl_related_keys_new_valist (key, args);
188 va_end (args);
189
190 return prop;
191 }
192
193
194 /**
195 * grl_related_keys_get:
196 * @relkeys: set of related keys to retrieve value
197 * @key: (type GrlKeyID): key to look up.
198 *
199 * Get the value associated with @key from @relkeys. If it does not contain any
200 * value, %NULL will be returned.
201 *
202 * Returns: (transfer none): a #GValue. This value should not be modified nor
203 * freed by user.
204 *
205 * Since: 0.1.10
206 **/
207 const GValue *
grl_related_keys_get(GrlRelatedKeys * relkeys,GrlKeyID key)208 grl_related_keys_get (GrlRelatedKeys *relkeys,
209 GrlKeyID key)
210 {
211 g_return_val_if_fail (GRL_IS_RELATED_KEYS (relkeys), NULL);
212 g_return_val_if_fail (key, NULL);
213
214 return g_hash_table_lookup (relkeys->priv->data, GRLKEYID_TO_POINTER (key));
215 }
216
217 /**
218 * grl_related_keys_set:
219 * @relkeys: set of related keys to modify
220 * @key: (type GrlKeyID): key to change or add
221 * @value: the new value
222 *
223 * Sets the value associated with @key into @relkeys. Old value is freed and
224 * the new one is set.
225 *
226 * Also, checks that @value is compliant with @key specification, modifying it
227 * accordingly. For instance, if @key requires a number between 0 and 10, but
228 * value is outside this range, it will be adapted accordingly.
229 *
230 * Since: 0.1.10
231 **/
232 void
grl_related_keys_set(GrlRelatedKeys * relkeys,GrlKeyID key,const GValue * value)233 grl_related_keys_set (GrlRelatedKeys *relkeys,
234 GrlKeyID key,
235 const GValue *value)
236 {
237 GValue *copy = NULL;
238 GrlRegistry *registry;
239 GType key_type, value_type;
240
241 g_return_if_fail (GRL_IS_RELATED_KEYS (relkeys));
242 g_return_if_fail (key);
243
244 if (!value) {
245 return;
246 }
247
248 key_type = GRL_METADATA_KEY_GET_TYPE (key);
249 value_type = G_VALUE_TYPE (value);
250
251 if (!g_value_type_transformable (value_type, key_type)) {
252 GRL_WARNING ("value has type %s, but expected %s",
253 g_type_name (value_type),
254 g_type_name (key_type));
255 return;
256 }
257
258 /* Dup value */
259 copy = g_new0 (GValue, 1);
260 g_value_init (copy, key_type);
261 if (!g_value_transform (value, copy)) {
262 GRL_WARNING ("transforming value type %s to key's type %s failed",
263 g_type_name (value_type),
264 g_type_name (key_type));
265 g_free (copy);
266 return;
267 }
268
269 registry = grl_registry_get_default ();
270
271 if (!grl_registry_metadata_key_validate (registry, key, copy)) {
272 GRL_WARNING ("'%s' value invalid, adjusting",
273 GRL_METADATA_KEY_GET_NAME (key));
274 }
275 g_hash_table_insert (relkeys->priv->data, GRLKEYID_TO_POINTER (key), copy);
276 }
277
278 /**
279 * grl_related_keys_set_string:
280 * @relkeys: set of related keys to modify
281 * @key: (type GrlKeyID): key to change or add
282 * @strvalue: the new value
283 *
284 * Sets the value associated with @key into @relkeys. @key must have been
285 * registered as a strying-type key. Old value is freed and the new one is set.
286 *
287 * Since: 0.1.10
288 **/
289 void
grl_related_keys_set_string(GrlRelatedKeys * relkeys,GrlKeyID key,const gchar * strvalue)290 grl_related_keys_set_string (GrlRelatedKeys *relkeys,
291 GrlKeyID key,
292 const gchar *strvalue)
293 {
294 GValue value = { 0 };
295
296 g_return_if_fail (GRL_IS_RELATED_KEYS (relkeys));
297
298 if (strvalue) {
299 g_value_init (&value, G_TYPE_STRING);
300 g_value_set_string (&value, strvalue);
301 grl_related_keys_set (relkeys, key, &value);
302 g_value_unset (&value);
303 }
304 }
305
306 /**
307 * grl_related_keys_get_string:
308 * @relkeys: set of related keys to inspect
309 * @key: (type GrlKeyID): key to use
310 *
311 * Returns the value associated with @key from @relkeys. If @key has no value,
312 * or value is not string, or @key is not in @relkeys, then %NULL is returned.
313 *
314 * Returns: string associated with @key, or %NULL in other case. Caller should
315 * not change nor free the value.
316 *
317 * Since: 0.1.10
318 **/
319 const gchar *
grl_related_keys_get_string(GrlRelatedKeys * relkeys,GrlKeyID key)320 grl_related_keys_get_string (GrlRelatedKeys *relkeys,
321 GrlKeyID key)
322 {
323 const GValue *value;
324
325 g_return_val_if_fail (GRL_IS_RELATED_KEYS (relkeys), NULL);
326
327 value = grl_related_keys_get (relkeys, key);
328
329 if (!value || !G_VALUE_HOLDS_STRING (value)) {
330 return NULL;
331 } else {
332 return g_value_get_string (value);
333 }
334 }
335
336 /**
337 * grl_related_keys_set_int:
338 * @relkeys: set of related keys to change
339 * @key: (type GrlKeyID): key to change or add
340 * @intvalue: the new value
341 *
342 * Sets the value associated with @key into @relkeys. @key must have been
343 * registered as an int-type key. Old value is replaced by the new one.
344 *
345 * Since: 0.1.10
346 **/
347 void
grl_related_keys_set_int(GrlRelatedKeys * relkeys,GrlKeyID key,gint intvalue)348 grl_related_keys_set_int (GrlRelatedKeys *relkeys,
349 GrlKeyID key,
350 gint intvalue)
351 {
352 GValue value = { 0 };
353 g_return_if_fail (GRL_IS_RELATED_KEYS (relkeys));
354 g_value_init (&value, G_TYPE_INT);
355 g_value_set_int (&value, intvalue);
356 grl_related_keys_set (relkeys, key, &value);
357 }
358
359 /**
360 * grl_related_keys_get_int:
361 * @relkeys: set of related keys to inspect
362 * @key: (type GrlKeyID): key to use
363 *
364 * Returns the value associated with @key from @relkeys. If @key has no value,
365 * or value is not a gint, or @key is not in @relkeys, then 0 is returned.
366 *
367 * Returns: int value associated with @key, or 0 in other case.
368 *
369 * Since: 0.1.10
370 **/
371 gint
grl_related_keys_get_int(GrlRelatedKeys * relkeys,GrlKeyID key)372 grl_related_keys_get_int (GrlRelatedKeys *relkeys,
373 GrlKeyID key)
374 {
375 const GValue *value;
376
377 g_return_val_if_fail (GRL_IS_RELATED_KEYS (relkeys), 0);
378
379 value = grl_related_keys_get (relkeys, key);
380
381 if (!value || !G_VALUE_HOLDS_INT (value)) {
382 return 0;
383 } else {
384 return g_value_get_int (value);
385 }
386 }
387
388 /**
389 * grl_related_keys_set_float:
390 * @relkeys: set of related keys to change
391 * @key: (type GrlKeyID): key to change or add
392 * @floatvalue: the new value
393 *
394 * Sets the value associated with @key into @relkeys. @key must have been
395 * registered as a float-type key. Old value is replaced by the new one.
396 *
397 * Since: 0.1.10
398 **/
399 void
grl_related_keys_set_float(GrlRelatedKeys * relkeys,GrlKeyID key,float floatvalue)400 grl_related_keys_set_float (GrlRelatedKeys *relkeys,
401 GrlKeyID key,
402 float floatvalue)
403 {
404 GValue value = { 0 };
405 g_return_if_fail (GRL_IS_RELATED_KEYS (relkeys));
406 g_value_init (&value, G_TYPE_FLOAT);
407 g_value_set_float (&value, floatvalue);
408 grl_related_keys_set (relkeys, key, &value);
409 }
410
411 /**
412 * grl_related_keys_get_float:
413 * @relkeys: set of related keys to inspect
414 * @key: (type GrlKeyID): key to use
415 *
416 * Returns the value associated with @key from @relkeys. If @key has no value,
417 * or value is not a gfloat, or @key is not in @relkeys, then 0 is returned.
418 *
419 * Returns: float value associated with @key, or 0 in other case.
420 *
421 * Since: 0.1.10
422 **/
423 gfloat
grl_related_keys_get_float(GrlRelatedKeys * relkeys,GrlKeyID key)424 grl_related_keys_get_float (GrlRelatedKeys *relkeys,
425 GrlKeyID key)
426 {
427 const GValue *value;
428
429 g_return_val_if_fail (GRL_IS_RELATED_KEYS (relkeys), 0.0);
430
431 value = grl_related_keys_get (relkeys, key);
432
433 if (!value || !G_VALUE_HOLDS_FLOAT (value)) {
434 return 0;
435 } else {
436 return g_value_get_float (value);
437 }
438 }
439
440 /**
441 * grl_related_keys_set_boolean:
442 * @relkeys: set of related keys to change
443 * @key: (type GrlKeyID): key to change or add
444 * @booleanvalue: the new value
445 *
446 * Sets the value associated with @key into @relkeys. @key must have been
447 * registered as a boolean-type key. Old value is replaced by the new one.
448 *
449 * Since: 0.2.3
450 **/
451 void
grl_related_keys_set_boolean(GrlRelatedKeys * relkeys,GrlKeyID key,gboolean booleanvalue)452 grl_related_keys_set_boolean (GrlRelatedKeys *relkeys,
453 GrlKeyID key,
454 gboolean booleanvalue)
455 {
456 GValue value = { 0 };
457 g_return_if_fail (GRL_IS_RELATED_KEYS (relkeys));
458 g_value_init (&value, G_TYPE_BOOLEAN);
459 g_value_set_boolean (&value, booleanvalue);
460 grl_related_keys_set (relkeys, key, &value);
461 }
462
463 /**
464 * grl_related_keys_get_boolean:
465 * @relkeys: set of related keys to inspect
466 * @key: (type GrlKeyID): key to use
467 *
468 * Returns the value associated with @key from @relkeys. If @key has no value,
469 * or value is not a gboolean, or @key is not in @relkeys, then %FALSE is
470 * returned.
471 *
472 * Returns: float value associated with @key, or %FALSE in other case.
473 *
474 * Since: 0.2.3
475 **/
476 gboolean
grl_related_keys_get_boolean(GrlRelatedKeys * relkeys,GrlKeyID key)477 grl_related_keys_get_boolean (GrlRelatedKeys *relkeys,
478 GrlKeyID key)
479 {
480 const GValue *value;
481
482 g_return_val_if_fail (GRL_IS_RELATED_KEYS (relkeys), FALSE);
483
484 value = grl_related_keys_get (relkeys, key);
485
486 if (!value || !G_VALUE_HOLDS_BOOLEAN (value)) {
487 return FALSE;
488 } else {
489 return g_value_get_boolean (value);
490 }
491 }
492
493 /**
494 * grl_related_keys_set_binary:
495 * @relkeys: set of related keys to change
496 * @key: (type GrlKeyID): key to change or add
497 * @buf: buffer holding the relkeys
498 * @size: size of the buffer
499 *
500 * Sets the value associated with @key into @relkeys. @key must have been
501 * registered as a binary-type key. Old value is replaced by the new one.
502 *
503 * Since: 0.1.10
504 **/
505 void
grl_related_keys_set_binary(GrlRelatedKeys * relkeys,GrlKeyID key,const guint8 * buf,gsize size)506 grl_related_keys_set_binary (GrlRelatedKeys *relkeys,
507 GrlKeyID key,
508 const guint8 *buf,
509 gsize size)
510 {
511 GValue v = { 0 };
512 GByteArray *array;
513
514 g_return_if_fail (GRL_IS_RELATED_KEYS (relkeys));
515
516 if (!buf || !size) {
517 return;
518 }
519
520 array = g_byte_array_append (g_byte_array_sized_new(size),
521 buf,
522 size);
523
524 g_value_init (&v, g_byte_array_get_type ());
525 g_value_take_boxed (&v, array);
526 grl_related_keys_set (relkeys, key, &v);
527 g_value_unset (&v);
528 }
529
530 /**
531 * grl_related_keys_get_binary:
532 * @relkeys: set of related keys to inspect
533 * @key: (type GrlKeyID): key to use
534 * @size: (out): location to store the buffer size
535 *
536 * Returns the value associated with @key from @relkeys. If @key has no value,
537 * or value is not a binary, or @key is not in @relkeys, then 0 is returned.
538 *
539 * Returns: buffer location associated with @key, or %NULL in other case. If
540 * successful @size will be set to the buffer size.
541 *
542 * Since: 0.1.10
543 **/
544 const guint8 *
grl_related_keys_get_binary(GrlRelatedKeys * relkeys,GrlKeyID key,gsize * size)545 grl_related_keys_get_binary (GrlRelatedKeys *relkeys,
546 GrlKeyID key,
547 gsize *size)
548 {
549 const GValue *value;
550
551 g_return_val_if_fail (GRL_IS_RELATED_KEYS (relkeys), NULL);
552 g_return_val_if_fail (size, NULL);
553
554 value = grl_related_keys_get (relkeys, key);
555
556
557 if (!value || !G_VALUE_HOLDS_BOXED (value)) {
558 return NULL;
559 } else {
560 GByteArray * array;
561
562 array = g_value_get_boxed (value);
563 *size = array->len;
564 return (const guint8 *) array->data;
565 }
566 }
567
568 /**
569 * grl_related_keys_set_boxed:
570 * @relkeys: set of related keys to modify
571 * @key: key to change or add
572 * @boxed: the new value
573 *
574 * Sets the value associated with @key into @relkeys. @key must have been
575 * registered as a boxed-type key. Old value is freed and the new one is set.
576 *
577 * Since: 0.2.0
578 */
579 void
grl_related_keys_set_boxed(GrlRelatedKeys * relkeys,GrlKeyID key,gconstpointer boxed)580 grl_related_keys_set_boxed (GrlRelatedKeys *relkeys,
581 GrlKeyID key,
582 gconstpointer boxed)
583 {
584 GValue value = { 0 };
585
586 g_return_if_fail (GRL_IS_RELATED_KEYS (relkeys));
587 g_return_if_fail (boxed != NULL);
588
589 g_value_init (&value, grl_metadata_key_get_type (key));
590 g_value_set_boxed (&value, boxed);
591 grl_related_keys_set (relkeys, key, &value);
592 g_value_unset (&value);
593 }
594
595 /**
596 * grl_related_keys_get_boxed:
597 * @relkeys: set of related keys to inspect
598 * @key: key to use
599 *
600 * Returns the value associated with @key from @relkeys. If @key has no value,
601 * the value is not of a boxed type, or @key is not in @relkeys, then %NULL is
602 * returned.
603 *
604 * Returns: (transfer none): the #GBoxed value associated with @key if
605 * possible, or %NULL in other case. The caller should not change nor free the
606 * value.
607 *
608 * Since: 0.2.0
609 */
610 gconstpointer
grl_related_keys_get_boxed(GrlRelatedKeys * relkeys,GrlKeyID key)611 grl_related_keys_get_boxed (GrlRelatedKeys *relkeys,
612 GrlKeyID key)
613 {
614 const GValue *value;
615
616 g_return_val_if_fail (GRL_IS_RELATED_KEYS (relkeys), NULL);
617
618 value = grl_related_keys_get (relkeys, key);
619
620 if (!value || !G_VALUE_HOLDS_BOXED (value)) {
621 return NULL;
622 } else {
623 return g_value_get_boxed (value);
624 }
625 }
626
627 /**
628 * grl_related_keys_set_int64:
629 * @relkeys: set of related keys to change
630 * @key: (type GrlKeyID): key to change or add
631 * @intvalue: the new value
632 *
633 * Sets the value associated with @key into @relkeys. @key must have been
634 * registered as a int64-type key. Old value is replaced by the new one.
635 *
636 * Since: 0.2.12
637 **/
638 void
grl_related_keys_set_int64(GrlRelatedKeys * relkeys,GrlKeyID key,gint64 intvalue)639 grl_related_keys_set_int64 (GrlRelatedKeys *relkeys,
640 GrlKeyID key,
641 gint64 intvalue)
642 {
643 GValue value = { 0 };
644 g_return_if_fail (GRL_IS_RELATED_KEYS (relkeys));
645 g_value_init (&value, G_TYPE_INT64);
646 g_value_set_int64 (&value, intvalue);
647 grl_related_keys_set (relkeys, key, &value);
648 }
649
650 /**
651 * grl_related_keys_get_int64:
652 * @relkeys: set of related keys to inspect
653 * @key: (type GrlKeyID): key to use
654 *
655 * Returns the value associated with @key from @relkeys. If @key has no value,
656 * or value is not a gint64, or @key is not in @relkeys, then 0 is returned.
657 *
658 * Returns: int64 value associated with @key, or 0 in other case.
659 *
660 * Since: 0.2.12
661 **/
662 gint64
grl_related_keys_get_int64(GrlRelatedKeys * relkeys,GrlKeyID key)663 grl_related_keys_get_int64 (GrlRelatedKeys *relkeys,
664 GrlKeyID key)
665 {
666 const GValue *value;
667
668 g_return_val_if_fail (GRL_IS_RELATED_KEYS (relkeys), 0);
669
670 value = grl_related_keys_get (relkeys, key);
671
672 if (!value || !G_VALUE_HOLDS_INT64 (value)) {
673 return 0;
674 } else {
675 return g_value_get_int64 (value);
676 }
677 }
678
679 /**
680 * grl_related_keys_set_for_id:
681 * @relkeys: set of related keys to modify
682 * @key_name: name of the key to change or add
683 * @value: the new value
684 *
685 * Sets the value associated with @key_name in @relkeys. This @key_name is used to create
686 * a new #GParamSpec instance, which is further used to create and register a key using
687 * grl_registry_register_metadata_key(). If @key_name already has a @value, old value
688 * is replaced by the new one.
689 *
690 * A property key_name consists of segments consisting of ASCII letters and
691 * digits, separated by either the '-' or '_' character. The first
692 * character of a property key_name must be a letter. Key_names which violate these
693 * rules lead to undefined behaviour.
694 *
695 * Returns: TRUE if @value was set to @key_name, FALSE otherwise.
696 *
697 * Since: 0.3.13
698 **/
699 gboolean
grl_related_keys_set_for_id(GrlRelatedKeys * relkeys,const gchar * key_name,const GValue * value)700 grl_related_keys_set_for_id (GrlRelatedKeys *relkeys,
701 const gchar *key_name,
702 const GValue *value)
703 {
704 GList *keys;
705 GrlKeyID bind_key, key;
706 GrlRegistry *registry;
707
708 keys = grl_related_keys_get_keys (relkeys);
709 if (keys) {
710 bind_key = GRLPOINTER_TO_KEYID (keys->data);
711 g_list_free (keys);
712 } else {
713 bind_key = GRL_METADATA_KEY_INVALID;
714 }
715
716 registry = grl_registry_get_default ();
717 key = grl_registry_register_or_lookup_metadata_key (registry,
718 key_name,
719 value,
720 bind_key);
721 if (key == GRL_METADATA_KEY_INVALID) {
722 return FALSE;
723 }
724
725 grl_related_keys_set (relkeys, key, value);
726 return TRUE;
727 }
728
729 /**
730 * grl_related_keys_remove:
731 * @relkeys: set of related keys
732 * @key: (type GrlKeyID): key to remove
733 *
734 * Removes @key from @relkeys set.
735 *
736 * Since: 0.2.3
737 **/
738 void
grl_related_keys_remove(GrlRelatedKeys * relkeys,GrlKeyID key)739 grl_related_keys_remove (GrlRelatedKeys *relkeys,
740 GrlKeyID key)
741 {
742 g_return_if_fail (GRL_IS_RELATED_KEYS (relkeys));
743 g_return_if_fail (key != GRL_METADATA_KEY_INVALID);
744
745 g_hash_table_remove (relkeys->priv->data, GRLKEYID_TO_POINTER (key));
746 }
747
748 /**
749 * grl_related_keys_has_key:
750 * @relkeys: set of related keys to inspect
751 * @key: (type GrlKeyID): key to search
752 *
753 * Checks if @key is in @relkeys.
754 *
755 * Returns: %TRUE if @key is in @relkeys, %FALSE in other case.
756 *
757 * Since: 0.1.10
758 **/
759 gboolean
grl_related_keys_has_key(GrlRelatedKeys * relkeys,GrlKeyID key)760 grl_related_keys_has_key (GrlRelatedKeys *relkeys,
761 GrlKeyID key)
762 {
763 g_return_val_if_fail (GRL_IS_RELATED_KEYS (relkeys), FALSE);
764
765 return g_hash_table_lookup_extended (relkeys->priv->data,
766 GRLKEYID_TO_POINTER (key),
767 NULL, NULL);
768 }
769
770 /**
771 * grl_related_keys_get_keys:
772 * @relkeys: set of related keys to inspect
773 *
774 * Returns a list with keys contained in @relkeys.
775 *
776 * Returns: (transfer container) (element-type GrlKeyID): a list with
777 * the keys. The content of the list should not be modified or freed. Use
778 * g_list_free() when done using the list.
779 *
780 * Since: 0.1.13
781 **/
782 GList *
grl_related_keys_get_keys(GrlRelatedKeys * relkeys)783 grl_related_keys_get_keys (GrlRelatedKeys *relkeys)
784 {
785 g_return_val_if_fail (GRL_IS_RELATED_KEYS (relkeys), NULL);
786
787 return g_hash_table_get_keys (relkeys->priv->data);
788 }
789
790 /**
791 * grl_related_keys_dup:
792 * @relkeys: set of related keys to duplicate
793 *
794 * Makes a deep copy of @relkeys and its contents.
795 *
796 * Returns: (transfer full): a new #GrlRelatedKeys.
797 * Free it with #g_object_unref.
798 *
799 * Since: 0.1.10
800 **/
801 GrlRelatedKeys *
grl_related_keys_dup(GrlRelatedKeys * relkeys)802 grl_related_keys_dup (GrlRelatedKeys *relkeys)
803 {
804 GList *keys, *key;
805 const GValue *value;
806 GValue *value_copy;
807 GrlRelatedKeys *dup_relkeys;
808
809 g_return_val_if_fail (GRL_IS_RELATED_KEYS (relkeys), NULL);
810
811 dup_relkeys = grl_related_keys_new ();
812
813 keys = grl_related_keys_get_keys (relkeys);
814 for (key = keys; key; key = g_list_next (key)) {
815 value = grl_related_keys_get (relkeys, GRLPOINTER_TO_KEYID (key->data));
816 value_copy = g_new0 (GValue, 1);
817 g_value_init (value_copy, G_VALUE_TYPE (value));
818 g_value_copy (value, value_copy);
819 g_hash_table_insert (dup_relkeys->priv->data, key->data, value_copy);
820 }
821
822 g_list_free (keys);
823
824 return dup_relkeys;
825 }
826