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