2005-03-09 Colin Walters <walters@verbum.org>
[platform/upstream/dbus.git] / dbus / dbus-signature.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-signature.c  Routines for reading recursive type signatures
3  *
4  * Copyright (C) 2005 Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 2.1
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #include "dbus-signature.h"
25 #include "dbus-marshal-recursive.h"
26 #include "dbus-marshal-basic.h"
27 #include "dbus-internals.h"
28 #include "dbus-test.h"
29
30 typedef struct
31
32   const char *pos;
33   unsigned int finished : 1;
34   unsigned int in_array : 1;
35 } DBusSignatureRealIter;
36
37 /**
38  * @addtogroup DBusSignature
39  * @{
40  */
41
42 /**
43  * Initializes a #DBusSignatureIter for reading a type signature.  This
44  * function is not safe to use on invalid signatures; be sure to
45  * validate potentially invalid signatures with dbus_signature_validate
46  * before using this function.
47  *
48  * @param iter pointer to an iterator to initialize
49  * @param signature the type signature
50  */
51 void
52 dbus_signature_iter_init (DBusSignatureIter *iter,
53                           const char        *signature)
54 {
55   DBusSignatureRealIter *real_iter = (DBusSignatureRealIter *) iter;
56
57   real_iter->pos = signature;
58   real_iter->finished = FALSE;
59   real_iter->in_array = FALSE;
60 }
61
62 /**
63  * Returns the current type pointed to by the iterator.
64  * If the iterator is pointing at a type code such as 's', then
65  * it will be returned directly.
66  *
67  * However, when the parser encounters a container type start
68  * character such as '(' for a structure, the corresponding type for
69  * the container will be returned, e.g.  DBUS_TYPE_STRUCT, not '('.
70  * In this case, you should initialize a sub-iterator with
71  * dbus_signature_iter_recurse to parse the container type.
72  *
73  * @param iter pointer to an iterator 
74  * @returns current type (e.g. DBUS_TYPE_STRING, DBUS_TYPE_ARRAY)
75  */
76 int
77 dbus_signature_iter_get_current_type (const DBusSignatureIter *iter)
78 {
79   DBusSignatureRealIter *real_iter = (DBusSignatureRealIter *) iter;
80
81   return _dbus_first_type_in_signature_c_str (real_iter->pos, 0);
82 }
83
84 /**
85  * Convenience function for returning the element type of an array;
86  * This function allows you to avoid initializing a sub-iterator and
87  * getting its current type.
88  *
89  * It is an error to invoke this function if the current type of the
90  * iterator is not DBUS_TYPE_ARRAY.
91  *
92  * @param iter pointer to an iterator 
93  * @returns current array element type
94  */
95 int
96 dbus_signature_iter_get_element_type (const DBusSignatureIter *iter)
97 {
98   DBusSignatureRealIter *real_iter = (DBusSignatureRealIter *) iter;
99
100   _dbus_return_val_if_fail (dbus_signature_iter_get_current_type (iter) == DBUS_TYPE_ARRAY, DBUS_TYPE_INVALID);
101
102   return _dbus_first_type_in_signature_c_str (real_iter->pos, 1);
103 }
104
105 /**
106  * Skip to the next value on this "level". e.g. the next field in a
107  * struct, the next value in an array. Returns FALSE at the end of the
108  * current container.
109  *
110  * @param iter the iterator
111  * @returns FALSE if nothing more to read at or below this level
112  */
113 dbus_bool_t
114 dbus_signature_iter_next (DBusSignatureIter *iter)
115 {
116   DBusSignatureRealIter *real_iter = (DBusSignatureRealIter *) iter;
117
118   if (real_iter->finished)
119     return FALSE;
120   else
121     {
122       int pos;
123
124       if (real_iter->in_array)
125         {
126           real_iter->finished = TRUE;
127           return FALSE;
128         }
129
130       pos = 0;
131       _dbus_type_signature_next (real_iter->pos, &pos);
132       real_iter->pos += pos;
133
134       if (*real_iter->pos == DBUS_STRUCT_END_CHAR
135           || *real_iter->pos == DBUS_DICT_ENTRY_END_CHAR)
136         {
137           real_iter->finished = TRUE;
138           return FALSE;
139         }
140
141       return *real_iter->pos != DBUS_TYPE_INVALID;
142     }
143 }
144
145 /**
146  * Initialize a new iterator pointing to the first type current
147  * container. It's an error to call this if the current type is a
148  * non-container (i.e. if dbus_type_is_container returns FALSE).
149  *
150  * @param iter the current interator
151  * @param subiter an iterator to initialize pointing to the first child
152  */
153 void
154 dbus_signature_iter_recurse (const DBusSignatureIter *iter,
155                              DBusSignatureIter       *subiter)
156 {
157   DBusSignatureRealIter *real_iter = (DBusSignatureRealIter *) iter;
158   DBusSignatureRealIter *real_sub_iter = (DBusSignatureRealIter *) subiter;
159
160   _dbus_return_if_fail (dbus_type_is_container (dbus_signature_iter_get_current_type (iter)));
161
162   *real_sub_iter = *real_iter;
163   real_sub_iter->pos++;
164
165   if (dbus_signature_iter_get_current_type (subiter) == DBUS_TYPE_ARRAY)
166     real_sub_iter->in_array = TRUE;
167 }
168
169 /**
170  * Check a type signature for validity.
171  *
172  * @param signature a potentially invalid type signature
173  * @error error return
174  * @returns TRUE iif signature is valid
175  */
176 dbus_bool_t
177 dbus_signature_validate (const char       *signature,
178                          DBusError        *error)
179                          
180 {
181   DBusString str;
182
183   _dbus_string_init_const (&str, signature);
184   if (_dbus_validate_signature (&str, 0, _dbus_string_get_length (&str)))
185     return TRUE;
186   dbus_set_error (error, DBUS_ERROR_INVALID_SIGNATURE, "Corrupt type signature");
187   return FALSE;
188 }
189
190 /**
191  * Check that a type signature is both valid and contains exactly
192  * one complete type.
193  *
194  * @param signature a potentially invalid type signature
195  * @error error return
196  * @returns TRUE iif signature is valid and has exactly one complete type
197  */
198 dbus_bool_t
199 dbus_signature_validate_single (const char       *signature,
200                                 DBusError        *error)
201 {
202   DBusSignatureIter iter;
203
204   if (!dbus_signature_validate (signature, error))
205     return FALSE;
206
207   dbus_signature_iter_init (&iter, signature);
208   if (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_INVALID)
209     goto lose;
210   if (!dbus_signature_iter_next (&iter))
211     return TRUE;
212  lose:
213   dbus_set_error (error, DBUS_ERROR_INVALID_SIGNATURE, "Exactly one complete type required in signature");
214   return FALSE;
215 }
216
217 /** macro that checks whether a typecode is a container type */
218 #define TYPE_IS_CONTAINER(typecode)             \
219     ((typecode) == DBUS_TYPE_STRUCT ||          \
220      (typecode) == DBUS_TYPE_DICT_ENTRY ||      \
221      (typecode) == DBUS_TYPE_VARIANT ||         \
222      (typecode) == DBUS_TYPE_ARRAY)
223
224 /**
225  * A "container type" can contain basic types, or nested
226  * container types. #DBUS_TYPE_INVALID is not a container type.
227  * This function will crash if passed a typecode that isn't
228  * in dbus-protocol.h
229  *
230  * @returns #TRUE if type is a container
231  */
232 dbus_bool_t
233 dbus_type_is_container (int typecode)
234 {
235   /* only reasonable (non-line-noise) typecodes are allowed */
236   _dbus_return_val_if_fail (_dbus_type_is_valid (typecode) || typecode == DBUS_TYPE_INVALID,
237                             FALSE);
238   return TYPE_IS_CONTAINER (typecode);
239 }
240
241 /**
242  * A "basic type" is a somewhat arbitrary concept, but the intent
243  * is to include those types that are fully-specified by a single
244  * typecode, with no additional type information or nested
245  * values. So all numbers and strings are basic types and
246  * structs, arrays, and variants are not basic types.
247  * #DBUS_TYPE_INVALID is not a basic type.
248  *
249  * This function will crash if passed a typecode that isn't
250  * in dbus-protocol.h
251  *
252  * @returns #TRUE if type is basic
253  */
254 dbus_bool_t
255 dbus_type_is_basic (int typecode)
256 {
257   /* only reasonable (non-line-noise) typecodes are allowed */
258   _dbus_return_val_if_fail (_dbus_type_is_valid (typecode) || typecode == DBUS_TYPE_INVALID,
259                             FALSE);
260
261   /* everything that isn't invalid or a container */
262   return !(typecode == DBUS_TYPE_INVALID || TYPE_IS_CONTAINER (typecode));
263 }
264
265 /**
266  * Tells you whether values of this type can change length if you set
267  * them to some other value. For this purpose, you assume that the
268  * first byte of the old and new value would be in the same location,
269  * so alignment padding is not a factor.
270  *
271  * This function is useful to determine whether #dbus_message_iter_get_fixed_array
272  * may be used.
273  *
274  * @returns #FALSE if the type can occupy different lengths
275  */
276 dbus_bool_t
277 dbus_type_is_fixed (int typecode)
278 {
279   switch (typecode)
280     {
281     case DBUS_TYPE_BYTE:
282     case DBUS_TYPE_BOOLEAN:
283     case DBUS_TYPE_INT16:
284     case DBUS_TYPE_UINT16:
285     case DBUS_TYPE_INT32:
286     case DBUS_TYPE_UINT32:
287     case DBUS_TYPE_INT64:
288     case DBUS_TYPE_UINT64:
289     case DBUS_TYPE_DOUBLE:
290       return TRUE;
291     default:
292       return FALSE;
293     }
294 }
295
296 #ifdef DBUS_BUILD_TESTS
297
298 /**
299  * @ingroup DBusSignatureInternals
300  * Unit test for DBusSignature.
301  *
302  * @returns #TRUE on success.
303  */
304 dbus_bool_t
305 _dbus_signature_test (void)
306 {
307   DBusSignatureIter iter;
308   DBusSignatureIter subiter;
309   DBusSignatureIter subsubiter;
310   DBusSignatureIter subsubsubiter;
311   const char *sig;
312
313   _dbus_assert (sizeof (DBusSignatureIter) >= sizeof (DBusSignatureRealIter));
314
315   sig = "";
316   _dbus_assert (dbus_signature_validate (sig, NULL));
317   _dbus_assert (!dbus_signature_validate_single (sig, NULL));
318   dbus_signature_iter_init (&iter, sig);
319   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_INVALID);
320
321   sig = DBUS_TYPE_STRING_AS_STRING;
322   _dbus_assert (dbus_signature_validate (sig, NULL));
323   _dbus_assert (dbus_signature_validate_single (sig, NULL));
324   dbus_signature_iter_init (&iter, sig);
325   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_STRING);
326
327   sig = DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_BYTE_AS_STRING;
328   _dbus_assert (dbus_signature_validate (sig, NULL));
329   dbus_signature_iter_init (&iter, sig);
330   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_STRING);
331   _dbus_assert (dbus_signature_iter_next (&iter));
332   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_BYTE);
333
334   sig = DBUS_TYPE_UINT16_AS_STRING
335     DBUS_STRUCT_BEGIN_CHAR_AS_STRING
336     DBUS_TYPE_STRING_AS_STRING
337     DBUS_TYPE_UINT32_AS_STRING
338     DBUS_TYPE_VARIANT_AS_STRING
339     DBUS_TYPE_DOUBLE_AS_STRING
340     DBUS_STRUCT_END_CHAR_AS_STRING;
341   _dbus_assert (dbus_signature_validate (sig, NULL));
342   dbus_signature_iter_init (&iter, sig);
343   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_UINT16);
344   _dbus_assert (dbus_signature_iter_next (&iter));
345   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_STRUCT);
346   dbus_signature_iter_recurse (&iter, &subiter);
347   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_STRING);
348   _dbus_assert (dbus_signature_iter_next (&subiter));
349   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_UINT32);
350   _dbus_assert (dbus_signature_iter_next (&subiter));
351   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_VARIANT);
352   _dbus_assert (dbus_signature_iter_next (&subiter));
353   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_DOUBLE);
354
355   sig = DBUS_TYPE_UINT16_AS_STRING
356     DBUS_STRUCT_BEGIN_CHAR_AS_STRING
357     DBUS_TYPE_UINT32_AS_STRING
358     DBUS_TYPE_BYTE_AS_STRING
359     DBUS_TYPE_ARRAY_AS_STRING
360     DBUS_TYPE_ARRAY_AS_STRING
361     DBUS_TYPE_DOUBLE_AS_STRING
362     DBUS_STRUCT_BEGIN_CHAR_AS_STRING
363     DBUS_TYPE_BYTE_AS_STRING
364     DBUS_STRUCT_END_CHAR_AS_STRING
365     DBUS_STRUCT_END_CHAR_AS_STRING;
366   _dbus_assert (dbus_signature_validate (sig, NULL));
367   dbus_signature_iter_init (&iter, sig);
368   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_UINT16);
369   _dbus_assert (dbus_signature_iter_next (&iter));
370   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_STRUCT);
371   dbus_signature_iter_recurse (&iter, &subiter);
372   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_UINT32);
373   _dbus_assert (dbus_signature_iter_next (&subiter));
374   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_BYTE);
375   _dbus_assert (dbus_signature_iter_next (&subiter));
376   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_ARRAY);
377   _dbus_assert (dbus_signature_iter_get_element_type (&subiter) == DBUS_TYPE_ARRAY);
378
379   dbus_signature_iter_recurse (&subiter, &subsubiter);
380   _dbus_assert (dbus_signature_iter_get_current_type (&subsubiter) == DBUS_TYPE_ARRAY);
381   _dbus_assert (dbus_signature_iter_get_element_type (&subsubiter) == DBUS_TYPE_DOUBLE);
382
383   dbus_signature_iter_recurse (&subsubiter, &subsubsubiter);
384   _dbus_assert (dbus_signature_iter_get_current_type (&subsubsubiter) == DBUS_TYPE_DOUBLE);
385   _dbus_assert (dbus_signature_iter_next (&subiter));
386   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_STRUCT);
387   dbus_signature_iter_recurse (&subiter, &subsubiter);
388   _dbus_assert (dbus_signature_iter_get_current_type (&subsubiter) == DBUS_TYPE_BYTE);
389
390   sig = DBUS_TYPE_ARRAY_AS_STRING
391     DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
392     DBUS_TYPE_INT16_AS_STRING
393     DBUS_TYPE_STRING_AS_STRING
394     DBUS_DICT_ENTRY_END_CHAR_AS_STRING
395     DBUS_TYPE_VARIANT_AS_STRING;
396   _dbus_assert (dbus_signature_validate (sig, NULL));
397   _dbus_assert (!dbus_signature_validate_single (sig, NULL));
398   dbus_signature_iter_init (&iter, sig);
399   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_ARRAY);
400   _dbus_assert (dbus_signature_iter_get_element_type (&iter) == DBUS_TYPE_DICT_ENTRY);
401
402   dbus_signature_iter_recurse (&iter, &subiter);
403   dbus_signature_iter_recurse (&subiter, &subsubiter);
404   _dbus_assert (dbus_signature_iter_get_current_type (&subsubiter) == DBUS_TYPE_INT16);
405   _dbus_assert (dbus_signature_iter_next (&subsubiter));
406   _dbus_assert (dbus_signature_iter_get_current_type (&subsubiter) == DBUS_TYPE_STRING);
407   _dbus_assert (!dbus_signature_iter_next (&subsubiter));
408
409   _dbus_assert (dbus_signature_iter_next (&iter));
410   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_VARIANT);
411   _dbus_assert (!dbus_signature_iter_next (&iter));
412
413   sig = DBUS_TYPE_DICT_ENTRY_AS_STRING;
414   _dbus_assert (!dbus_signature_validate (sig, NULL));
415
416   sig = DBUS_TYPE_ARRAY_AS_STRING;
417   _dbus_assert (!dbus_signature_validate (sig, NULL));
418
419   sig = DBUS_TYPE_UINT32_AS_STRING
420     DBUS_TYPE_ARRAY_AS_STRING;
421   _dbus_assert (!dbus_signature_validate (sig, NULL));
422
423   sig = DBUS_TYPE_ARRAY_AS_STRING
424     DBUS_TYPE_DICT_ENTRY_AS_STRING;
425   _dbus_assert (!dbus_signature_validate (sig, NULL));
426
427   sig = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING;
428   _dbus_assert (!dbus_signature_validate (sig, NULL));
429
430   sig = DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
431   _dbus_assert (!dbus_signature_validate (sig, NULL));
432
433   sig = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
434     DBUS_TYPE_INT32_AS_STRING;
435   _dbus_assert (!dbus_signature_validate (sig, NULL));
436
437   sig = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
438     DBUS_TYPE_INT32_AS_STRING
439     DBUS_TYPE_STRING_AS_STRING;
440   _dbus_assert (!dbus_signature_validate (sig, NULL));
441
442   sig = DBUS_STRUCT_END_CHAR_AS_STRING
443     DBUS_STRUCT_BEGIN_CHAR_AS_STRING;
444   _dbus_assert (!dbus_signature_validate (sig, NULL));
445
446   sig = DBUS_STRUCT_BEGIN_CHAR_AS_STRING
447     DBUS_TYPE_BOOLEAN_AS_STRING;
448   _dbus_assert (!dbus_signature_validate (sig, NULL));
449   return TRUE;
450 #if 0
451  oom:
452   _dbus_assert_not_reached ("out of memory");
453   return FALSE;
454 #endif
455 }
456
457 #endif
458
459 /** @} */ /* end of DBusSignature group */
460