2003-01-27 Havoc Pennington <hp@pobox.com>
[platform/upstream/dbus.git] / dbus / dbus-marshal.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-marshal.c  Marshalling routines
3  *
4  * Copyright (C) 2002  CodeFactory AB
5  *
6  * Licensed under the Academic Free License version 1.2
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-marshal.h"
25 #include "dbus-internals.h"
26
27 #include <string.h>
28
29 /* from ORBit */
30 static void
31 swap_bytes (unsigned char *data,
32             unsigned int   len)
33 {
34   unsigned char *p1 = data;
35   unsigned char *p2 = data + len - 1;
36
37   while (p1 < p2)
38     {
39       unsigned char tmp = *p1;
40       *p1 = *p2;
41       *p2 = tmp;
42
43       --p2;
44       ++p1;
45     }
46 }
47
48 /**
49  * @defgroup DBusMarshal marshaling and unmarshaling
50  * @ingroup  DBusInternals
51  * @brief functions to marshal/unmarshal data from the wire
52  *
53  * Types and functions related to converting primitive data types from
54  * wire format to native machine format, and vice versa.
55  *
56  * @{
57  */
58
59 /**
60  * Unpacks a 32 bit unsigned integer from a data pointer
61  *
62  * @param byte_order The byte order to use
63  * @param data the data pointer
64  * @returns the integer
65  */
66 dbus_uint32_t
67 _dbus_unpack_uint32 (int                  byte_order,
68                      const unsigned char *data)
69 {
70   _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
71   
72   if (byte_order == DBUS_LITTLE_ENDIAN)
73     return DBUS_UINT32_FROM_LE (*(dbus_uint32_t*)data);
74   else
75     return DBUS_UINT32_FROM_BE (*(dbus_uint32_t*)data);
76 }             
77
78 /**
79  * Unpacks a 32 bit signed integer from a data pointer
80  *
81  * @param byte_order The byte order to use
82  * @param data the data pointer
83  * @returns the integer
84  */
85 dbus_int32_t
86 _dbus_unpack_int32 (int                  byte_order,
87                     const unsigned char *data)
88 {
89   _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
90   
91   if (byte_order == DBUS_LITTLE_ENDIAN)
92     return DBUS_INT32_FROM_LE (*(dbus_int32_t*)data);
93   else
94     return DBUS_INT32_FROM_BE (*(dbus_int32_t*)data);
95 }
96
97 /**
98  * Packs a 32 bit unsigned integer into a data pointer.
99  *
100  * @param value the value
101  * @param byte_order the byte order to use
102  * @param data the data pointer
103  */
104 void
105 _dbus_pack_uint32 (dbus_uint32_t   value,
106                    int             byte_order,
107                    unsigned char  *data)
108 {
109   _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
110   
111   if ((byte_order) == DBUS_LITTLE_ENDIAN)                  
112     *((dbus_uint32_t*)(data)) = DBUS_UINT32_TO_LE (value);       
113   else
114     *((dbus_uint32_t*)(data)) = DBUS_UINT32_TO_BE (value);
115 }
116
117 /**
118  * Packs a 32 bit signed integer into a data pointer.
119  *
120  * @param value the value
121  * @param byte_order the byte order to use
122  * @param data the data pointer
123  */
124 void
125 _dbus_pack_int32 (dbus_int32_t   value,
126                   int            byte_order,
127                   unsigned char *data)
128 {
129   _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
130   
131   if ((byte_order) == DBUS_LITTLE_ENDIAN)                  
132     *((dbus_int32_t*)(data)) = DBUS_INT32_TO_LE (value);       
133   else
134     *((dbus_int32_t*)(data)) = DBUS_INT32_TO_BE (value);
135 }
136
137 /**
138  * Sets the 4 bytes at the given offset to a marshaled signed integer,
139  * replacing anything found there previously.
140  *
141  * @param str the string to write the marshalled int to
142  * @param offset the byte offset where int should be written
143  * @param byte_order the byte order to use
144  * @param value the value
145  * 
146  */
147 void
148 _dbus_marshal_set_int32 (DBusString          *str,
149                          int                  byte_order,
150                          int                  offset,
151                          dbus_int32_t         value)
152 {
153   char *data;
154   
155   _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN ||
156                 byte_order == DBUS_BIG_ENDIAN);
157   
158   _dbus_string_get_data_len (str, &data, offset, 4);
159
160   _dbus_pack_int32 (value, byte_order, data);
161 }
162
163 /**
164  * Sets the 4 bytes at the given offset to a marshaled unsigned
165  * integer, replacing anything found there previously.
166  *
167  * @param str the string to write the marshalled int to
168  * @param offset the byte offset where int should be written
169  * @param byte_order the byte order to use
170  * @param value the value
171  * 
172  */
173 void
174 _dbus_marshal_set_uint32 (DBusString          *str,
175                           int                  byte_order,
176                           int                  offset,
177                           dbus_uint32_t        value)
178 {
179   char *data;
180   
181   _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN ||
182                 byte_order == DBUS_BIG_ENDIAN);
183   
184   _dbus_string_get_data_len (str, &data, offset, 4);
185
186   _dbus_pack_uint32 (value, byte_order, data);
187 }
188
189 /**
190  * Sets the existing marshaled string at the given offset with
191  * a new marshaled string. The given offset must point to
192  * an existing string or the wrong length will be deleted
193  * and replaced with the new string.
194  *
195  * @param str the string to write the marshalled string to
196  * @param offset the byte offset where string should be written
197  * @param byte_order the byte order to use
198  * @param value the value
199  * @returns #TRUE on success
200  * 
201  */
202 dbus_bool_t
203 _dbus_marshal_set_string (DBusString          *str,
204                           int                  byte_order,
205                           int                  offset,
206                           const DBusString    *value)
207 {
208   int old_len;
209   int new_len;
210   
211   _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN ||
212                 byte_order == DBUS_BIG_ENDIAN);
213   
214   old_len = _dbus_demarshal_uint32 (str, byte_order,
215                                     offset, NULL);
216
217   new_len = _dbus_string_get_length (value);
218   
219   if (!_dbus_string_replace_len (value, 0, new_len,
220                                  str, offset + 4, old_len))
221     return FALSE;
222
223   _dbus_marshal_set_uint32 (str, byte_order,
224                             offset, new_len);
225
226   return TRUE;
227 }
228
229 /**
230  * Marshals a double value.
231  *
232  * @param str the string to append the marshalled value to
233  * @param byte_order the byte order to use
234  * @param value the value
235  * @returns #TRUE on success
236  */
237 dbus_bool_t
238 _dbus_marshal_double (DBusString *str,
239                       int         byte_order,
240                       double      value)
241 {
242   _dbus_assert (sizeof (double) == 8);
243
244   if (!_dbus_string_align_length (str, sizeof (double)))
245     return FALSE;
246   
247   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
248     swap_bytes ((unsigned char *)&value, sizeof (double));
249
250   return _dbus_string_append_len (str, (const char *)&value, sizeof (double));
251 }
252
253 /**
254  * Marshals a 32 bit signed integer value.
255  *
256  * @param str the string to append the marshalled value to
257  * @param byte_order the byte order to use
258  * @param value the value
259  * @returns #TRUE on success
260  */
261 dbus_bool_t
262 _dbus_marshal_int32  (DBusString   *str,
263                       int           byte_order,
264                       dbus_int32_t  value)
265 {
266   if (!_dbus_string_align_length (str, sizeof (dbus_int32_t)))
267     return FALSE;
268   
269   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
270     value = DBUS_INT32_SWAP_LE_BE (value);
271
272   return _dbus_string_append_len (str, (const char *)&value, sizeof (dbus_int32_t));
273 }
274
275 /**
276  * Marshals a 32 bit unsigned integer value.
277  *
278  * @param str the string to append the marshalled value to
279  * @param byte_order the byte order to use
280  * @param value the value
281  * @returns #TRUE on success
282  */
283 dbus_bool_t
284 _dbus_marshal_uint32 (DBusString    *str,
285                       int            byte_order,
286                       dbus_uint32_t  value)
287 {
288   if (!_dbus_string_align_length (str, sizeof (dbus_uint32_t)))
289     return FALSE;
290   
291   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
292     value = DBUS_UINT32_SWAP_LE_BE (value);
293
294   return _dbus_string_append_len (str, (const char *)&value, sizeof (dbus_uint32_t));
295 }
296
297 /**
298  * Marshals a UTF-8 string
299  *
300  * @param str the string to append the marshalled value to
301  * @param byte_order the byte order to use
302  * @param value the string
303  * @returns #TRUE on success
304  */
305 dbus_bool_t
306 _dbus_marshal_string (DBusString    *str,
307                       int            byte_order,
308                       const char    *value)
309 {
310   int len, old_string_len;
311
312   old_string_len = _dbus_string_get_length (str);
313   
314   len = strlen (value);
315
316   if (!_dbus_marshal_uint32 (str, byte_order, len))
317     {
318       /* Restore the previous length */
319       _dbus_string_set_length (str, old_string_len);
320
321       return FALSE;
322     }
323
324   return _dbus_string_append_len (str, value, len + 1);
325 }
326
327 /**
328  * Marshals a byte array
329  *
330  * @param str the string to append the marshalled value to
331  * @param byte_order the byte order to use
332  * @param value the array
333  * @param len number of elements in the array
334  * @returns #TRUE on success
335  */
336 dbus_bool_t
337 _dbus_marshal_byte_array (DBusString          *str,
338                           int                  byte_order,
339                           const unsigned char *value,
340                           int                  len)
341 {
342   int old_string_len;
343
344   old_string_len = _dbus_string_get_length (str);
345   
346   if (!_dbus_marshal_uint32 (str, byte_order, len))
347     {
348       /* Restore the previous length */
349       _dbus_string_set_length (str, old_string_len);
350
351       return FALSE;
352     }
353
354   return _dbus_string_append_len (str, value, len);
355 }
356
357 /**
358  * Marshals a 32 bit signed integer array
359  *
360  * @param str the string to append the marshalled value to
361  * @param byte_order the byte order to use
362  * @param value the array
363  * @param len the length of the array
364  * @returns #TRUE on success
365  */
366 dbus_bool_t
367 _dbus_marshal_int32_array (DBusString         *str,
368                            int                 byte_order,
369                            const dbus_int32_t *value,
370                            int                 len)
371 {
372   int i, old_string_len;
373
374   old_string_len = _dbus_string_get_length (str);
375
376   if (!_dbus_marshal_uint32 (str, byte_order, len))
377     goto error;
378
379   for (i = 0; i < len; i++)
380     if (!_dbus_marshal_int32 (str, byte_order, value[i]))
381       goto error;
382
383   return TRUE;
384   
385  error:
386   /* Restore previous length */
387   _dbus_string_set_length (str, old_string_len);
388   
389   return FALSE;
390 }
391
392 /**
393  * Marshals a 32 bit unsigned integer array
394  *
395  * @param str the string to append the marshalled value to
396  * @param byte_order the byte order to use
397  * @param value the array
398  * @param len the length of the array
399  * @returns #TRUE on success
400  */
401 dbus_bool_t
402 _dbus_marshal_uint32_array (DBusString          *str,
403                             int                  byte_order,
404                             const dbus_uint32_t  *value,
405                             int                  len)
406 {
407   int i, old_string_len;
408
409   old_string_len = _dbus_string_get_length (str);
410
411   if (!_dbus_marshal_uint32 (str, byte_order, len))
412     goto error;
413
414   for (i = 0; i < len; i++)
415     if (!_dbus_marshal_uint32 (str, byte_order, value[i]))
416       goto error;
417
418   return TRUE;
419   
420  error:
421   /* Restore previous length */
422   _dbus_string_set_length (str, old_string_len);
423   
424   return FALSE;  
425 }
426
427 /**
428  * Marshals a double array
429  *
430  * @param str the string to append the marshalled value to
431  * @param byte_order the byte order to use
432  * @param value the array
433  * @param len the length of the array
434  * @returns #TRUE on success
435  */
436 dbus_bool_t
437 _dbus_marshal_double_array (DBusString          *str,
438                             int                  byte_order,
439                             const double        *value,
440                             int                  len)
441 {
442   int i, old_string_len;
443
444   old_string_len = _dbus_string_get_length (str);
445
446   if (!_dbus_marshal_uint32 (str, byte_order, len))
447     goto error;
448
449   for (i = 0; i < len; i++)
450     if (!_dbus_marshal_double (str, byte_order, value[i]))
451       goto error;
452
453   return TRUE;
454   
455  error:
456   /* Restore previous length */
457   _dbus_string_set_length (str, old_string_len);
458   
459   return FALSE;    
460 }
461
462 /**
463  * Marshals a string array
464  *
465  * @param str the string to append the marshalled value to
466  * @param byte_order the byte order to use
467  * @param value the array
468  * @param len the length of the array
469  * @returns #TRUE on success
470  */
471 dbus_bool_t
472 _dbus_marshal_string_array (DBusString  *str,
473                             int          byte_order,
474                             const char **value,
475                             int          len)
476 {
477   int i, old_string_len;
478
479   old_string_len = _dbus_string_get_length (str);
480
481   if (!_dbus_marshal_uint32 (str, byte_order, len))
482     goto error;
483
484   for (i = 0; i < len; i++)
485     if (!_dbus_marshal_string (str, byte_order, value[i]))
486       goto error;
487
488   return TRUE;
489   
490  error:
491   /* Restore previous length */
492   _dbus_string_set_length (str, old_string_len);
493   
494   return FALSE;      
495 }
496
497 /**
498  * Demarshals a double.
499  *
500  * @param str the string containing the data
501  * @param byte_order the byte order
502  * @param pos the position in the string
503  * @param new_pos the new position of the string
504  * @returns the demarshaled double.
505  */
506 double
507 _dbus_demarshal_double (DBusString  *str,
508                         int          byte_order,
509                         int          pos,
510                         int         *new_pos)
511 {
512   double retval;
513   const char *buffer;
514
515   pos = _DBUS_ALIGN_VALUE (pos, sizeof (double));
516
517   _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (double));
518
519   retval = *(double *)buffer;
520   
521   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
522     swap_bytes ((unsigned char *)&retval, sizeof (double));
523
524   if (new_pos)
525     *new_pos = pos + sizeof (double);
526   
527   return retval;  
528 }
529
530 /**
531  * Demarshals a 32 bit signed integer.
532  *
533  * @param str the string containing the data
534  * @param byte_order the byte order
535  * @param pos the position in the string
536  * @param new_pos the new position of the string
537  * @returns the demarshaled integer.
538  */
539 dbus_int32_t
540 _dbus_demarshal_int32  (DBusString *str,
541                         int         byte_order,
542                         int         pos,
543                         int        *new_pos)
544 {
545   const char *buffer;
546
547   pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_int32_t));
548   
549   _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (dbus_int32_t));
550
551   if (new_pos)
552     *new_pos = pos + sizeof (dbus_int32_t);
553
554   return _dbus_unpack_int32 (byte_order, buffer);
555 }
556
557 /**
558  * Demarshals a 32 bit unsigned integer.
559  *
560  * @param str the string containing the data
561  * @param byte_order the byte order
562  * @param pos the position in the string
563  * @param new_pos the new position of the string
564  * @returns the demarshaled integer.
565  */
566 dbus_uint32_t
567 _dbus_demarshal_uint32  (DBusString *str,
568                          int         byte_order,
569                          int         pos,
570                          int        *new_pos)
571 {
572   const char *buffer;
573
574   pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_uint32_t));
575   
576   _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (dbus_uint32_t));
577
578   if (new_pos)
579     *new_pos = pos + sizeof (dbus_uint32_t);
580
581   return _dbus_unpack_uint32 (byte_order, buffer);
582 }
583
584 /**
585  * Demarshals an UTF-8 string.
586  *
587  * @todo Should we check the string to make sure
588  * that it's  valid UTF-8, and maybe "fix" the string
589  * if it's broken?
590  *
591  * @todo Should probably demarshal to a DBusString,
592  * having memcpy() in here is Evil(tm).
593  *
594  * @param str the string containing the data
595  * @param byte_order the byte order
596  * @param pos the position in the string
597  * @param new_pos the new position of the string
598  * @returns the demarshaled string.
599  */
600 char *
601 _dbus_demarshal_string (DBusString *str,
602                         int         byte_order,
603                         int         pos,
604                         int        *new_pos)
605 {
606   int len;
607   char *retval;
608   const char *data;
609
610   len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
611
612   retval = dbus_malloc (len + 1);
613
614   if (!retval)
615     return NULL;
616
617   _dbus_string_get_const_data_len (str, &data, pos, len);
618
619   if (!data)
620     return NULL;
621
622   memcpy (retval, data, len + 1);
623
624   if (new_pos)
625     *new_pos = pos + len + 1;
626   
627   return retval;
628 }
629
630 /**
631  * Demarshals a byte array.
632  *
633  * @todo Should probably demarshal to a DBusString,
634  * having memcpy() in here is Evil(tm).
635  *
636  * @param str the string containing the data
637  * @param byte_order the byte order
638  * @param pos the position in the string
639  * @param new_pos the new position of the string
640  * @param array_len length of the demarshaled data
641  * @returns the demarshaled data.
642  */
643 unsigned char *
644 _dbus_demarshal_byte_array (DBusString *str,
645                             int         byte_order,
646                             int         pos,
647                             int        *new_pos,
648                             int        *array_len)
649 {
650   int len;
651   unsigned char *retval;
652   const char *data;
653
654   len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
655
656   retval = dbus_malloc (len);
657
658   if (!retval)
659     return NULL;
660
661   _dbus_string_get_const_data_len (str, &data, pos, len);
662
663   if (!data)
664     return NULL;
665
666   memcpy (retval, data, len);
667
668   if (new_pos)
669     *new_pos = pos + len;
670
671   if (array_len)
672     *array_len = len;
673
674   return retval;
675 }
676
677 /**
678  * Demarshals a 32 bit signed integer array.
679  *
680  * @param str the string containing the data
681  * @param byte_order the byte order
682  * @param pos the position in the string
683  * @param new_pos the new position of the string
684  * @param array_len length of the demarshaled data
685  * @returns the demarshaled data.
686  */
687 dbus_int32_t *
688 _dbus_demarshal_int32_array (DBusString *str,
689                              int         byte_order,
690                              int         pos,
691                              int        *new_pos,
692                              int        *array_len)
693 {
694   int len, i;
695   dbus_int32_t *retval;
696   
697   len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
698
699   retval = dbus_new (dbus_int32_t, len);
700
701   if (!retval)
702     return NULL;
703
704   for (i = 0; i < len; i++)
705     retval[i] = _dbus_demarshal_int32 (str, byte_order, pos, &pos);
706
707   if (new_pos)
708     *new_pos = pos;
709
710   if (array_len)
711     *array_len = len;
712   
713   return retval;
714 }
715
716 /**
717  * Demarshals a 32 bit unsigned integer array.
718  *
719  * @param str the string containing the data
720  * @param byte_order the byte order
721  * @param pos the position in the string
722  * @param new_pos the new position of the string
723  * @param array_len length of the demarshaled data
724  * @returns the demarshaled data.
725  */
726 dbus_uint32_t *
727 _dbus_demarshal_uint32_array (DBusString *str,
728                               int         byte_order,
729                               int         pos,
730                               int        *new_pos,
731                               int        *array_len)
732 {
733   int len, i;
734   dbus_uint32_t *retval;
735   
736   len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
737
738   retval = dbus_new (dbus_uint32_t, len);
739
740   if (!retval)
741     return NULL;
742
743   for (i = 0; i < len; i++)
744     retval[i] = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
745
746   if (new_pos)
747     *new_pos = pos;
748
749   if (array_len)
750     *array_len = len;
751   
752   return retval;  
753 }
754
755 /**
756  * Demarshals a double array.
757  *
758  * @param str the string containing the data
759  * @param byte_order the byte order
760  * @param pos the position in the string
761  * @param new_pos the new position of the string
762  * @param array_len length of the demarshaled data
763  * @returns the demarshaled data.
764  */
765 double *
766 _dbus_demarshal_double_array (DBusString *str,
767                               int         byte_order,
768                               int         pos,
769                               int        *new_pos,
770                               int        *array_len)
771 {
772   int len, i;
773   double *retval;
774   
775   len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
776
777   retval = dbus_new (double, len);
778
779   if (!retval)
780     return NULL;
781
782   for (i = 0; i < len; i++)
783     retval[i] = _dbus_demarshal_double (str, byte_order, pos, &pos);
784
785   if (new_pos)
786     *new_pos = pos;
787
788   if (array_len)
789     *array_len = len;
790   
791   return retval;  
792 }
793
794 /**
795  * Demarshals a string array.
796  *
797  * @param str the string containing the data
798  * @param byte_order the byte order
799  * @param pos the position in the string
800  * @param new_pos the new position of the string
801  * @param array_len length of the demarshaled data
802  * @returns the demarshaled data.
803  */
804 char **
805 _dbus_demarshal_string_array (DBusString *str,
806                               int         byte_order,
807                               int         pos,
808                               int        *new_pos,
809                               int        *array_len)
810 {
811   int len, i, j;
812   char **retval;
813
814   len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
815
816   retval = dbus_new (char *, len);
817
818   if (!retval)
819     return NULL;
820
821   for (i = 0; i < len; i++)
822     {
823       retval[i] = _dbus_demarshal_string (str, byte_order, pos, &pos);
824
825       if (retval[i] == 0)
826         goto error;
827     }
828
829  if (new_pos)
830     *new_pos = pos;
831
832   if (array_len)
833     *array_len = len;
834   
835   return retval;
836
837  error:
838   for (j = 0; j < i; j++)
839     dbus_free (retval[i]);
840   dbus_free (retval);
841
842   return NULL;
843 }
844
845 /** 
846  * Returns the position right after the end position 
847  * end position of a field. Validates the field
848  * contents as required (e.g. ensures that
849  * string fields have a valid length and
850  * are nul-terminated).
851  *
852  * @todo security: audit the field validation code.
853  * 
854  * @todo warns on invalid type in a message, but
855  * probably the whole message needs to be dumped,
856  * or we might even drop the connection due
857  * to bad protocol. Needs better error handling.
858  * Possible security issue.
859  *
860  * @param str a string
861  * @param byte_order the byte order to use
862  * @param pos the pos where the field starts
863  * @param end_pos pointer where the position right
864  * after the end position will follow
865  * @returns TRUE if more data exists after the field
866  */
867 dbus_bool_t
868 _dbus_marshal_get_field_end_pos (DBusString *str,
869                                  int         byte_order,
870                                  int         pos,
871                                  int        *end_pos)
872 {
873   const char *data;
874
875   if (pos >= _dbus_string_get_length (str))
876     return FALSE;
877
878   _dbus_string_get_const_data_len (str, &data, pos, 1);
879   
880   switch (*data)
881     {
882     case DBUS_TYPE_INVALID:
883       return FALSE;
884       break;
885
886     case DBUS_TYPE_INT32:
887       *end_pos = _DBUS_ALIGN_VALUE (pos + 1, sizeof (dbus_int32_t)) + sizeof (dbus_int32_t);
888
889       break;
890
891     case DBUS_TYPE_UINT32:
892       *end_pos = _DBUS_ALIGN_VALUE (pos + 1, sizeof (dbus_uint32_t)) + sizeof (dbus_uint32_t);
893
894       break;
895
896     case DBUS_TYPE_DOUBLE:
897       *end_pos = _DBUS_ALIGN_VALUE (pos + 1, sizeof (double)) + sizeof (double);
898
899       break;
900
901     case DBUS_TYPE_STRING:
902       {
903         int len;
904
905         /* Demarshal the length */
906         len = _dbus_demarshal_uint32 (str, byte_order, pos + 1, &pos);
907
908         *end_pos = pos + len + 1;
909
910         if (*end_pos > _dbus_string_get_length (str))
911           {
912             _dbus_verbose ("string length outside length of the message\n");
913             return FALSE;
914           }
915
916         if (_dbus_string_get_byte (str, pos+len) != '\0')
917           {
918             _dbus_verbose ("string field not nul-terminated\n");
919             return FALSE;
920           }
921         
922         break;
923       }
924
925     case DBUS_TYPE_BYTE_ARRAY:
926       {
927         int len;
928
929         /* Demarshal the length */
930         len = _dbus_demarshal_uint32 (str, byte_order, pos + 1, &pos);
931         
932         *end_pos = pos + len;
933
934         break;
935       }
936
937     case DBUS_TYPE_INT32_ARRAY:
938       {
939         int len, new_pos;
940
941         /* Demarshal the length */
942         len = _dbus_demarshal_uint32 (str, byte_order, pos + 1, &new_pos);
943         
944         *end_pos = _DBUS_ALIGN_VALUE (new_pos, sizeof (dbus_int32_t))
945           + (len * sizeof (dbus_int32_t));
946
947         break;
948       }
949
950     case DBUS_TYPE_UINT32_ARRAY:
951       {
952         int len, new_pos;
953
954         /* Demarshal the length */
955         len = _dbus_demarshal_uint32 (str, byte_order, pos + 1, &new_pos);
956
957         *end_pos = _DBUS_ALIGN_VALUE (new_pos, sizeof (dbus_uint32_t))
958           + (len * sizeof (dbus_uint32_t));
959         
960         break;
961       }
962
963     case DBUS_TYPE_DOUBLE_ARRAY:
964       {
965         int len, new_pos;
966         
967         /* Demarshal the length */
968         len = _dbus_demarshal_uint32 (str, byte_order, pos + 1, &new_pos);
969
970         *end_pos = _DBUS_ALIGN_VALUE (new_pos, sizeof (double))
971           + (len * sizeof (double));
972         
973         break;
974       }
975       
976     case DBUS_TYPE_STRING_ARRAY:
977       {
978         int len, i;
979         
980         /* Demarshal the length */
981         len = _dbus_demarshal_uint32 (str, byte_order, pos + 1, &pos);
982
983         for (i = 0; i < len; i++)
984           {
985             int str_len;
986             
987             /* Demarshal string length */
988             str_len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
989             pos += str_len + 1;
990           }
991
992         *end_pos = pos;
993         break;
994       }      
995     default:
996       _dbus_warn ("Unknown message field type %d\n", *data);
997       return FALSE;
998     }
999
1000   if (*end_pos > _dbus_string_get_length (str))
1001     return FALSE;
1002   
1003   return TRUE;
1004 }
1005
1006 /**
1007  * If in verbose mode, print a block of binary data.
1008  *
1009  * @todo right now it prints even if not in verbose mode
1010  * 
1011  * @param data the data
1012  * @param len the length of the data
1013  */
1014 void
1015 _dbus_verbose_bytes (const unsigned char *data,
1016                      int                  len)
1017 {
1018   int i;
1019   const unsigned char *aligned;
1020
1021   /* Print blanks on first row if appropriate */
1022   aligned = _DBUS_ALIGN_ADDRESS (data, 4);
1023   if (aligned > data)
1024     aligned -= 4;
1025   _dbus_assert (aligned <= data);
1026
1027   if (aligned != data)
1028     {
1029       _dbus_verbose ("%5d\t%p: ", - (data - aligned), aligned); 
1030       while (aligned != data)
1031         {
1032           _dbus_verbose ("    ");
1033           ++aligned;
1034         }
1035     }
1036
1037   /* now print the bytes */
1038   i = 0;
1039   while (i < len)
1040     {
1041       if (_DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i])
1042         {
1043           _dbus_verbose ("%5d\t%p: ",
1044                    i, &data[i]);
1045         }
1046       
1047       if (data[i] >= 32 &&
1048           data[i] <= 126)
1049         _dbus_verbose (" '%c' ", data[i]);
1050       else
1051         _dbus_verbose ("0x%s%x ",
1052                  data[i] <= 0xf ? "0" : "", data[i]);
1053
1054       ++i;
1055
1056       if (_DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i])
1057         {
1058           if (i > 3)
1059             _dbus_verbose ("big: %d little: %d",
1060                            _dbus_unpack_uint32 (DBUS_BIG_ENDIAN, &data[i-4]),
1061                            _dbus_unpack_uint32 (DBUS_LITTLE_ENDIAN, &data[i-4]));
1062           
1063           _dbus_verbose ("\n");
1064         }
1065     }
1066
1067   _dbus_verbose ("\n");
1068 }
1069
1070 /**
1071  * Dump the given part of the string to verbose log.
1072  *
1073  * @param str the string
1074  * @param start the start of range to dump
1075  * @param len length of range
1076  */
1077 void
1078 _dbus_verbose_bytes_of_string (const DBusString    *str,
1079                                int                  start,
1080                                int                  len)
1081 {
1082   const char *d;
1083
1084   _dbus_string_get_const_data_len (str, &d, start, len);
1085
1086   _dbus_verbose_bytes (d, len);
1087 }
1088
1089 /** @} */
1090
1091 #ifdef DBUS_BUILD_TESTS
1092 #include "dbus-test.h"
1093 #include <stdio.h>
1094
1095 dbus_bool_t
1096 _dbus_marshal_test (void)
1097 {
1098   DBusString str;
1099   char *tmp1, *tmp2;
1100   dbus_int32_t array1[3] = { 0x123, 0x456, 0x789 }, *array2;
1101   int pos = 0, len;
1102   
1103   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
1104     _dbus_assert_not_reached ("failed to init string");
1105
1106   /* Marshal doubles */
1107   if (!_dbus_marshal_double (&str, DBUS_BIG_ENDIAN, 3.14))
1108     _dbus_assert_not_reached ("could not marshal double value");
1109   _dbus_assert (_dbus_demarshal_double (&str, DBUS_BIG_ENDIAN, pos, &pos) == 3.14);
1110
1111   if (!_dbus_marshal_double (&str, DBUS_LITTLE_ENDIAN, 3.14))
1112     _dbus_assert_not_reached ("could not marshal double value");
1113   _dbus_assert (_dbus_demarshal_double (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == 3.14);
1114   
1115   /* Marshal signed integers */
1116   if (!_dbus_marshal_int32 (&str, DBUS_BIG_ENDIAN, -12345678))
1117     _dbus_assert_not_reached ("could not marshal signed integer value");
1118   _dbus_assert (_dbus_demarshal_int32 (&str, DBUS_BIG_ENDIAN, pos, &pos) == -12345678);
1119
1120   if (!_dbus_marshal_int32 (&str, DBUS_LITTLE_ENDIAN, -12345678))
1121     _dbus_assert_not_reached ("could not marshal signed integer value");
1122   _dbus_assert (_dbus_demarshal_int32 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == -12345678);
1123   
1124   /* Marshal unsigned integers */
1125   if (!_dbus_marshal_uint32 (&str, DBUS_BIG_ENDIAN, 0x12345678))
1126     _dbus_assert_not_reached ("could not marshal signed integer value");
1127   _dbus_assert (_dbus_demarshal_uint32 (&str, DBUS_BIG_ENDIAN, pos, &pos) == 0x12345678);
1128   
1129   if (!_dbus_marshal_uint32 (&str, DBUS_LITTLE_ENDIAN, 0x12345678))
1130     _dbus_assert_not_reached ("could not marshal signed integer value");
1131   _dbus_assert (_dbus_demarshal_uint32 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == 0x12345678);
1132
1133   /* Marshal strings */
1134   tmp1 = "This is the dbus test string";
1135   if (!_dbus_marshal_string (&str, DBUS_BIG_ENDIAN, tmp1))
1136     _dbus_assert_not_reached ("could not marshal string");
1137   tmp2 = _dbus_demarshal_string (&str, DBUS_BIG_ENDIAN, pos, &pos);
1138   _dbus_assert (strcmp (tmp1, tmp2) == 0);
1139   dbus_free (tmp2);
1140
1141   tmp1 = "This is the dbus test string";
1142   if (!_dbus_marshal_string (&str, DBUS_LITTLE_ENDIAN, tmp1))
1143     _dbus_assert_not_reached ("could not marshal string");
1144   tmp2 = _dbus_demarshal_string (&str, DBUS_LITTLE_ENDIAN, pos, &pos);
1145   _dbus_assert (strcmp (tmp1, tmp2) == 0);
1146   dbus_free (tmp2);
1147
1148   /* Marshal signed integer arrays */
1149   if (!_dbus_marshal_int32_array (&str, DBUS_BIG_ENDIAN, array1, 3))
1150     _dbus_assert_not_reached ("could not marshal integer array");
1151   array2 = _dbus_demarshal_int32_array (&str, DBUS_BIG_ENDIAN, pos, &pos, &len);
1152
1153   if (len != 3)
1154     _dbus_assert_not_reached ("Signed integer array lengths differ!\n");
1155   dbus_free (array2);
1156   
1157
1158
1159   _dbus_string_free (&str);
1160   
1161       
1162   return TRUE;
1163 }
1164
1165 #endif /* DBUS_BUILD_TESTS */