2003-01-08 Anders Carlsson <andersca@codefactory.se>
[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 #define DBUS_UINT32_SWAP_LE_BE_CONSTANT(val)    ((dbus_uint32_t) ( \
30     (((dbus_uint32_t) (val) & (dbus_uint32_t) 0x000000ffU) << 24) |  \
31     (((dbus_uint32_t) (val) & (dbus_uint32_t) 0x0000ff00U) <<  8) |  \
32     (((dbus_uint32_t) (val) & (dbus_uint32_t) 0x00ff0000U) >>  8) |  \
33     (((dbus_uint32_t) (val) & (dbus_uint32_t) 0xff000000U) >> 24)))
34
35 #define DBUS_UINT32_SWAP_LE_BE(val) (DBUS_UINT32_SWAP_LE_BE_CONSTANT (val))
36
37 #ifdef WORDS_BIGENDIAN
38 #define DBUS_INT32_TO_BE(val)   ((dbus_int32_t) (val))
39 #define DBUS_UINT32_TO_BE(val)  ((dbus_uint32_t) (val))
40 #define DBUS_INT32_TO_LE(val)   ((dbus_int32_t) DBUS_UINT32_SWAP_LE_BE (val))
41 #define DBUS_UINT32_TO_LE(val)  (DBUS_UINT32_SWAP_LE_BE (val))
42 #else
43 #define DBUS_INT32_TO_LE(val)   ((dbus_int32_t) (val))
44 #define DBUS_UINT32_TO_LE(val)  ((dbus_uint32_t) (val))
45 #define DBUS_INT32_TO_BE(val)   ((dbus_int32_t) DBUS_UINT32_SWAP_LE_BE (val))
46 #define DBUS_UINT32_TO_BE(val)  (DBUS_UINT32_SWAP_LE_BE (val))
47 #endif
48
49 /* The transformation is symmetric, so the FROM just maps to the TO. */
50 #define DBUS_INT32_FROM_LE(val)  (DBUS_INT32_TO_LE (val))
51 #define DBUS_UINT32_FROM_LE(val) (DBUS_UINT32_TO_LE (val))
52 #define DBUS_INT32_FROM_BE(val)  (DBUS_INT32_TO_BE (val))
53 #define DBUS_UINT32_FROM_BE(val) (DBUS_UINT32_TO_BE (val))
54
55
56 /* from ORBit */
57 static void
58 swap_bytes (unsigned char *data,
59             unsigned int   len)
60 {
61   unsigned char *p1 = data;
62   unsigned char *p2 = data + len - 1;
63
64   while (p1 < p2)
65     {
66       unsigned char tmp = *p1;
67       *p1 = *p2;
68       *p2 = tmp;
69
70       --p2;
71       ++p1;
72     }
73 }
74
75 static dbus_uint32_t
76 unpack_uint32 (int                  byte_order,
77                const unsigned char *data)
78 {
79   _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
80   
81   if (byte_order == DBUS_LITTLE_ENDIAN)
82     return DBUS_UINT32_FROM_LE (*(dbus_uint32_t*)data);
83   else
84     return DBUS_UINT32_FROM_BE (*(dbus_uint32_t*)data);
85 }             
86
87 /**
88  * Unpacks a 32 bit unsigned integer from a data pointer
89  *
90  * @param byte_order The byte order to use
91  * @param data the data pointer
92  * @returns the integer
93  */
94 dbus_int32_t
95 dbus_unpack_int32 (int                  byte_order,
96                    const unsigned char *data)
97 {
98   _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
99   
100   if (byte_order == DBUS_LITTLE_ENDIAN)
101     return DBUS_INT32_FROM_LE (*(dbus_int32_t*)data);
102   else
103     return DBUS_INT32_FROM_BE (*(dbus_int32_t*)data);
104 }
105
106 /**
107  * @defgroup DBusMarshal marshaling and unmarshaling
108  * @ingroup  DBusInternals
109  * @brief functions to marshal/unmarshal data from the wire
110  *
111  * Types and functions related to converting primitive data types from
112  * wire format to native machine format, and vice versa.
113  *
114  * @{
115  */
116
117 /**
118  * Packs a 32 bit unsigned 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   if (!_dbus_string_set_length (str,
151                                 _DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
152                                                   sizeof (double))))
153     return FALSE;
154   
155   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
156     swap_bytes ((unsigned char *)&value, sizeof (double));
157
158   return _dbus_string_append_len (str, (const char *)&value, sizeof (double));
159 }
160
161 /**
162  * Marshals a 32 bit signed integer value.
163  *
164  * @param str the string to append the marshalled value to
165  * @param byte_order the byte order to use
166  * @param value the value
167  * @returns #TRUE on success
168  */
169 dbus_bool_t
170 _dbus_marshal_int32  (DBusString   *str,
171                       int           byte_order,
172                       dbus_int32_t  value)
173 {
174   if (!_dbus_string_set_length (str,
175                                 _DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
176                                                   sizeof (dbus_int32_t))))
177     return FALSE;
178   
179   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
180     swap_bytes ((unsigned char *)&value, sizeof (dbus_int32_t));
181
182   return _dbus_string_append_len (str, (const char *)&value, sizeof (dbus_int32_t));
183 }
184
185 /**
186  * Marshals a 32 bit unsigned integer value.
187  *
188  * @param str the string to append the marshalled value to
189  * @param byte_order the byte order to use
190  * @param value the value
191  * @returns #TRUE on success
192  */
193 dbus_bool_t
194 _dbus_marshal_uint32 (DBusString    *str,
195                       int            byte_order,
196                       dbus_uint32_t  value)
197 {
198   if (!_dbus_string_set_length (str,
199                                 _DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
200                                                   sizeof (dbus_uint32_t))))
201     return FALSE;
202
203   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
204     swap_bytes ((unsigned char *)&value, sizeof (dbus_uint32_t));
205
206   return _dbus_string_append_len (str, (const char *)&value, sizeof (dbus_uint32_t));
207 }
208
209 /**
210  * Marshals a UTF-8 string
211  *
212  * @param str the string to append the marshalled value to
213  * @param byte_order the byte order to use
214  * @param value the string
215  * @returns #TRUE on success
216  */
217 dbus_bool_t
218 _dbus_marshal_string (DBusString    *str,
219                       int            byte_order,
220                       const char    *value)
221 {
222   int len, old_string_len;
223
224   old_string_len = _dbus_string_get_length (str);
225   
226   len = strlen (value);
227
228   if (!_dbus_marshal_uint32 (str, byte_order, len))
229     {
230       /* Restore the previous length */
231       _dbus_string_set_length (str, old_string_len);
232
233       return FALSE;
234     }
235
236   return _dbus_string_append_len (str, value, len + 1);
237 }
238
239 /**
240  * Marshals a byte array
241  *
242  * @param str the string to append the marshalled value to
243  * @param byte_order the byte order to use
244  * @param value the byte array
245  * @param len the length of the byte array
246  * @returns #TRUE on success
247  */
248 dbus_bool_t
249 _dbus_marshal_byte_array (DBusString          *str,
250                           int                  byte_order,
251                           const unsigned char *value,
252                           int                  len)
253 {
254   int old_string_len;
255
256   old_string_len = _dbus_string_get_length (str);
257   
258   if (!_dbus_marshal_uint32 (str, byte_order, len))
259     {
260       /* Restore the previous length */
261       _dbus_string_set_length (str, old_string_len);
262
263       return FALSE;
264     }
265
266   return _dbus_string_append_len (str, value, len);
267 }
268
269 /**
270  * Demarshals a double.
271  *
272  * @param str the string containing the data
273  * @param byte_order the byte order
274  * @param pos the position in the string
275  * @param new_pos the new position of the string
276  * @returns the demarshaled double.
277  */
278 double
279 _dbus_demarshal_double (DBusString  *str,
280                         int          byte_order,
281                         int          pos,
282                         int         *new_pos)
283 {
284   double retval;
285   const char *buffer;
286
287   pos = _DBUS_ALIGN_VALUE (pos, sizeof (double));
288
289   _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (double));
290
291   retval = *(double *)buffer;
292   
293   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
294     swap_bytes ((unsigned char *)&retval, sizeof (double));
295
296   if (new_pos)
297     *new_pos = pos + sizeof (double);
298   
299   return retval;  
300 }
301
302 /**
303  * Demarshals a 32 bit signed integer.
304  *
305  * @param str the string containing the data
306  * @param byte_order the byte order
307  * @param pos the position in the string
308  * @param new_pos the new position of the string
309  * @returns the demarshaled integer.
310  */
311 dbus_int32_t
312 _dbus_demarshal_int32  (DBusString *str,
313                         int         byte_order,
314                         int         pos,
315                         int        *new_pos)
316 {
317   const char *buffer;
318
319   pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_int32_t));
320   
321   _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (dbus_int32_t));
322
323   if (new_pos)
324     *new_pos = pos + sizeof (dbus_int32_t);
325
326   return dbus_unpack_int32 (byte_order, buffer);
327 }
328
329 /**
330  * Demarshals a 32 bit unsigned integer.
331  *
332  * @param str the string containing the data
333  * @param byte_order the byte order
334  * @param pos the position in the string
335  * @param new_pos the new position of the string
336  * @returns the demarshaled integer.
337  */
338 dbus_uint32_t
339 _dbus_demarshal_uint32  (DBusString *str,
340                          int         byte_order,
341                          int         pos,
342                          int        *new_pos)
343 {
344   const char *buffer;
345
346   pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_uint32_t));
347   
348   _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (dbus_uint32_t));
349
350   if (new_pos)
351     *new_pos = pos + sizeof (dbus_uint32_t);
352
353   return unpack_uint32 (byte_order, buffer);
354 }
355
356 /**
357  * Demarshals an UTF-8 string.
358  *
359  * @todo Should we check the string to make sure
360  * that it's  valid UTF-8, and maybe "fix" the string
361  * if it's broken?
362  *
363  * @param str the string containing the data
364  * @param byte_order the byte order
365  * @param pos the position in the string
366  * @param new_pos the new position of the string
367  * @returns the demarshaled string.
368  */
369 char *
370 _dbus_demarshal_string (DBusString *str,
371                         int         byte_order,
372                         int         pos,
373                         int        *new_pos)
374 {
375   int len;
376   char *retval;
377   const char *data;
378
379   len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
380
381   retval = dbus_malloc (len + 1);
382
383   if (!retval)
384     return NULL;
385
386   _dbus_string_get_const_data_len (str, &data, pos, len);
387
388   if (!data)
389     return NULL;
390
391   memcpy (retval, data, len + 1);
392
393   if (new_pos)
394     *new_pos = pos + len + 1;
395   
396   return retval;
397 }
398
399 unsigned char *
400 _dbus_demarshal_byte_array (DBusString *str,
401                             int         byte_order,
402                             int         pos,
403                             int        *new_pos,
404                             int        *array_len)
405 {
406   int len;
407   unsigned char *retval;
408   const char *data;
409
410   len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
411
412   retval = dbus_malloc (len);
413
414   if (!retval)
415     return NULL;
416
417   _dbus_string_get_const_data_len (str, &data, pos, len);
418
419   if (!data)
420     return NULL;
421
422   memcpy (retval, data, len);
423
424   if (new_pos)
425     *new_pos = pos + len;
426
427   if (array_len)
428     *array_len = len;
429
430   return retval;
431 }
432
433 /** 
434  * Returns the position right after the end position 
435  * end position of a field
436  *
437  * @param str a string
438  * @param byte_order the byte order to use
439  * @param pos the pos where the field starts
440  * @param end_pos pointer where the position right
441  * after the end position will follow
442  * @returns TRUE if more data exists after the field
443  */
444 dbus_bool_t
445 _dbus_marshal_get_field_end_pos (DBusString *str,
446                                  int         byte_order,
447                                  int         pos,
448                                  int        *end_pos)
449 {
450   const char *data;
451
452   if (pos >= _dbus_string_get_length (str))
453     return FALSE;
454
455   _dbus_string_get_const_data_len (str, &data, pos, 1);
456   
457   switch (*data)
458     {
459     case DBUS_TYPE_INVALID:
460       return FALSE;
461       break;
462
463     case DBUS_TYPE_INT32:
464       *end_pos = _DBUS_ALIGN_VALUE (pos + 1, sizeof (dbus_int32_t)) + sizeof (dbus_int32_t);
465
466       break;
467
468     case DBUS_TYPE_UINT32:
469       *end_pos = _DBUS_ALIGN_VALUE (pos + 1, sizeof (dbus_uint32_t)) + sizeof (dbus_uint32_t);
470
471       break;
472
473     case DBUS_TYPE_DOUBLE:
474       *end_pos = _DBUS_ALIGN_VALUE (pos + 1, sizeof (double)) + sizeof (double);
475
476       break;
477
478     case DBUS_TYPE_STRING:
479       {
480         int len, new_pos;
481
482         /* Demarshal the length */
483         len = _dbus_demarshal_uint32 (str, byte_order, pos + 1, &new_pos);
484
485         *end_pos = new_pos + len + 1;
486
487         break;
488       }
489
490     case DBUS_TYPE_BYTE_ARRAY:
491       {
492         int len, new_pos;
493
494         /* Demarshal the length */
495         len = _dbus_demarshal_uint32 (str, byte_order, pos + 1, &new_pos);
496         
497         *end_pos = new_pos + len;
498
499         break;
500       }
501       
502     default:
503       _dbus_warn ("Unknown message field type %d\n", *data);
504       return FALSE;
505     }
506
507   if (*end_pos >= _dbus_string_get_length (str))
508     return FALSE;
509   
510   return TRUE;
511 }
512
513 /**
514  * If in verbose mode, print a block of binary data.
515  *
516  * @todo right now it prints even if not in verbose mode
517  * 
518  * @param data the data
519  * @param len the length of the data
520  */
521 void
522 _dbus_verbose_bytes (const unsigned char *data,
523                      int                  len)
524 {
525   int i;
526   const unsigned char *aligned;
527
528   /* Print blanks on first row if appropriate */
529   aligned = _DBUS_ALIGN_ADDRESS (data, 4);
530   if (aligned > data)
531     aligned -= 4;
532   _dbus_assert (aligned <= data);
533
534   if (aligned != data)
535     {
536       _dbus_verbose ("%5d\t%p: ", - (data - aligned), aligned); 
537       while (aligned != data)
538         {
539           _dbus_verbose ("    ");
540           ++aligned;
541         }
542     }
543
544   /* now print the bytes */
545   i = 0;
546   while (i < len)
547     {
548       if (_DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i])
549         {
550           _dbus_verbose ("%5d\t%p: ",
551                    i, &data[i]);
552         }
553       
554       if (data[i] >= 32 &&
555           data[i] <= 126)
556         _dbus_verbose (" '%c' ", data[i]);
557       else
558         _dbus_verbose ("0x%s%x ",
559                  data[i] <= 0xf ? "0" : "", data[i]);
560
561       ++i;
562
563       if (_DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i])
564         {
565           if (i > 3)
566             _dbus_verbose ("big: %d little: %d",
567                      unpack_uint32 (DBUS_BIG_ENDIAN, &data[i-4]),
568                      unpack_uint32 (DBUS_LITTLE_ENDIAN, &data[i-4]));
569           
570           _dbus_verbose ("\n");
571         }
572     }
573
574   _dbus_verbose ("\n");
575 }
576
577 /**
578  * Dump the given part of the string to verbose log.
579  *
580  * @param str the string
581  * @param start the start of range to dump
582  * @param len length of range
583  */
584 void
585 _dbus_verbose_bytes_of_string (const DBusString    *str,
586                                int                  start,
587                                int                  len)
588 {
589   const char *d;
590
591   _dbus_string_get_const_data_len (str, &d, start, len);
592
593   _dbus_verbose_bytes (d, len);
594 }
595
596 /** @} */
597
598 #ifdef DBUS_BUILD_TESTS
599 #include "dbus-test.h"
600 #include <stdio.h>
601
602 dbus_bool_t
603 _dbus_marshal_test (void)
604 {
605   DBusString str;
606   char *tmp1, *tmp2;
607   int pos = 0;
608   
609   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
610     _dbus_assert_not_reached ("failed to init string");
611
612
613   /* Marshal doubles */
614   if (!_dbus_marshal_double (&str, DBUS_BIG_ENDIAN, 3.14))
615     _dbus_assert_not_reached ("could not marshal double value");
616   _dbus_assert (_dbus_demarshal_double (&str, DBUS_BIG_ENDIAN, pos, &pos) == 3.14);
617
618   if (!_dbus_marshal_double (&str, DBUS_LITTLE_ENDIAN, 3.14))
619     _dbus_assert_not_reached ("could not marshal double value");
620   _dbus_assert (_dbus_demarshal_double (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == 3.14);
621   
622   /* Marshal signed integers */
623   if (!_dbus_marshal_int32 (&str, DBUS_BIG_ENDIAN, -12345678))
624     _dbus_assert_not_reached ("could not marshal signed integer value");
625   _dbus_assert (_dbus_demarshal_int32 (&str, DBUS_BIG_ENDIAN, pos, &pos) == -12345678);
626
627   if (!_dbus_marshal_int32 (&str, DBUS_LITTLE_ENDIAN, -12345678))
628     _dbus_assert_not_reached ("could not marshal signed integer value");
629   _dbus_assert (_dbus_demarshal_int32 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == -12345678);
630   
631   /* Marshal unsigned integers */
632   if (!_dbus_marshal_uint32 (&str, DBUS_BIG_ENDIAN, 0x12345678))
633     _dbus_assert_not_reached ("could not marshal signed integer value");
634   _dbus_assert (_dbus_demarshal_uint32 (&str, DBUS_BIG_ENDIAN, pos, &pos) == 0x12345678);
635   
636   if (!_dbus_marshal_uint32 (&str, DBUS_LITTLE_ENDIAN, 0x12345678))
637     _dbus_assert_not_reached ("could not marshal signed integer value");
638   _dbus_assert (_dbus_demarshal_uint32 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == 0x12345678);
639
640   /* Marshal strings */
641   tmp1 = "This is the dbus test string";
642   if (!_dbus_marshal_string (&str, DBUS_BIG_ENDIAN, tmp1))
643     _dbus_assert_not_reached ("could not marshal string");
644   tmp2 = _dbus_demarshal_string (&str, DBUS_BIG_ENDIAN, pos, &pos);
645   _dbus_assert (strcmp (tmp1, tmp2) == 0);
646   dbus_free (tmp2);
647
648   tmp1 = "This is the dbus test string";
649   if (!_dbus_marshal_string (&str, DBUS_LITTLE_ENDIAN, tmp1))
650     _dbus_assert_not_reached ("could not marshal string");
651   tmp2 = _dbus_demarshal_string (&str, DBUS_LITTLE_ENDIAN, pos, &pos);
652   _dbus_assert (strcmp (tmp1, tmp2) == 0);
653   dbus_free (tmp2);
654
655   _dbus_string_free (&str);
656   
657   return TRUE;
658 }
659
660 #endif /* DBUS_BUILD_TESTS */