Merge branch 'mgorse'
[platform/core/uifw/at-spi2-atk.git] / dbind / dbind-any.c
1 /* type driven marshalling */
2 #include "config.h"
3 #include "dbind-config.h"
4 #define DBUS_API_SUBJECT_TO_CHANGE
5 #include <stdio.h>
6 #include <glib.h>
7 #include "dbind-any.h"
8
9 #undef DEBUG
10
11 /* Align a value upward to a boundary, expressed as a number of bytes.
12    E.g. align to an 8-byte boundary with argument of 8.  */
13
14 /*
15  *   (this + boundary - 1)
16  *          &
17  *    ~(boundary - 1)
18  */
19
20 #define ALIGN_VALUE(this, boundary) \
21   (( ((gulong)(this)) + (((gulong)(boundary)) -1)) & (~(((gulong)(boundary))-1)))
22
23 #define ALIGN_ADDRESS(this, boundary) \
24   ((gpointer)ALIGN_VALUE(this, boundary))
25
26 #define PTR_PLUS(ptr, offset) \
27         ((gpointer) (((guchar *)(ptr)) + (offset)))
28
29 unsigned int dbind_find_c_alignment_r (char **type);
30 unsigned int dbind_find_c_alignment   (char  *type);
31
32 static void
33 warn_braces ()
34 {
35     fprintf (stderr, "Error: dbus flags structures & dicts with braces rather than "
36              " an explicit type member of 'struct'\n");
37 }
38
39 /* gather immediate allocation information for this type */
40 size_t dbind_gather_alloc_info_r (char **type)
41 {
42     char t = **type;
43     (*type)++;
44     if (t == DBUS_TYPE_ARRAY) {
45         switch (**type) {
46             case DBUS_STRUCT_BEGIN_CHAR:
47                 while (**type != DBUS_STRUCT_END_CHAR && **type != '\0') (*type)++;
48                 if (**type != '\0') (*type)++;
49                 break;
50             case '\0':
51                 break;
52             default:
53                 (*type)++;
54                 break;
55             }
56         }
57
58         switch (t) {
59     case DBUS_TYPE_BYTE:
60         return sizeof (char);
61     case DBUS_TYPE_BOOLEAN:
62         return sizeof (dbus_bool_t);
63     case DBUS_TYPE_INT16:
64     case DBUS_TYPE_UINT16:
65         return sizeof (dbus_int16_t);
66     case DBUS_TYPE_INT32:
67     case DBUS_TYPE_UINT32:
68         return sizeof (dbus_int32_t);
69     case DBUS_TYPE_INT64:
70     case DBUS_TYPE_UINT64:
71         return sizeof (dbus_int64_t);
72     case DBUS_TYPE_DOUBLE:
73         return sizeof (double);
74     /* ptr types */
75     case DBUS_TYPE_STRING:
76     case DBUS_TYPE_OBJECT_PATH:
77     case DBUS_TYPE_SIGNATURE:
78     case DBUS_TYPE_ARRAY:
79         return sizeof (void *);
80     case DBUS_STRUCT_BEGIN_CHAR: {
81                 int sum = 0, stralign;
82
83         stralign = dbind_find_c_alignment (*type - 1);
84
85         while (**type != DBUS_STRUCT_END_CHAR) {
86                         sum = ALIGN_VALUE (sum, dbind_find_c_alignment (*type));
87                         sum += dbind_gather_alloc_info_r (type);
88         }
89                 sum = ALIGN_VALUE (sum, stralign);
90
91         g_assert (**type == DBUS_STRUCT_END_CHAR);
92         (*type)++;
93
94                 return sum;
95     }
96     case DBUS_TYPE_STRUCT:
97     case DBUS_TYPE_DICT_ENTRY:
98         warn_braces ();
99         default:
100                 return 0;
101         }
102 }
103
104 size_t dbind_gather_alloc_info (char *type)
105 {
106     return dbind_gather_alloc_info_r (&type);
107 }
108
109 unsigned int
110 dbind_find_c_alignment_r (char **type)
111 {
112         unsigned int retval = 1;
113
114     char t = **type;
115     (*type)++;
116
117 #ifdef DEBUG
118     fprintf (stderr, "\tfind align for %c (0x%x)\n", t, t);
119 #endif
120
121         switch (t) {
122     case DBUS_TYPE_BYTE:
123         return DBIND_ALIGNOF_CHAR;
124     case DBUS_TYPE_BOOLEAN:
125         return DBIND_ALIGNOF_DBUS_BOOL_T;
126     case DBUS_TYPE_INT16:
127     case DBUS_TYPE_UINT16:
128         return DBIND_ALIGNOF_DBUS_INT16_T;
129     case DBUS_TYPE_INT32:
130     case DBUS_TYPE_UINT32:
131         return DBIND_ALIGNOF_DBUS_INT32_T;
132     case DBUS_TYPE_INT64:
133     case DBUS_TYPE_UINT64:
134         return DBIND_ALIGNOF_DBUS_INT64_T;
135     case DBUS_TYPE_DOUBLE:
136         return DBIND_ALIGNOF_DOUBLE;
137     /* ptr types */
138     case DBUS_TYPE_STRING:
139     case DBUS_TYPE_OBJECT_PATH:
140     case DBUS_TYPE_SIGNATURE:
141     case DBUS_TYPE_ARRAY:
142         return DBIND_ALIGNOF_DBIND_POINTER;
143         case DBUS_STRUCT_BEGIN_CHAR:
144 #if DBIND_ALIGNOF_DBIND_STRUCT > 1
145                 retval = MAX (retval, DBIND_ALIGNOF_DBIND_STRUCT);
146 #endif
147         while (**type != DBUS_STRUCT_END_CHAR) {
148             int elem_align = dbind_find_c_alignment_r (type);
149                         retval = MAX (retval, elem_align);
150         }
151         (*type)++;
152                 return retval;
153     case DBUS_TYPE_STRUCT:
154     case DBUS_TYPE_DICT_ENTRY:
155         warn_braces ();
156         return DBIND_ALIGNOF_DBIND_POINTER;
157     case '\0':
158         g_assert_not_reached();
159         break;
160         default:
161                 return 1;
162         }
163 }
164
165 unsigned int
166 dbind_find_c_alignment (char *type)
167 {
168     return dbind_find_c_alignment_r (&type);
169 }
170
171 #define DBIND_POD_CASES \
172          DBUS_TYPE_BYTE: \
173     case DBUS_TYPE_INT16: \
174     case DBUS_TYPE_UINT16: \
175     case DBUS_TYPE_INT32: \
176     case DBUS_TYPE_UINT32: \
177     case DBUS_TYPE_BOOLEAN: \
178     case DBUS_TYPE_INT64: \
179     case DBUS_TYPE_UINT64: \
180     case DBUS_TYPE_DOUBLE
181
182 void
183 dbind_any_marshal (DBusMessageIter *iter,
184                    char           **type,
185                    void           **data)
186 {
187     size_t len;
188
189 #ifdef DEBUG
190     fprintf (stderr, "any marshal '%c' to %p\n", **type, *data);
191 #endif
192
193     switch (**type) {
194     case DBIND_POD_CASES:
195     case DBUS_TYPE_STRING:
196     case DBUS_TYPE_OBJECT_PATH:
197     case DBUS_TYPE_SIGNATURE:
198         len = dbind_gather_alloc_info (*type);
199         dbus_message_iter_append_basic (iter, **type, *data);
200         *data = ((guchar *)*data) + len;
201         (*type)++;
202         break;
203     case DBUS_TYPE_ARRAY: {
204         int i;
205         GArray *vals = **(void ***)data;
206         size_t elem_size, elem_align;
207         DBusMessageIter sub;
208         char *saved_child_type, *child_type_string;
209
210         (*type)++;
211         saved_child_type = *type;
212
213         elem_size = dbind_gather_alloc_info (*type);
214         elem_align = dbind_find_c_alignment_r (type); 
215
216         /* wow this part of the API sucks too ... */
217         child_type_string = g_strndup (saved_child_type, *type - saved_child_type);
218 /*        fprintf (stderr, "array child type '%s'\n", child_type_string); */
219         dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY,
220                                           child_type_string, &sub);
221         for (i = 0; i < vals->len; i++) {
222             void *ptr = vals->data + elem_size * i;
223             *type = saved_child_type; /* rewind type info */
224             ptr = ALIGN_ADDRESS (ptr, elem_align);
225             dbind_any_marshal (&sub, type, &ptr);
226         }
227
228         dbus_message_iter_close_container (iter, &sub);
229         g_free (child_type_string);
230         break;
231     }
232     case DBUS_STRUCT_BEGIN_CHAR: {
233                 gconstpointer data0 = *data;
234                 int offset = 0, stralign;
235         DBusMessageIter sub;
236
237         stralign = dbind_find_c_alignment (*type);
238
239         (*type)++;
240
241         dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL, &sub);
242
243         offset = 0 ;
244         while (**type != DBUS_STRUCT_END_CHAR) {
245             char *subt = *type;
246                         offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
247                         *data = PTR_PLUS (data0, offset);
248             dbind_any_marshal (&sub, type, data);
249             offset += dbind_gather_alloc_info (subt);
250         }
251
252                 offset = ALIGN_VALUE (offset, stralign);
253                 *data = PTR_PLUS (data0, offset);
254
255         dbus_message_iter_close_container (iter, &sub);
256
257         g_assert (**type == DBUS_STRUCT_END_CHAR);
258         (*type)++;
259
260         break;
261     }
262     case DBUS_TYPE_STRUCT:
263     case DBUS_TYPE_DICT_ENTRY:
264         warn_braces ();
265         break;
266     }
267 }
268
269 void
270 dbind_any_demarshal (DBusMessageIter *iter,
271                      char           **type,
272                      void           **data)
273 {
274     size_t len;
275
276 #ifdef DEBUG
277     fprintf (stderr, "any demarshal '%c' to %p\n", **type, *data);
278 #endif
279
280     switch (**type) {
281     case DBIND_POD_CASES:
282         len = dbind_gather_alloc_info (*type);
283         dbus_message_iter_get_basic (iter, *data);
284         *data = ((guchar *)*data) + len;
285         (*type)++;
286         break;
287     case DBUS_TYPE_STRING:
288     case DBUS_TYPE_OBJECT_PATH:
289     case DBUS_TYPE_SIGNATURE:
290         len = dbind_gather_alloc_info (*type);
291         dbus_message_iter_get_basic (iter, *data);
292 #ifdef DEBUG
293         fprintf (stderr, "dup string '%s' (%p)\n", **(void ***)data, **(void ***)data);
294 #endif
295         **(void ***)data = g_strdup (**(void ***)data);
296         *data = ((guchar *)*data) + len;
297         (*type)++;
298         break;
299     case DBUS_TYPE_ARRAY: {
300         GArray *vals;
301         DBusMessageIter child;
302         size_t elem_size, elem_align;
303         char *stored_child_type;
304         int i;
305
306         (*type)++;
307         stored_child_type = *type;
308         
309         elem_size = dbind_gather_alloc_info (*type);
310         elem_align = dbind_find_c_alignment_r (type);
311         vals = g_array_new (FALSE, FALSE, elem_size);
312         (**(void ***)data) = vals;
313         *data = ((guchar *)*data) + sizeof (void *);
314         
315         i = 0;
316         dbus_message_iter_recurse (iter, &child);
317         while (dbus_message_iter_get_arg_type (&child) != DBUS_TYPE_INVALID) {
318             void *ptr;
319             char *subt = stored_child_type;
320             g_array_set_size (vals, i + 1);
321             ptr = vals->data + elem_size * i;
322             ptr = ALIGN_ADDRESS (ptr, elem_align);
323             dbind_any_demarshal (&child, &subt, &ptr);
324             i++;
325         };
326         break;
327     }
328     case DBUS_STRUCT_BEGIN_CHAR: {
329                 gconstpointer data0 = *data;
330                 int offset = 0, stralign;
331         DBusMessageIter child;
332
333         stralign = dbind_find_c_alignment (*type);
334
335         (*type)++;
336
337         dbus_message_iter_recurse (iter, &child);
338
339         while (**type != DBUS_STRUCT_END_CHAR) {
340             char *subt = *type;
341                         offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
342                         *data = PTR_PLUS (data0, offset);
343             dbind_any_demarshal (&child, type, data);
344             offset += dbind_gather_alloc_info (subt);
345         }
346
347                 offset = ALIGN_VALUE (offset, stralign);
348                 *data = PTR_PLUS (data0, offset);
349
350         g_assert (**type == DBUS_STRUCT_END_CHAR);
351         (*type)++;
352
353         break;
354     }
355     case DBUS_TYPE_STRUCT:
356     case DBUS_TYPE_DICT_ENTRY:
357         warn_braces ();
358         break;
359     }
360     dbus_message_iter_next (iter);
361 }
362
363 static void
364 dbind_any_free_r (char **type, void **data)
365 {
366     size_t len;
367
368 #ifdef DEBUG
369     fprintf (stderr, "any free '%c' to %p\n", **type, *data);
370 #endif
371
372     switch (**type) {
373     case DBIND_POD_CASES:
374         *data = ((guchar *)*data) + dbind_gather_alloc_info (*type);
375         (*type)++;
376         break;
377     case DBUS_TYPE_STRING:
378     case DBUS_TYPE_OBJECT_PATH:
379     case DBUS_TYPE_SIGNATURE:
380 #ifdef DEBUG
381         fprintf (stderr, "string free %p\n", **(void ***)data);
382 #endif
383         g_free (**(void ***)data);
384         *data = ((guchar *)*data) + dbind_gather_alloc_info (*type);
385         (*type)++;
386         break;
387     case DBUS_TYPE_ARRAY: {
388         int i;
389         GArray *vals = **(void ***)data;
390         size_t elem_size, elem_align;
391         char *saved_child_type, *child_type_string;
392
393         (*type)++;
394         saved_child_type = *type;
395
396         elem_size = dbind_gather_alloc_info (*type);
397         elem_align = dbind_find_c_alignment_r (type); 
398
399         for (i = 0; i < vals->len; i++) {
400             void *ptr = vals->data + elem_size * i;
401             *type = saved_child_type; /* rewind type info */
402             ptr = ALIGN_ADDRESS (ptr, elem_align);
403             dbind_any_free_r (type, &ptr);
404         }
405         g_array_free (vals, TRUE);
406         break;
407     }
408     case DBUS_STRUCT_BEGIN_CHAR: {
409                 gconstpointer data0 = *data;
410                 int offset = 0, stralign;
411
412         stralign = dbind_find_c_alignment (*type);
413         (*type)++;
414
415         offset = 0 ;
416         while (**type != DBUS_STRUCT_END_CHAR) {
417             char *subt = *type;
418                         offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type));
419                         *data = PTR_PLUS (data0, offset);
420             dbind_any_free_r (type, data);
421             offset += dbind_gather_alloc_info (subt);
422         }
423
424                 offset = ALIGN_VALUE (offset, stralign);
425                 *data = PTR_PLUS (data0, offset);
426
427         g_assert (**type == DBUS_STRUCT_END_CHAR);
428         (*type)++;
429
430         break;
431     }
432     case DBUS_TYPE_STRUCT:
433     case DBUS_TYPE_DICT_ENTRY:
434         warn_braces ();
435         break;
436     }
437 }
438
439 /* nice deep free ... */
440 void
441 dbind_any_free (char *type,
442                 void *ptr)
443 {
444     dbind_any_free_r (&type, &ptr);
445 }
446
447 /* should this be the default normalization ? */
448 void
449 dbind_any_free_ptr (char *type, void *ptr)
450 {
451     dbind_any_free (type, &ptr);
452 }