Annotate all hash table parameters and return values for introspection
[platform/upstream/libsoup.git] / libsoup / soup-value-utils.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * soup-type-utils.c: GValue and GType-related utilities
4  *
5  * Copyright (C) 2007 Red Hat, Inc.
6  */
7
8 #include "soup-value-utils.h"
9
10 #include <string.h>
11
12 /**
13  * SECTION:soup-value-utils
14  * @short_description: #GValue utilities
15  *
16  * These methods are useful for manipulating #GValue<!-- -->s, and in
17  * particular, arrays and hash tables of #GValue<!-- -->s, in a
18  * slightly nicer way than the standard #GValue API.
19  *
20  * They are written for use with soup-xmlrpc, but they also work with
21  * types not used by XML-RPC.
22  **/
23
24 /**
25  * SOUP_VALUE_SETV:
26  * @val: a #GValue
27  * @type: a #GType
28  * @args: #va_list pointing to a value of type @type
29  *
30  * Copies an argument of type @type from @args into @val. @val will
31  * point directly to the value in @args rather than copying it, so you
32  * must g_value_copy() it if you want it to remain valid.
33  **/
34
35 /**
36  * SOUP_VALUE_GETV:
37  * @val: a #GValue
38  * @type: a #GType
39  * @args: #va_list pointing to a value of type pointer-to-@type
40  *
41  * Extracts a value of type @type from @val into @args. The return
42  * value will point to the same data as @val rather than being a copy
43  * of it.
44  **/
45
46 static void
47 soup_value_hash_value_free (gpointer val)
48 {
49         g_value_unset (val);
50         g_free (val);
51 }
52
53 /**
54  * soup_value_hash_new:
55  *
56  * Creates a #GHashTable whose keys are strings and whose values
57  * are #GValue.
58  *
59  * Return value: (element-type utf8 GValue): a new empty #GHashTable
60  **/
61 GHashTable *
62 soup_value_hash_new (void)
63 {
64         return g_hash_table_new_full (g_str_hash, g_str_equal,
65                                       g_free, soup_value_hash_value_free);
66 }
67
68 static void
69 soup_value_hash_insert_valist (GHashTable *hash, const char *first_key,
70                                va_list args)
71 {
72         const char *key;
73         GType type;
74         GValue value;
75
76         key = first_key;
77         while (key) {
78                 type = va_arg (args, GType);
79                 SOUP_VALUE_SETV (&value, type, args);
80
81                 soup_value_hash_insert_value (hash, key, &value);
82                 key = va_arg (args, const char *);
83         }
84 }
85
86 /**
87  * soup_value_hash_new_with_vals:
88  * @first_key: the key for the first value
89  * @...: the type of @first_key, followed by the value, followed
90  * by additional key/type/value triplets, terminated by %NULL
91  *
92  * Creates a #GHashTable whose keys are strings and whose values
93  * are #GValue, and initializes it with the provided data. As
94  * with soup_value_hash_insert(), the keys and values are copied
95  * rather than being inserted directly.
96  *
97  * Return value: (element-type utf8 GValue): a new #GHashTable, initialized with the given values
98  **/
99 GHashTable *
100 soup_value_hash_new_with_vals (const char *first_key, ...)
101 {
102         GHashTable *hash = soup_value_hash_new ();
103         va_list args;
104
105         va_start (args, first_key);
106         soup_value_hash_insert_valist (hash, first_key, args);
107         va_end (args);
108
109         return hash;
110 }
111
112 /**
113  * soup_value_hash_insert_value:
114  * @hash: (element-type utf8 GValue): a value hash
115  * @key: the key
116  * @value: a value
117  *
118  * Inserts @value into @hash. (Unlike with g_hash_table_insert(), both
119  * the key and the value are copied).
120  **/
121 void
122 soup_value_hash_insert_value (GHashTable *hash, const char *key, GValue *value)
123 {
124         GValue *copy = g_new0 (GValue, 1);
125
126         g_value_init (copy, G_VALUE_TYPE (value));
127         g_value_copy (value, copy);
128         g_hash_table_insert (hash, g_strdup (key), copy);
129 }
130
131 /**
132  * soup_value_hash_insert:
133  * @hash: (element-type utf8 GValue): a value hash
134  * @key: the key
135  * @type: a #GType
136  * @...: a value of type @type
137  *
138  * Inserts the provided value of type @type into @hash. (Unlike with
139  * g_hash_table_insert(), both the key and the value are copied).
140  **/
141 void
142 soup_value_hash_insert (GHashTable *hash, const char *key, GType type, ...)
143 {
144         va_list args;
145         GValue val;
146
147         va_start (args, type);
148         SOUP_VALUE_SETV (&val, type, args);
149         va_end (args);
150         soup_value_hash_insert_value (hash, key, &val);
151 }
152
153 /**
154  * soup_value_hash_insert_vals:
155  * @hash: (element-type utf8 GValue): a value hash
156  * @first_key: the key for the first value
157  * @...: the type of @first_key, followed by the value, followed
158  * by additional key/type/value triplets, terminated by %NULL
159  *
160  * Inserts the given data into @hash. As with
161  * soup_value_hash_insert(), the keys and values are copied rather
162  * than being inserted directly.
163  **/
164 void
165 soup_value_hash_insert_vals (GHashTable *hash, const char *first_key, ...)
166 {
167         va_list args;
168
169         va_start (args, first_key);
170         soup_value_hash_insert_valist (hash, first_key, args);
171         va_end (args);
172 }
173
174 /**
175  * soup_value_hash_lookup:
176  * @hash: (element-type utf8 GValue): a value hash
177  * @key: the key to look up
178  * @type: a #GType
179  * @...: a value of type pointer-to-@type
180  *
181  * Looks up @key in @hash and stores its value into the provided
182  * location.
183  *
184  * Return value: %TRUE if @hash contained a value with key @key and
185  * type @type, %FALSE if not.
186  **/
187 gboolean
188 soup_value_hash_lookup (GHashTable *hash, const char *key, GType type, ...)
189 {
190         va_list args;
191         GValue *value;
192
193         value = g_hash_table_lookup (hash, key);
194         if (!value || !G_VALUE_HOLDS (value, type))
195                 return FALSE;
196
197         va_start (args, type);
198         SOUP_VALUE_GETV (value, type, args);
199         va_end (args);
200
201         return TRUE;
202 }
203
204 /**
205  * soup_value_hash_lookup_vals:
206  * @hash: (element-type utf8 GValue): a value hash
207  * @first_key: the first key to look up
208  * @...: the type of @first_key, a pointer to that type, and
209  * then additional key/type/pointer triplets, terminated
210  * by %NULL.
211  *
212  * Looks up a number of keys in @hash and returns their values.
213  *
214  * Return value: %TRUE if all of the keys were found, %FALSE
215  * if any were missing; note that you will generally need to
216  * initialize each destination variable to a reasonable default
217  * value, since there is no way to tell which keys were found
218  * and which were not.
219  **/
220 gboolean
221 soup_value_hash_lookup_vals (GHashTable *hash, const char *first_key, ...)
222 {
223         va_list args;
224         GValue *value;
225         const char *key;
226         GType type;
227         gboolean found_all = TRUE;
228
229         va_start (args, first_key);
230         key = first_key;
231         while (key) {
232                 type = va_arg (args, GType);
233
234                 value = g_hash_table_lookup (hash, key);
235                 if (!value || !G_VALUE_HOLDS (value, type)) {
236                         found_all = FALSE;
237                         /* skip a pointer */
238                         va_arg (args, gpointer);
239                 } else
240                         SOUP_VALUE_GETV (value, type, args);
241
242                 key = va_arg (args, const char *);
243         }
244         va_end (args);
245
246         return found_all;
247 }
248
249
250 /**
251  * soup_value_array_from_args:
252  * @args: arguments to create a #GValueArray from
253  *
254  * Creates a #GValueArray from the provided arguments, which must
255  * consist of pairs of a #GType and a value of that type, terminated
256  * by %G_TYPE_INVALID. (The array will contain copies of the provided
257  * data rather than pointing to the passed-in data directly.)
258  *
259  * Return value: a new #GValueArray, or %NULL if an error occurred.
260  **/
261 GValueArray *
262 soup_value_array_from_args (va_list args)
263 {
264         GValueArray *array;
265         GType type;
266         GValue val;
267
268         array = g_value_array_new (1);
269         while ((type = va_arg (args, GType)) != G_TYPE_INVALID) {
270                 SOUP_VALUE_SETV (&val, type, args);
271                 g_value_array_append (array, &val);
272         }
273         return array;
274 }
275
276 /**
277  * soup_value_array_to_args:
278  * @array: a #GValueArray
279  * @args: arguments to extract @array into
280  *
281  * Extracts a #GValueArray into the provided arguments, which must
282  * consist of pairs of a #GType and a value of pointer-to-that-type,
283  * terminated by %G_TYPE_INVALID. The returned values will point to the
284  * same memory as the values in the array.
285  *
286  * Return value: success or failure
287  **/
288 gboolean
289 soup_value_array_to_args (GValueArray *array, va_list args)
290 {
291         GType type;
292         GValue *value;
293         int i;
294
295         for (i = 0; i < array->n_values; i++) {
296                 type = va_arg (args, GType);
297                 if (type == G_TYPE_INVALID)
298                         return FALSE;
299                 value = g_value_array_get_nth (array, i);
300                 if (!G_VALUE_HOLDS (value, type))
301                         return FALSE;
302                 SOUP_VALUE_GETV (value, type, args);
303         }
304         return TRUE;
305 }
306
307 /**
308  * soup_value_array_new:
309  *
310  * Creates a new %GValueArray. (This is just a wrapper around
311  * g_value_array_new(), for naming consistency purposes.)
312  *
313  * Return value: a new %GValueArray
314  **/
315 GValueArray *
316 soup_value_array_new (void)
317 {
318         return g_value_array_new (1);
319 }
320
321 static void
322 soup_value_array_append_valist (GValueArray *array,
323                                 GType first_type, va_list args)
324 {
325         GType type;
326         GValue value;
327
328         type = first_type;
329         while (type != G_TYPE_INVALID) {
330                 SOUP_VALUE_SETV (&value, type, args);
331
332                 g_value_array_append (array, &value);
333                 type = va_arg (args, GType);
334         }
335 }
336
337 /**
338  * soup_value_array_new_with_vals:
339  * @first_type: the type of the first value to add
340  * @...: the first value to add, followed by other type/value
341  * pairs, terminated by %G_TYPE_INVALID
342  *
343  * Creates a new %GValueArray and copies the provided values
344  * into it.
345  *
346  * Return value: a new %GValueArray
347  **/
348 GValueArray *
349 soup_value_array_new_with_vals (GType first_type, ...)
350 {
351         GValueArray *array = soup_value_array_new ();
352         va_list args;
353
354         va_start (args, first_type);
355         soup_value_array_append_valist (array, first_type, args);
356         va_end (args);
357
358         return array;
359 }
360
361 /**
362  * soup_value_array_insert:
363  * @array: a #GValueArray
364  * @index_: the index to insert at
365  * @type: a #GType
366  * @...: a value of type @type
367  *
368  * Inserts the provided value of type @type into @array as with
369  * g_value_array_insert(). (The provided data is copied rather than
370  * being inserted directly.)
371  **/
372 void
373 soup_value_array_insert (GValueArray *array, guint index_, GType type, ...)
374 {
375         va_list args;
376         GValue val;
377
378         va_start (args, type);
379         SOUP_VALUE_SETV (&val, type, args);
380         va_end (args);
381         g_value_array_insert (array, index_, &val);
382 }
383
384 /**
385  * soup_value_array_append:
386  * @array: a #GValueArray
387  * @type: a #GType
388  * @...: a value of type @type
389  *
390  * Appends the provided value of type @type to @array as with
391  * g_value_array_append(). (The provided data is copied rather than
392  * being inserted directly.)
393  **/
394 void
395 soup_value_array_append (GValueArray *array, GType type, ...)
396 {
397         va_list args;
398         GValue val;
399
400         va_start (args, type);
401         SOUP_VALUE_SETV (&val, type, args);
402         va_end (args);
403         g_value_array_append (array, &val);
404 }
405
406 /**
407  * soup_value_array_append_vals:
408  * @array: a #GValueArray
409  * @first_type: the type of the first value to add
410  * @...: the first value to add, followed by other type/value
411  * pairs, terminated by %G_TYPE_INVALID
412  *
413  * Appends the provided values into @array as with
414  * g_value_array_append(). (The provided data is copied rather than
415  * being inserted directly.)
416  **/
417 void
418 soup_value_array_append_vals (GValueArray *array, GType first_type, ...)
419 {
420         va_list args;
421
422         va_start (args, first_type);
423         soup_value_array_append_valist (array, first_type, args);
424         va_end (args);
425 }
426
427 /**
428  * soup_value_array_get_nth:
429  * @array: a #GValueArray
430  * @index_: the index to look up
431  * @type: a #GType
432  * @...: a value of type pointer-to-@type
433  *
434  * Gets the @index_ element of @array and stores its value into the
435  * provided location.
436  *
437  * Return value: %TRUE if @array contained a value with index @index_
438  * and type @type, %FALSE if not.
439  **/
440 gboolean
441 soup_value_array_get_nth (GValueArray *array, guint index_, GType type, ...)
442 {
443         GValue *value;
444         va_list args;
445
446         value = g_value_array_get_nth (array, index_);
447         if (!value || !G_VALUE_HOLDS (value, type))
448                 return FALSE;
449
450         va_start (args, type);
451         SOUP_VALUE_GETV (value, type, args);
452         va_end (args);
453         return TRUE;
454 }
455
456
457 static GByteArray *
458 soup_byte_array_copy (GByteArray *ba)
459 {
460         GByteArray *copy;
461
462         copy = g_byte_array_sized_new (ba->len);
463         g_byte_array_append (copy, ba->data, ba->len);
464         return copy;
465 }
466
467 static void
468 soup_byte_array_free (GByteArray *ba)
469 {
470         g_byte_array_free (ba, TRUE);
471 }
472
473 /**
474  * SOUP_TYPE_BYTE_ARRAY:
475  *
476  * glib does not define a #GType for #GByteArray, so libsoup
477  * defines this one itself.
478  **/
479 GType
480 soup_byte_array_get_type (void)
481 {
482         static volatile gsize type_volatile = 0;
483
484         if (g_once_init_enter (&type_volatile)) {
485                 GType type = g_boxed_type_register_static (
486                         g_intern_static_string ("SoupByteArray"),
487                         (GBoxedCopyFunc) soup_byte_array_copy,
488                         (GBoxedFreeFunc) soup_byte_array_free);
489                 g_once_init_leave (&type_volatile, type);
490         }
491         return type_volatile;
492 }