2005-07-30 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;
33   unsigned int finished : 1;
34   unsigned int in_array : 1;
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->pos++;
196
197   if (dbus_signature_iter_get_current_type (subiter) == DBUS_TYPE_ARRAY)
198     real_sub_iter->in_array = TRUE;
199 }
200
201 /**
202  * Check a type signature for validity.
203  *
204  * @param signature a potentially invalid type signature
205  * @param error error return
206  * @returns TRUE iif signature is valid
207  */
208 dbus_bool_t
209 dbus_signature_validate (const char       *signature,
210                          DBusError        *error)
211                          
212 {
213   DBusString str;
214
215   _dbus_string_init_const (&str, signature);
216   if (_dbus_validate_signature (&str, 0, _dbus_string_get_length (&str)))
217     return TRUE;
218   dbus_set_error (error, DBUS_ERROR_INVALID_SIGNATURE, "Corrupt type signature");
219   return FALSE;
220 }
221
222 /**
223  * Check that a type signature is both valid and contains exactly
224  * one complete type.
225  *
226  * @param signature a potentially invalid type signature
227  * @param error error return
228  * @returns TRUE iif signature is valid and has exactly one complete type
229  */
230 dbus_bool_t
231 dbus_signature_validate_single (const char       *signature,
232                                 DBusError        *error)
233 {
234   DBusSignatureIter iter;
235
236   if (!dbus_signature_validate (signature, error))
237     return FALSE;
238
239   dbus_signature_iter_init (&iter, signature);
240   if (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_INVALID)
241     goto lose;
242   if (!dbus_signature_iter_next (&iter))
243     return TRUE;
244  lose:
245   dbus_set_error (error, DBUS_ERROR_INVALID_SIGNATURE, "Exactly one complete type required in signature");
246   return FALSE;
247 }
248
249 /** macro that checks whether a typecode is a container type */
250 #define TYPE_IS_CONTAINER(typecode)             \
251     ((typecode) == DBUS_TYPE_STRUCT ||          \
252      (typecode) == DBUS_TYPE_DICT_ENTRY ||      \
253      (typecode) == DBUS_TYPE_VARIANT ||         \
254      (typecode) == DBUS_TYPE_ARRAY)
255
256 /**
257  * A "container type" can contain basic types, or nested
258  * container types. #DBUS_TYPE_INVALID is not a container type.
259  * This function will crash if passed a typecode that isn't
260  * in dbus-protocol.h
261  *
262  * @returns #TRUE if type is a container
263  */
264 dbus_bool_t
265 dbus_type_is_container (int typecode)
266 {
267   /* only reasonable (non-line-noise) typecodes are allowed */
268   _dbus_return_val_if_fail (_dbus_type_is_valid (typecode) || typecode == DBUS_TYPE_INVALID,
269                             FALSE);
270   return TYPE_IS_CONTAINER (typecode);
271 }
272
273 /**
274  * A "basic type" is a somewhat arbitrary concept, but the intent
275  * is to include those types that are fully-specified by a single
276  * typecode, with no additional type information or nested
277  * values. So all numbers and strings are basic types and
278  * structs, arrays, and variants are not basic types.
279  * #DBUS_TYPE_INVALID is not a basic type.
280  *
281  * This function will crash if passed a typecode that isn't
282  * in dbus-protocol.h
283  *
284  * @returns #TRUE if type is basic
285  */
286 dbus_bool_t
287 dbus_type_is_basic (int typecode)
288 {
289   /* only reasonable (non-line-noise) typecodes are allowed */
290   _dbus_return_val_if_fail (_dbus_type_is_valid (typecode) || typecode == DBUS_TYPE_INVALID,
291                             FALSE);
292
293   /* everything that isn't invalid or a container */
294   return !(typecode == DBUS_TYPE_INVALID || TYPE_IS_CONTAINER (typecode));
295 }
296
297 /**
298  * Tells you whether values of this type can change length if you set
299  * them to some other value. For this purpose, you assume that the
300  * first byte of the old and new value would be in the same location,
301  * so alignment padding is not a factor.
302  *
303  * This function is useful to determine whether #dbus_message_iter_get_fixed_array
304  * may be used.
305  *
306  * @returns #FALSE if the type can occupy different lengths
307  */
308 dbus_bool_t
309 dbus_type_is_fixed (int typecode)
310 {
311   switch (typecode)
312     {
313     case DBUS_TYPE_BYTE:
314     case DBUS_TYPE_BOOLEAN:
315     case DBUS_TYPE_INT16:
316     case DBUS_TYPE_UINT16:
317     case DBUS_TYPE_INT32:
318     case DBUS_TYPE_UINT32:
319     case DBUS_TYPE_INT64:
320     case DBUS_TYPE_UINT64:
321     case DBUS_TYPE_DOUBLE:
322       return TRUE;
323     default:
324       return FALSE;
325     }
326 }
327
328 #ifdef DBUS_BUILD_TESTS
329
330 /**
331  * @ingroup DBusSignatureInternals
332  * Unit test for DBusSignature.
333  *
334  * @returns #TRUE on success.
335  */
336 dbus_bool_t
337 _dbus_signature_test (void)
338 {
339   DBusSignatureIter iter;
340   DBusSignatureIter subiter;
341   DBusSignatureIter subsubiter;
342   DBusSignatureIter subsubsubiter;
343   const char *sig;
344
345   _dbus_assert (sizeof (DBusSignatureIter) >= sizeof (DBusSignatureRealIter));
346
347   sig = "";
348   _dbus_assert (dbus_signature_validate (sig, NULL));
349   _dbus_assert (!dbus_signature_validate_single (sig, NULL));
350   dbus_signature_iter_init (&iter, sig);
351   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_INVALID);
352
353   sig = DBUS_TYPE_STRING_AS_STRING;
354   _dbus_assert (dbus_signature_validate (sig, NULL));
355   _dbus_assert (dbus_signature_validate_single (sig, NULL));
356   dbus_signature_iter_init (&iter, sig);
357   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_STRING);
358
359   sig = DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_BYTE_AS_STRING;
360   _dbus_assert (dbus_signature_validate (sig, NULL));
361   dbus_signature_iter_init (&iter, sig);
362   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_STRING);
363   _dbus_assert (dbus_signature_iter_next (&iter));
364   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_BYTE);
365
366   sig = DBUS_TYPE_UINT16_AS_STRING
367     DBUS_STRUCT_BEGIN_CHAR_AS_STRING
368     DBUS_TYPE_STRING_AS_STRING
369     DBUS_TYPE_UINT32_AS_STRING
370     DBUS_TYPE_VARIANT_AS_STRING
371     DBUS_TYPE_DOUBLE_AS_STRING
372     DBUS_STRUCT_END_CHAR_AS_STRING;
373   _dbus_assert (dbus_signature_validate (sig, NULL));
374   dbus_signature_iter_init (&iter, sig);
375   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_UINT16);
376   _dbus_assert (dbus_signature_iter_next (&iter));
377   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_STRUCT);
378   dbus_signature_iter_recurse (&iter, &subiter);
379   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_STRING);
380   _dbus_assert (dbus_signature_iter_next (&subiter));
381   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_UINT32);
382   _dbus_assert (dbus_signature_iter_next (&subiter));
383   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_VARIANT);
384   _dbus_assert (dbus_signature_iter_next (&subiter));
385   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_DOUBLE);
386
387   sig = DBUS_TYPE_UINT16_AS_STRING
388     DBUS_STRUCT_BEGIN_CHAR_AS_STRING
389     DBUS_TYPE_UINT32_AS_STRING
390     DBUS_TYPE_BYTE_AS_STRING
391     DBUS_TYPE_ARRAY_AS_STRING
392     DBUS_TYPE_ARRAY_AS_STRING
393     DBUS_TYPE_DOUBLE_AS_STRING
394     DBUS_STRUCT_BEGIN_CHAR_AS_STRING
395     DBUS_TYPE_BYTE_AS_STRING
396     DBUS_STRUCT_END_CHAR_AS_STRING
397     DBUS_STRUCT_END_CHAR_AS_STRING;
398   _dbus_assert (dbus_signature_validate (sig, NULL));
399   dbus_signature_iter_init (&iter, sig);
400   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_UINT16);
401   _dbus_assert (dbus_signature_iter_next (&iter));
402   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_STRUCT);
403   dbus_signature_iter_recurse (&iter, &subiter);
404   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_UINT32);
405   _dbus_assert (dbus_signature_iter_next (&subiter));
406   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_BYTE);
407   _dbus_assert (dbus_signature_iter_next (&subiter));
408   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_ARRAY);
409   _dbus_assert (dbus_signature_iter_get_element_type (&subiter) == DBUS_TYPE_ARRAY);
410
411   dbus_signature_iter_recurse (&subiter, &subsubiter);
412   _dbus_assert (dbus_signature_iter_get_current_type (&subsubiter) == DBUS_TYPE_ARRAY);
413   _dbus_assert (dbus_signature_iter_get_element_type (&subsubiter) == DBUS_TYPE_DOUBLE);
414
415   dbus_signature_iter_recurse (&subsubiter, &subsubsubiter);
416   _dbus_assert (dbus_signature_iter_get_current_type (&subsubsubiter) == DBUS_TYPE_DOUBLE);
417   _dbus_assert (dbus_signature_iter_next (&subiter));
418   _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_STRUCT);
419   dbus_signature_iter_recurse (&subiter, &subsubiter);
420   _dbus_assert (dbus_signature_iter_get_current_type (&subsubiter) == DBUS_TYPE_BYTE);
421
422   sig = DBUS_TYPE_ARRAY_AS_STRING
423     DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
424     DBUS_TYPE_INT16_AS_STRING
425     DBUS_TYPE_STRING_AS_STRING
426     DBUS_DICT_ENTRY_END_CHAR_AS_STRING
427     DBUS_TYPE_VARIANT_AS_STRING;
428   _dbus_assert (dbus_signature_validate (sig, NULL));
429   _dbus_assert (!dbus_signature_validate_single (sig, NULL));
430   dbus_signature_iter_init (&iter, sig);
431   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_ARRAY);
432   _dbus_assert (dbus_signature_iter_get_element_type (&iter) == DBUS_TYPE_DICT_ENTRY);
433
434   dbus_signature_iter_recurse (&iter, &subiter);
435   dbus_signature_iter_recurse (&subiter, &subsubiter);
436   _dbus_assert (dbus_signature_iter_get_current_type (&subsubiter) == DBUS_TYPE_INT16);
437   _dbus_assert (dbus_signature_iter_next (&subsubiter));
438   _dbus_assert (dbus_signature_iter_get_current_type (&subsubiter) == DBUS_TYPE_STRING);
439   _dbus_assert (!dbus_signature_iter_next (&subsubiter));
440
441   _dbus_assert (dbus_signature_iter_next (&iter));
442   _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_VARIANT);
443   _dbus_assert (!dbus_signature_iter_next (&iter));
444
445   sig = DBUS_TYPE_DICT_ENTRY_AS_STRING;
446   _dbus_assert (!dbus_signature_validate (sig, NULL));
447
448   sig = DBUS_TYPE_ARRAY_AS_STRING;
449   _dbus_assert (!dbus_signature_validate (sig, NULL));
450
451   sig = DBUS_TYPE_UINT32_AS_STRING
452     DBUS_TYPE_ARRAY_AS_STRING;
453   _dbus_assert (!dbus_signature_validate (sig, NULL));
454
455   sig = DBUS_TYPE_ARRAY_AS_STRING
456     DBUS_TYPE_DICT_ENTRY_AS_STRING;
457   _dbus_assert (!dbus_signature_validate (sig, NULL));
458
459   sig = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING;
460   _dbus_assert (!dbus_signature_validate (sig, NULL));
461
462   sig = DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
463   _dbus_assert (!dbus_signature_validate (sig, NULL));
464
465   sig = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
466     DBUS_TYPE_INT32_AS_STRING;
467   _dbus_assert (!dbus_signature_validate (sig, NULL));
468
469   sig = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
470     DBUS_TYPE_INT32_AS_STRING
471     DBUS_TYPE_STRING_AS_STRING;
472   _dbus_assert (!dbus_signature_validate (sig, NULL));
473
474   sig = DBUS_STRUCT_END_CHAR_AS_STRING
475     DBUS_STRUCT_BEGIN_CHAR_AS_STRING;
476   _dbus_assert (!dbus_signature_validate (sig, NULL));
477
478   sig = DBUS_STRUCT_BEGIN_CHAR_AS_STRING
479     DBUS_TYPE_BOOLEAN_AS_STRING;
480   _dbus_assert (!dbus_signature_validate (sig, NULL));
481   return TRUE;
482 #if 0
483  oom:
484   _dbus_assert_not_reached ("out of memory");
485   return FALSE;
486 #endif
487 }
488
489 #endif
490
491 /** @} */ /* end of DBusSignature group */
492