2005-02-24 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_retur(dbus_signature_iter_get_current_type (iter) == DBUS_TYPE_ARRAY);
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 #ifdef DBUS_BUILD_TESTS
267
268 /**
269  * @ingroup DBusSignatureInternals
270  * Unit test for DBusSignature.
271  *
272  * @returns #TRUE on success.
273  */
274 dbus_bool_t
275 _dbus_signature_test (void)
276 {
277   DBusSignatureIter iter;
278   DBusSignatureIter subiter;
279   DBusSignatureIter subsubiter;
280   DBusSignatureIter subsubsubiter;
281   const char *sig;
282
283   _dbus_assert (sizeof (DBusSignatureIter) >= sizeof (DBusSignatureRealIter));
284
285   sig = "";
286   _dbus_assert (dbus_signature_validate (sig, NULL));
287   _dbus_assert (!dbus_signature_validate_single (sig, NULL));
288   dbus_signature_iter_init (&iter, sig);
289   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_INVALID);
290
291   sig = DBUS_TYPE_STRING_AS_STRING;
292   _dbus_assert (dbus_signature_validate (sig, NULL));
293   _dbus_assert (dbus_signature_validate_single (sig, NULL));
294   dbus_signature_iter_init (&iter, sig);
295   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_STRING);
296
297   sig = DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_BYTE_AS_STRING;
298   _dbus_assert (dbus_signature_validate (sig, NULL));
299   dbus_signature_iter_init (&iter, sig);
300   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_STRING);
301   _dbus_assert (dbus_signature_iter_next (&iter));
302   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_BYTE);
303
304   sig = DBUS_TYPE_UINT16_AS_STRING
305     DBUS_STRUCT_BEGIN_CHAR_AS_STRING
306     DBUS_TYPE_STRING_AS_STRING
307     DBUS_TYPE_UINT32_AS_STRING
308     DBUS_TYPE_VARIANT_AS_STRING
309     DBUS_TYPE_DOUBLE_AS_STRING
310     DBUS_STRUCT_END_CHAR_AS_STRING;
311   _dbus_assert (dbus_signature_validate (sig, NULL));
312   dbus_signature_iter_init (&iter, sig);
313   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_UINT16);
314   _dbus_assert (dbus_signature_iter_next (&iter));
315   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_STRUCT);
316   dbus_signature_iter_recurse (&iter, &subiter);
317   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_STRING);
318   _dbus_assert (dbus_signature_iter_next (&subiter));
319   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_UINT32);
320   _dbus_assert (dbus_signature_iter_next (&subiter));
321   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_VARIANT);
322   _dbus_assert (dbus_signature_iter_next (&subiter));
323   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_DOUBLE);
324
325   sig = DBUS_TYPE_UINT16_AS_STRING
326     DBUS_STRUCT_BEGIN_CHAR_AS_STRING
327     DBUS_TYPE_UINT32_AS_STRING
328     DBUS_TYPE_BYTE_AS_STRING
329     DBUS_TYPE_ARRAY_AS_STRING
330     DBUS_TYPE_ARRAY_AS_STRING
331     DBUS_TYPE_DOUBLE_AS_STRING
332     DBUS_STRUCT_BEGIN_CHAR_AS_STRING
333     DBUS_TYPE_BYTE_AS_STRING
334     DBUS_STRUCT_END_CHAR_AS_STRING
335     DBUS_STRUCT_END_CHAR_AS_STRING;
336   _dbus_assert (dbus_signature_validate (sig, NULL));
337   dbus_signature_iter_init (&iter, sig);
338   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_UINT16);
339   _dbus_assert (dbus_signature_iter_next (&iter));
340   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_STRUCT);
341   dbus_signature_iter_recurse (&iter, &subiter);
342   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_UINT32);
343   _dbus_assert (dbus_signature_iter_next (&subiter));
344   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_BYTE);
345   _dbus_assert (dbus_signature_iter_next (&subiter));
346   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_ARRAY);
347   _dbus_assert (dbus_signature_iter_get_element_type (&subiter) == DBUS_TYPE_ARRAY);
348
349   dbus_signature_iter_recurse (&subiter, &subsubiter);
350   _dbus_assert (dbus_signature_iter_get_current_type (&subsubiter) == DBUS_TYPE_ARRAY);
351   _dbus_assert (dbus_signature_iter_get_element_type (&subsubiter) == DBUS_TYPE_DOUBLE);
352
353   dbus_signature_iter_recurse (&subsubiter, &subsubsubiter);
354   _dbus_assert (dbus_signature_iter_get_current_type (&subsubsubiter) == DBUS_TYPE_DOUBLE);
355   _dbus_assert (dbus_signature_iter_next (&subiter));
356   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_STRUCT);
357   dbus_signature_iter_recurse (&subiter, &subsubiter);
358   _dbus_assert (dbus_signature_iter_get_current_type (&subsubiter) == DBUS_TYPE_BYTE);
359
360   sig = DBUS_TYPE_ARRAY_AS_STRING
361     DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
362     DBUS_TYPE_INT16_AS_STRING
363     DBUS_TYPE_STRING_AS_STRING
364     DBUS_DICT_ENTRY_END_CHAR_AS_STRING
365     DBUS_TYPE_VARIANT_AS_STRING;
366   _dbus_assert (dbus_signature_validate (sig, NULL));
367   _dbus_assert (!dbus_signature_validate_single (sig, NULL));
368   dbus_signature_iter_init (&iter, sig);
369   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_ARRAY);
370   _dbus_assert (dbus_signature_iter_get_element_type (&iter) == DBUS_TYPE_DICT_ENTRY);
371
372   dbus_signature_iter_recurse (&iter, &subiter);
373   dbus_signature_iter_recurse (&subiter, &subsubiter);
374   _dbus_assert (dbus_signature_iter_get_current_type (&subsubiter) == DBUS_TYPE_INT16);
375   _dbus_assert (dbus_signature_iter_next (&subsubiter));
376   _dbus_assert (dbus_signature_iter_get_current_type (&subsubiter) == DBUS_TYPE_STRING);
377   _dbus_assert (!dbus_signature_iter_next (&subsubiter));
378
379   _dbus_assert (dbus_signature_iter_next (&iter));
380   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_VARIANT);
381   _dbus_assert (!dbus_signature_iter_next (&iter));
382
383   sig = DBUS_TYPE_DICT_ENTRY_AS_STRING;
384   _dbus_assert (!dbus_signature_validate (sig, NULL));
385
386   sig = DBUS_TYPE_ARRAY_AS_STRING;
387   _dbus_assert (!dbus_signature_validate (sig, NULL));
388
389   sig = DBUS_TYPE_UINT32_AS_STRING
390     DBUS_TYPE_ARRAY_AS_STRING;
391   _dbus_assert (!dbus_signature_validate (sig, NULL));
392
393   sig = DBUS_TYPE_ARRAY_AS_STRING
394     DBUS_TYPE_DICT_ENTRY_AS_STRING;
395   _dbus_assert (!dbus_signature_validate (sig, NULL));
396
397   sig = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING;
398   _dbus_assert (!dbus_signature_validate (sig, NULL));
399
400   sig = DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
401   _dbus_assert (!dbus_signature_validate (sig, NULL));
402
403   sig = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
404     DBUS_TYPE_INT32_AS_STRING;
405   _dbus_assert (!dbus_signature_validate (sig, NULL));
406
407   sig = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
408     DBUS_TYPE_INT32_AS_STRING
409     DBUS_TYPE_STRING_AS_STRING;
410   _dbus_assert (!dbus_signature_validate (sig, NULL));
411
412   sig = DBUS_STRUCT_END_CHAR_AS_STRING
413     DBUS_STRUCT_BEGIN_CHAR_AS_STRING;
414   _dbus_assert (!dbus_signature_validate (sig, NULL));
415
416   sig = DBUS_STRUCT_BEGIN_CHAR_AS_STRING
417     DBUS_TYPE_BOOLEAN_AS_STRING;
418   _dbus_assert (!dbus_signature_validate (sig, NULL));
419   return TRUE;
420 #if 0
421  oom:
422   _dbus_assert_not_reached ("out of memory");
423   return FALSE;
424 #endif
425 }
426
427 #endif
428
429 /** @} */ /* end of DBusSignature group */
430