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