2006-10-19 Havoc Pennington <hp@redhat.com>
[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;           /**< current position in the signature string */
33   unsigned int finished : 1; /**< true if we are at the end iter */
34   unsigned int in_array : 1; /**< true if we are a subiterator pointing to an array's element type */
35 } DBusSignatureRealIter;
36
37 /**
38  * @defgroup DBusSignature Type signature parsing
39  * @ingroup  DBus
40  * @brief Parsing D-Bus type signatures
41  * @{
42  */
43
44 /**
45  * Initializes a #DBusSignatureIter for reading a type signature.  This
46  * function is not safe to use on invalid signatures; be sure to
47  * validate potentially invalid signatures with dbus_signature_validate
48  * before using this function.
49  *
50  * @param iter pointer to an iterator to initialize
51  * @param signature the type signature
52  */
53 void
54 dbus_signature_iter_init (DBusSignatureIter *iter,
55                           const char        *signature)
56 {
57   DBusSignatureRealIter *real_iter = (DBusSignatureRealIter *) iter;
58
59   real_iter->pos = signature;
60   real_iter->finished = FALSE;
61   real_iter->in_array = FALSE;
62 }
63
64 /**
65  * Returns the current type pointed to by the iterator.
66  * If the iterator is pointing at a type code such as 's', then
67  * it will be returned directly.
68  *
69  * However, when the parser encounters a container type start
70  * character such as '(' for a structure, the corresponding type for
71  * the container will be returned, e.g.  DBUS_TYPE_STRUCT, not '('.
72  * In this case, you should initialize a sub-iterator with
73  * dbus_signature_iter_recurse to parse the container type.
74  *
75  * @param iter pointer to an iterator 
76  * @returns current type (e.g. DBUS_TYPE_STRING, DBUS_TYPE_ARRAY)
77  */
78 int
79 dbus_signature_iter_get_current_type (const DBusSignatureIter *iter)
80 {
81   DBusSignatureRealIter *real_iter = (DBusSignatureRealIter *) iter;
82
83   return _dbus_first_type_in_signature_c_str (real_iter->pos, 0);
84 }
85
86 /**
87  * Returns the full type signature represented by the current
88  * iterator as a C string.
89  *
90  * @param iter pointer to an iterator 
91  * @returns current signature; or NULL on OOM.  Should be freed with #dbus_free
92  */
93 char *
94 dbus_signature_iter_get_signature (const DBusSignatureIter *iter)
95 {
96   DBusSignatureRealIter *real_iter = (DBusSignatureRealIter *) iter;
97   DBusString str;
98   char *ret;
99   int pos;
100   
101   if (!_dbus_string_init (&str))
102     return NULL;
103
104   pos = 0;
105   _dbus_type_signature_next (real_iter->pos, &pos);
106
107   if (!_dbus_string_append_len (&str, real_iter->pos, pos))
108     return NULL;
109   if (!_dbus_string_steal_data (&str, &ret))
110     ret = NULL;
111   _dbus_string_free (&str);
112
113   return ret; 
114 }
115
116 /**
117  * Convenience function for returning the element type of an array;
118  * This function allows you to avoid initializing a sub-iterator and
119  * getting its current type.
120  *
121  * It is an error to invoke this function if the current type of the
122  * iterator is not DBUS_TYPE_ARRAY.
123  *
124  * @param iter pointer to an iterator 
125  * @returns current array element type
126  */
127 int
128 dbus_signature_iter_get_element_type (const DBusSignatureIter *iter)
129 {
130   DBusSignatureRealIter *real_iter = (DBusSignatureRealIter *) iter;
131
132   _dbus_return_val_if_fail (dbus_signature_iter_get_current_type (iter) == DBUS_TYPE_ARRAY, DBUS_TYPE_INVALID);
133
134   return _dbus_first_type_in_signature_c_str (real_iter->pos, 1);
135 }
136
137 /**
138  * Skip to the next value on this "level". e.g. the next field in a
139  * struct, the next value in an array. Returns FALSE at the end of the
140  * current container.
141  *
142  * @param iter the iterator
143  * @returns FALSE if nothing more to read at or below this level
144  */
145 dbus_bool_t
146 dbus_signature_iter_next (DBusSignatureIter *iter)
147 {
148   DBusSignatureRealIter *real_iter = (DBusSignatureRealIter *) iter;
149
150   if (real_iter->finished)
151     return FALSE;
152   else
153     {
154       int pos;
155
156       if (real_iter->in_array)
157         {
158           real_iter->finished = TRUE;
159           return FALSE;
160         }
161
162       pos = 0;
163       _dbus_type_signature_next (real_iter->pos, &pos);
164       real_iter->pos += pos;
165
166       if (*real_iter->pos == DBUS_STRUCT_END_CHAR
167           || *real_iter->pos == DBUS_DICT_ENTRY_END_CHAR)
168         {
169           real_iter->finished = TRUE;
170           return FALSE;
171         }
172
173       return *real_iter->pos != DBUS_TYPE_INVALID;
174     }
175 }
176
177 /**
178  * Initialize a new iterator pointing to the first type current
179  * container. It's an error to call this if the current type is a
180  * non-container (i.e. if dbus_type_is_container returns FALSE).
181  *
182  * @param iter the current interator
183  * @param subiter an iterator to initialize pointing to the first child
184  */
185 void
186 dbus_signature_iter_recurse (const DBusSignatureIter *iter,
187                              DBusSignatureIter       *subiter)
188 {
189   DBusSignatureRealIter *real_iter = (DBusSignatureRealIter *) iter;
190   DBusSignatureRealIter *real_sub_iter = (DBusSignatureRealIter *) subiter;
191
192   _dbus_return_if_fail (dbus_type_is_container (dbus_signature_iter_get_current_type (iter)));
193
194   *real_sub_iter = *real_iter;
195   real_sub_iter->in_array = FALSE;
196   real_sub_iter->pos++;
197
198   if (dbus_signature_iter_get_current_type (iter) == DBUS_TYPE_ARRAY)
199     real_sub_iter->in_array = TRUE;
200 }
201
202 /**
203  * Check a type signature for validity.
204  *
205  * @param signature a potentially invalid type signature
206  * @param error error return
207  * @returns TRUE iif signature is valid
208  */
209 dbus_bool_t
210 dbus_signature_validate (const char       *signature,
211                          DBusError        *error)
212                          
213 {
214   DBusString str;
215
216   _dbus_string_init_const (&str, signature);
217   if (_dbus_validate_signature (&str, 0, _dbus_string_get_length (&str)))
218     return TRUE;
219   dbus_set_error (error, DBUS_ERROR_INVALID_SIGNATURE, "Corrupt type signature");
220   return FALSE;
221 }
222
223 /**
224  * Check that a type signature is both valid and contains exactly
225  * one complete type.
226  *
227  * @param signature a potentially invalid type signature
228  * @param error error return
229  * @returns TRUE iif signature is valid and has exactly one complete type
230  */
231 dbus_bool_t
232 dbus_signature_validate_single (const char       *signature,
233                                 DBusError        *error)
234 {
235   DBusSignatureIter iter;
236
237   if (!dbus_signature_validate (signature, error))
238     return FALSE;
239
240   dbus_signature_iter_init (&iter, signature);
241   if (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_INVALID)
242     goto lose;
243   if (!dbus_signature_iter_next (&iter))
244     return TRUE;
245  lose:
246   dbus_set_error (error, DBUS_ERROR_INVALID_SIGNATURE, "Exactly one complete type required in signature");
247   return FALSE;
248 }
249
250 /** macro that checks whether a typecode is a container type */
251 #define TYPE_IS_CONTAINER(typecode)             \
252     ((typecode) == DBUS_TYPE_STRUCT ||          \
253      (typecode) == DBUS_TYPE_DICT_ENTRY ||      \
254      (typecode) == DBUS_TYPE_VARIANT ||         \
255      (typecode) == DBUS_TYPE_ARRAY)
256
257 /**
258  * A "container type" can contain basic types, or nested
259  * container types. #DBUS_TYPE_INVALID is not a container type.
260  * This function will crash if passed a typecode that isn't
261  * in dbus-protocol.h
262  *
263  * @returns #TRUE if type is a container
264  */
265 dbus_bool_t
266 dbus_type_is_container (int typecode)
267 {
268   /* only reasonable (non-line-noise) typecodes are allowed */
269   _dbus_return_val_if_fail (_dbus_type_is_valid (typecode) || typecode == DBUS_TYPE_INVALID,
270                             FALSE);
271   return TYPE_IS_CONTAINER (typecode);
272 }
273
274 /**
275  * A "basic type" is a somewhat arbitrary concept, but the intent
276  * is to include those types that are fully-specified by a single
277  * typecode, with no additional type information or nested
278  * values. So all numbers and strings are basic types and
279  * structs, arrays, and variants are not basic types.
280  * #DBUS_TYPE_INVALID is not a basic type.
281  *
282  * This function will crash if passed a typecode that isn't
283  * in dbus-protocol.h
284  *
285  * @returns #TRUE if type is basic
286  */
287 dbus_bool_t
288 dbus_type_is_basic (int typecode)
289 {
290   /* only reasonable (non-line-noise) typecodes are allowed */
291   _dbus_return_val_if_fail (_dbus_type_is_valid (typecode) || typecode == DBUS_TYPE_INVALID,
292                             FALSE);
293
294   /* everything that isn't invalid or a container */
295   return !(typecode == DBUS_TYPE_INVALID || TYPE_IS_CONTAINER (typecode));
296 }
297
298 /**
299  * Tells you whether values of this type can change length if you set
300  * them to some other value. For this purpose, you assume that the
301  * first byte of the old and new value would be in the same location,
302  * so alignment padding is not a factor.
303  *
304  * This function is useful to determine whether #dbus_message_iter_get_fixed_array
305  * may be used.
306  *
307  * @returns #FALSE if the type can occupy different lengths
308  */
309 dbus_bool_t
310 dbus_type_is_fixed (int typecode)
311 {
312   switch (typecode)
313     {
314     case DBUS_TYPE_BYTE:
315     case DBUS_TYPE_BOOLEAN:
316     case DBUS_TYPE_INT16:
317     case DBUS_TYPE_UINT16:
318     case DBUS_TYPE_INT32:
319     case DBUS_TYPE_UINT32:
320     case DBUS_TYPE_INT64:
321     case DBUS_TYPE_UINT64:
322     case DBUS_TYPE_DOUBLE:
323       return TRUE;
324     default:
325       return FALSE;
326     }
327 }
328
329 #ifdef DBUS_BUILD_TESTS
330
331 /**
332  * @ingroup DBusSignatureInternals
333  * Unit test for DBusSignature.
334  *
335  * @returns #TRUE on success.
336  */
337 dbus_bool_t
338 _dbus_signature_test (void)
339 {
340   DBusSignatureIter iter;
341   DBusSignatureIter subiter;
342   DBusSignatureIter subsubiter;
343   DBusSignatureIter subsubsubiter;
344   const char *sig;
345   dbus_bool_t boolres;
346
347   _dbus_assert (sizeof (DBusSignatureIter) >= sizeof (DBusSignatureRealIter));
348
349   sig = "";
350   _dbus_assert (dbus_signature_validate (sig, NULL));
351   _dbus_assert (!dbus_signature_validate_single (sig, NULL));
352   dbus_signature_iter_init (&iter, sig);
353   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_INVALID);
354
355   sig = DBUS_TYPE_STRING_AS_STRING;
356   _dbus_assert (dbus_signature_validate (sig, NULL));
357   _dbus_assert (dbus_signature_validate_single (sig, NULL));
358   dbus_signature_iter_init (&iter, sig);
359   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_STRING);
360
361   sig = DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_BYTE_AS_STRING;
362   _dbus_assert (dbus_signature_validate (sig, NULL));
363   dbus_signature_iter_init (&iter, sig);
364   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_STRING);
365   boolres = dbus_signature_iter_next (&iter);
366   _dbus_assert (boolres);
367   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_BYTE);
368
369   sig = DBUS_TYPE_UINT16_AS_STRING
370     DBUS_STRUCT_BEGIN_CHAR_AS_STRING
371     DBUS_TYPE_STRING_AS_STRING
372     DBUS_TYPE_UINT32_AS_STRING
373     DBUS_TYPE_VARIANT_AS_STRING
374     DBUS_TYPE_DOUBLE_AS_STRING
375     DBUS_STRUCT_END_CHAR_AS_STRING;
376   _dbus_assert (dbus_signature_validate (sig, NULL));
377   dbus_signature_iter_init (&iter, sig);
378   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_UINT16);
379   boolres = dbus_signature_iter_next (&iter);
380   _dbus_assert (boolres);
381   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_STRUCT);
382   dbus_signature_iter_recurse (&iter, &subiter);
383   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_STRING);
384   boolres = dbus_signature_iter_next (&subiter);
385   _dbus_assert (boolres);
386   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_UINT32);
387   boolres = dbus_signature_iter_next (&subiter);
388   _dbus_assert (boolres);
389   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_VARIANT);
390   boolres = dbus_signature_iter_next (&subiter);
391   _dbus_assert (boolres);
392   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_DOUBLE);
393
394   sig = DBUS_TYPE_UINT16_AS_STRING
395     DBUS_STRUCT_BEGIN_CHAR_AS_STRING
396     DBUS_TYPE_UINT32_AS_STRING
397     DBUS_TYPE_BYTE_AS_STRING
398     DBUS_TYPE_ARRAY_AS_STRING
399     DBUS_TYPE_ARRAY_AS_STRING
400     DBUS_TYPE_DOUBLE_AS_STRING
401     DBUS_STRUCT_BEGIN_CHAR_AS_STRING
402     DBUS_TYPE_BYTE_AS_STRING
403     DBUS_STRUCT_END_CHAR_AS_STRING
404     DBUS_STRUCT_END_CHAR_AS_STRING;
405   _dbus_assert (dbus_signature_validate (sig, NULL));
406   dbus_signature_iter_init (&iter, sig);
407   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_UINT16);
408   boolres = dbus_signature_iter_next (&iter);
409   _dbus_assert (boolres);
410   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_STRUCT);
411   dbus_signature_iter_recurse (&iter, &subiter);
412   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_UINT32);
413   boolres = dbus_signature_iter_next (&subiter);
414   _dbus_assert (boolres);
415   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_BYTE);
416   boolres = dbus_signature_iter_next (&subiter);
417   _dbus_assert (boolres);
418   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_ARRAY);
419   _dbus_assert (dbus_signature_iter_get_element_type (&subiter) == DBUS_TYPE_ARRAY);
420
421   dbus_signature_iter_recurse (&subiter, &subsubiter);
422   _dbus_assert (dbus_signature_iter_get_current_type (&subsubiter) == DBUS_TYPE_ARRAY);
423   _dbus_assert (dbus_signature_iter_get_element_type (&subsubiter) == DBUS_TYPE_DOUBLE);
424
425   dbus_signature_iter_recurse (&subsubiter, &subsubsubiter);
426   _dbus_assert (dbus_signature_iter_get_current_type (&subsubsubiter) == DBUS_TYPE_DOUBLE);
427   boolres = dbus_signature_iter_next (&subiter);
428   _dbus_assert (boolres);
429   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_STRUCT);
430   dbus_signature_iter_recurse (&subiter, &subsubiter);
431   _dbus_assert (dbus_signature_iter_get_current_type (&subsubiter) == DBUS_TYPE_BYTE);
432
433   sig = DBUS_TYPE_ARRAY_AS_STRING
434     DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
435     DBUS_TYPE_INT16_AS_STRING
436     DBUS_TYPE_STRING_AS_STRING
437     DBUS_DICT_ENTRY_END_CHAR_AS_STRING
438     DBUS_TYPE_VARIANT_AS_STRING;
439   _dbus_assert (dbus_signature_validate (sig, NULL));
440   _dbus_assert (!dbus_signature_validate_single (sig, NULL));
441   dbus_signature_iter_init (&iter, sig);
442   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_ARRAY);
443   _dbus_assert (dbus_signature_iter_get_element_type (&iter) == DBUS_TYPE_DICT_ENTRY);
444
445   dbus_signature_iter_recurse (&iter, &subiter);
446   dbus_signature_iter_recurse (&subiter, &subsubiter);
447   _dbus_assert (dbus_signature_iter_get_current_type (&subsubiter) == DBUS_TYPE_INT16);
448   boolres = dbus_signature_iter_next (&subsubiter);
449   _dbus_assert (boolres);
450   _dbus_assert (dbus_signature_iter_get_current_type (&subsubiter) == DBUS_TYPE_STRING);
451   boolres = dbus_signature_iter_next (&subsubiter);
452   _dbus_assert (!boolres);
453
454   boolres = dbus_signature_iter_next (&iter);
455   _dbus_assert (boolres);
456   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_VARIANT);
457   boolres = dbus_signature_iter_next (&iter);
458   _dbus_assert (!boolres);
459
460   sig = DBUS_TYPE_DICT_ENTRY_AS_STRING;
461   _dbus_assert (!dbus_signature_validate (sig, NULL));
462
463   sig = DBUS_TYPE_ARRAY_AS_STRING;
464   _dbus_assert (!dbus_signature_validate (sig, NULL));
465
466   sig = DBUS_TYPE_UINT32_AS_STRING
467     DBUS_TYPE_ARRAY_AS_STRING;
468   _dbus_assert (!dbus_signature_validate (sig, NULL));
469
470   sig = DBUS_TYPE_ARRAY_AS_STRING
471     DBUS_TYPE_DICT_ENTRY_AS_STRING;
472   _dbus_assert (!dbus_signature_validate (sig, NULL));
473
474   sig = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING;
475   _dbus_assert (!dbus_signature_validate (sig, NULL));
476
477   sig = DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
478   _dbus_assert (!dbus_signature_validate (sig, NULL));
479
480   sig = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
481     DBUS_TYPE_INT32_AS_STRING;
482   _dbus_assert (!dbus_signature_validate (sig, NULL));
483
484   sig = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
485     DBUS_TYPE_INT32_AS_STRING
486     DBUS_TYPE_STRING_AS_STRING;
487   _dbus_assert (!dbus_signature_validate (sig, NULL));
488
489   sig = DBUS_STRUCT_END_CHAR_AS_STRING
490     DBUS_STRUCT_BEGIN_CHAR_AS_STRING;
491   _dbus_assert (!dbus_signature_validate (sig, NULL));
492
493   sig = DBUS_STRUCT_BEGIN_CHAR_AS_STRING
494     DBUS_TYPE_BOOLEAN_AS_STRING;
495   _dbus_assert (!dbus_signature_validate (sig, NULL));
496   return TRUE;
497 #if 0
498  oom:
499   _dbus_assert_not_reached ("out of memory");
500   return FALSE;
501 #endif
502 }
503
504 #endif
505
506 /** @} */ /* end of DBusSignature group */
507