2003-01-18 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  * Marshals a double value.
139  *
140  * @param str the string to append the marshalled value to
141  * @param byte_order the byte order to use
142  * @param value the value
143  * @returns #TRUE on success
144  */
145 dbus_bool_t
146 _dbus_marshal_double (DBusString *str,
147                       int         byte_order,
148                       double      value)
149 {
150   _dbus_assert (sizeof (double) == 8);
151   
152   if (!_dbus_string_set_length (str,
153                                 _DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
154                                                    sizeof (double))))
155     return FALSE;
156   
157   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
158     swap_bytes ((unsigned char *)&value, sizeof (double));
159
160   return _dbus_string_append_len (str, (const char *)&value, sizeof (double));
161 }
162
163 /**
164  * Marshals a 32 bit signed integer value.
165  *
166  * @param str the string to append the marshalled value to
167  * @param byte_order the byte order to use
168  * @param value the value
169  * @returns #TRUE on success
170  */
171 dbus_bool_t
172 _dbus_marshal_int32  (DBusString   *str,
173                       int           byte_order,
174                       dbus_int32_t  value)
175 {
176   if (!_dbus_string_set_length (str,
177                                 _DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
178                                                    sizeof (dbus_int32_t))))
179     return FALSE;
180   
181   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
182     swap_bytes ((unsigned char *)&value, sizeof (dbus_int32_t));
183
184   return _dbus_string_append_len (str, (const char *)&value, sizeof (dbus_int32_t));
185 }
186
187 /**
188  * Marshals a 32 bit unsigned integer value.
189  *
190  * @param str the string to append the marshalled value to
191  * @param byte_order the byte order to use
192  * @param value the value
193  * @returns #TRUE on success
194  */
195 dbus_bool_t
196 _dbus_marshal_uint32 (DBusString    *str,
197                       int            byte_order,
198                       dbus_uint32_t  value)
199 {
200   if (!_dbus_string_set_length (str,
201                                 _DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
202                                                    sizeof (dbus_uint32_t))))
203     return FALSE;
204
205   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
206     swap_bytes ((unsigned char *)&value, sizeof (dbus_uint32_t));
207
208   return _dbus_string_append_len (str, (const char *)&value, sizeof (dbus_uint32_t));
209 }
210
211 /**
212  * Marshals a UTF-8 string
213  *
214  * @param str the string to append the marshalled value to
215  * @param byte_order the byte order to use
216  * @param value the string
217  * @returns #TRUE on success
218  */
219 dbus_bool_t
220 _dbus_marshal_string (DBusString    *str,
221                       int            byte_order,
222                       const char    *value)
223 {
224   int len, old_string_len;
225
226   old_string_len = _dbus_string_get_length (str);
227   
228   len = strlen (value);
229
230   if (!_dbus_marshal_uint32 (str, byte_order, len))
231     {
232       /* Restore the previous length */
233       _dbus_string_set_length (str, old_string_len);
234
235       return FALSE;
236     }
237
238   return _dbus_string_append_len (str, value, len + 1);
239 }
240
241 /**
242  * Marshals a byte array
243  *
244  * @param str the string to append the marshalled value to
245  * @param byte_order the byte order to use
246  * @param value the byte array
247  * @param len the length of the byte array
248  * @returns #TRUE on success
249  */
250 dbus_bool_t
251 _dbus_marshal_byte_array (DBusString          *str,
252                           int                  byte_order,
253                           const unsigned char *value,
254                           int                  len)
255 {
256   int old_string_len;
257
258   old_string_len = _dbus_string_get_length (str);
259   
260   if (!_dbus_marshal_uint32 (str, byte_order, len))
261     {
262       /* Restore the previous length */
263       _dbus_string_set_length (str, old_string_len);
264
265       return FALSE;
266     }
267
268   return _dbus_string_append_len (str, value, len);
269 }
270
271 /**
272  * Demarshals a double.
273  *
274  * @param str the string containing the data
275  * @param byte_order the byte order
276  * @param pos the position in the string
277  * @param new_pos the new position of the string
278  * @returns the demarshaled double.
279  */
280 double
281 _dbus_demarshal_double (DBusString  *str,
282                         int          byte_order,
283                         int          pos,
284                         int         *new_pos)
285 {
286   double retval;
287   const char *buffer;
288
289   pos = _DBUS_ALIGN_VALUE (pos, sizeof (double));
290
291   _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (double));
292
293   retval = *(double *)buffer;
294   
295   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
296     swap_bytes ((unsigned char *)&retval, sizeof (double));
297
298   if (new_pos)
299     *new_pos = pos + sizeof (double);
300   
301   return retval;  
302 }
303
304 /**
305  * Demarshals a 32 bit signed integer.
306  *
307  * @param str the string containing the data
308  * @param byte_order the byte order
309  * @param pos the position in the string
310  * @param new_pos the new position of the string
311  * @returns the demarshaled integer.
312  */
313 dbus_int32_t
314 _dbus_demarshal_int32  (DBusString *str,
315                         int         byte_order,
316                         int         pos,
317                         int        *new_pos)
318 {
319   const char *buffer;
320
321   pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_int32_t));
322   
323   _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (dbus_int32_t));
324
325   if (new_pos)
326     *new_pos = pos + sizeof (dbus_int32_t);
327
328   return _dbus_unpack_int32 (byte_order, buffer);
329 }
330
331 /**
332  * Demarshals a 32 bit unsigned integer.
333  *
334  * @param str the string containing the data
335  * @param byte_order the byte order
336  * @param pos the position in the string
337  * @param new_pos the new position of the string
338  * @returns the demarshaled integer.
339  */
340 dbus_uint32_t
341 _dbus_demarshal_uint32  (DBusString *str,
342                          int         byte_order,
343                          int         pos,
344                          int        *new_pos)
345 {
346   const char *buffer;
347
348   pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_uint32_t));
349   
350   _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (dbus_uint32_t));
351
352   if (new_pos)
353     *new_pos = pos + sizeof (dbus_uint32_t);
354
355   return _dbus_unpack_uint32 (byte_order, buffer);
356 }
357
358 /**
359  * Demarshals an UTF-8 string.
360  *
361  * @todo Should we check the string to make sure
362  * that it's  valid UTF-8, and maybe "fix" the string
363  * if it's broken?
364  *
365  * @todo Should probably demarshal to a DBusString,
366  * having memcpy() in here is Evil(tm).
367  *
368  * @param str the string containing the data
369  * @param byte_order the byte order
370  * @param pos the position in the string
371  * @param new_pos the new position of the string
372  * @returns the demarshaled string.
373  */
374 char *
375 _dbus_demarshal_string (DBusString *str,
376                         int         byte_order,
377                         int         pos,
378                         int        *new_pos)
379 {
380   int len;
381   char *retval;
382   const char *data;
383
384   len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
385
386   retval = dbus_malloc (len + 1);
387
388   if (!retval)
389     return NULL;
390
391   _dbus_string_get_const_data_len (str, &data, pos, len);
392
393   if (!data)
394     return NULL;
395
396   memcpy (retval, data, len + 1);
397
398   if (new_pos)
399     *new_pos = pos + len + 1;
400   
401   return retval;
402 }
403
404 /**
405  * Demarshals a byte array.
406  *
407  * @todo Should probably demarshal to a DBusString,
408  * having memcpy() in here is Evil(tm).
409  *
410  * @param str the string containing the data
411  * @param byte_order the byte order
412  * @param pos the position in the string
413  * @param new_pos the new position of the string
414  * @param array_len length of the demarshaled data
415  * @returns the demarshaled data.
416  */
417 unsigned char *
418 _dbus_demarshal_byte_array (DBusString *str,
419                             int         byte_order,
420                             int         pos,
421                             int        *new_pos,
422                             int        *array_len)
423 {
424   int len;
425   unsigned char *retval;
426   const char *data;
427
428   len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
429
430   retval = dbus_malloc (len);
431
432   if (!retval)
433     return NULL;
434
435   _dbus_string_get_const_data_len (str, &data, pos, len);
436
437   if (!data)
438     return NULL;
439
440   memcpy (retval, data, len);
441
442   if (new_pos)
443     *new_pos = pos + len;
444
445   if (array_len)
446     *array_len = len;
447
448   return retval;
449 }
450
451 /** 
452  * Returns the position right after the end position 
453  * end position of a field
454  *
455  * @todo warns on invalid type in a message, but
456  * probably the whole message needs to be dumped,
457  * or we might even drop the connection due
458  * to bad protocol. Needs better error handling.
459  * Possible security issue.
460  *
461  * @param str a string
462  * @param byte_order the byte order to use
463  * @param pos the pos where the field starts
464  * @param end_pos pointer where the position right
465  * after the end position will follow
466  * @returns TRUE if more data exists after the field
467  */
468 dbus_bool_t
469 _dbus_marshal_get_field_end_pos (DBusString *str,
470                                  int         byte_order,
471                                  int         pos,
472                                  int        *end_pos)
473 {
474   const char *data;
475
476   if (pos >= _dbus_string_get_length (str))
477     return FALSE;
478
479   _dbus_string_get_const_data_len (str, &data, pos, 1);
480   
481   switch (*data)
482     {
483     case DBUS_TYPE_INVALID:
484       return FALSE;
485       break;
486
487     case DBUS_TYPE_INT32:
488       *end_pos = _DBUS_ALIGN_VALUE (pos + 1, sizeof (dbus_int32_t)) + sizeof (dbus_int32_t);
489
490       break;
491
492     case DBUS_TYPE_UINT32:
493       *end_pos = _DBUS_ALIGN_VALUE (pos + 1, sizeof (dbus_uint32_t)) + sizeof (dbus_uint32_t);
494
495       break;
496
497     case DBUS_TYPE_DOUBLE:
498       *end_pos = _DBUS_ALIGN_VALUE (pos + 1, sizeof (double)) + sizeof (double);
499
500       break;
501
502     case DBUS_TYPE_STRING:
503       {
504         int len, new_pos;
505
506         /* Demarshal the length */
507         len = _dbus_demarshal_uint32 (str, byte_order, pos + 1, &new_pos);
508
509         *end_pos = new_pos + len + 1;
510
511         break;
512       }
513
514     case DBUS_TYPE_BYTE_ARRAY:
515       {
516         int len, new_pos;
517
518         /* Demarshal the length */
519         len = _dbus_demarshal_uint32 (str, byte_order, pos + 1, &new_pos);
520         
521         *end_pos = new_pos + len;
522
523         break;
524       }
525       
526     default:
527       _dbus_warn ("Unknown message field type %d\n", *data);
528       return FALSE;
529     }
530
531   if (*end_pos >= _dbus_string_get_length (str))
532     return FALSE;
533   
534   return TRUE;
535 }
536
537 /**
538  * If in verbose mode, print a block of binary data.
539  *
540  * @todo right now it prints even if not in verbose mode
541  * 
542  * @param data the data
543  * @param len the length of the data
544  */
545 void
546 _dbus_verbose_bytes (const unsigned char *data,
547                      int                  len)
548 {
549   int i;
550   const unsigned char *aligned;
551
552   /* Print blanks on first row if appropriate */
553   aligned = _DBUS_ALIGN_ADDRESS (data, 4);
554   if (aligned > data)
555     aligned -= 4;
556   _dbus_assert (aligned <= data);
557
558   if (aligned != data)
559     {
560       _dbus_verbose ("%5d\t%p: ", - (data - aligned), aligned); 
561       while (aligned != data)
562         {
563           _dbus_verbose ("    ");
564           ++aligned;
565         }
566     }
567
568   /* now print the bytes */
569   i = 0;
570   while (i < len)
571     {
572       if (_DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i])
573         {
574           _dbus_verbose ("%5d\t%p: ",
575                    i, &data[i]);
576         }
577       
578       if (data[i] >= 32 &&
579           data[i] <= 126)
580         _dbus_verbose (" '%c' ", data[i]);
581       else
582         _dbus_verbose ("0x%s%x ",
583                  data[i] <= 0xf ? "0" : "", data[i]);
584
585       ++i;
586
587       if (_DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i])
588         {
589           if (i > 3)
590             _dbus_verbose ("big: %d little: %d",
591                            _dbus_unpack_uint32 (DBUS_BIG_ENDIAN, &data[i-4]),
592                            _dbus_unpack_uint32 (DBUS_LITTLE_ENDIAN, &data[i-4]));
593           
594           _dbus_verbose ("\n");
595         }
596     }
597
598   _dbus_verbose ("\n");
599 }
600
601 /**
602  * Dump the given part of the string to verbose log.
603  *
604  * @param str the string
605  * @param start the start of range to dump
606  * @param len length of range
607  */
608 void
609 _dbus_verbose_bytes_of_string (const DBusString    *str,
610                                int                  start,
611                                int                  len)
612 {
613   const char *d;
614
615   _dbus_string_get_const_data_len (str, &d, start, len);
616
617   _dbus_verbose_bytes (d, len);
618 }
619
620 /** @} */
621
622 #ifdef DBUS_BUILD_TESTS
623 #include "dbus-test.h"
624 #include <stdio.h>
625
626 dbus_bool_t
627 _dbus_marshal_test (void)
628 {
629   DBusString str;
630   char *tmp1, *tmp2;
631   int pos = 0;
632   
633   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
634     _dbus_assert_not_reached ("failed to init string");
635
636
637   /* Marshal doubles */
638   if (!_dbus_marshal_double (&str, DBUS_BIG_ENDIAN, 3.14))
639     _dbus_assert_not_reached ("could not marshal double value");
640   _dbus_assert (_dbus_demarshal_double (&str, DBUS_BIG_ENDIAN, pos, &pos) == 3.14);
641
642   if (!_dbus_marshal_double (&str, DBUS_LITTLE_ENDIAN, 3.14))
643     _dbus_assert_not_reached ("could not marshal double value");
644   _dbus_assert (_dbus_demarshal_double (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == 3.14);
645   
646   /* Marshal signed integers */
647   if (!_dbus_marshal_int32 (&str, DBUS_BIG_ENDIAN, -12345678))
648     _dbus_assert_not_reached ("could not marshal signed integer value");
649   _dbus_assert (_dbus_demarshal_int32 (&str, DBUS_BIG_ENDIAN, pos, &pos) == -12345678);
650
651   if (!_dbus_marshal_int32 (&str, DBUS_LITTLE_ENDIAN, -12345678))
652     _dbus_assert_not_reached ("could not marshal signed integer value");
653   _dbus_assert (_dbus_demarshal_int32 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == -12345678);
654   
655   /* Marshal unsigned integers */
656   if (!_dbus_marshal_uint32 (&str, DBUS_BIG_ENDIAN, 0x12345678))
657     _dbus_assert_not_reached ("could not marshal signed integer value");
658   _dbus_assert (_dbus_demarshal_uint32 (&str, DBUS_BIG_ENDIAN, pos, &pos) == 0x12345678);
659   
660   if (!_dbus_marshal_uint32 (&str, DBUS_LITTLE_ENDIAN, 0x12345678))
661     _dbus_assert_not_reached ("could not marshal signed integer value");
662   _dbus_assert (_dbus_demarshal_uint32 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == 0x12345678);
663
664   /* Marshal strings */
665   tmp1 = "This is the dbus test string";
666   if (!_dbus_marshal_string (&str, DBUS_BIG_ENDIAN, tmp1))
667     _dbus_assert_not_reached ("could not marshal string");
668   tmp2 = _dbus_demarshal_string (&str, DBUS_BIG_ENDIAN, pos, &pos);
669   _dbus_assert (strcmp (tmp1, tmp2) == 0);
670   dbus_free (tmp2);
671
672   tmp1 = "This is the dbus test string";
673   if (!_dbus_marshal_string (&str, DBUS_LITTLE_ENDIAN, tmp1))
674     _dbus_assert_not_reached ("could not marshal string");
675   tmp2 = _dbus_demarshal_string (&str, DBUS_LITTLE_ENDIAN, pos, &pos);
676   _dbus_assert (strcmp (tmp1, tmp2) == 0);
677   dbus_free (tmp2);
678
679   _dbus_string_free (&str);
680   
681   return TRUE;
682 }
683
684 #endif /* DBUS_BUILD_TESTS */