2003-01-07 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 /* This alignment thing is from ORBit2 */
57 /* Align a value upward to a boundary, expressed as a number of bytes.
58  * E.g. align to an 8-byte boundary with argument of 8.
59  */
60
61 /*
62  *   (this + boundary - 1)
63  *          &
64  *    ~(boundary - 1)
65  */
66
67 #define DBUS_ALIGN_VALUE(this, boundary) \
68   (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
69
70 #define DBUS_ALIGN_ADDRESS(this, boundary) \
71   ((void*)DBUS_ALIGN_VALUE(this, boundary))
72
73 /* from ORBit */
74 static void
75 swap_bytes (unsigned char *data,
76             unsigned int   len)
77 {
78   unsigned char *p1 = data;
79   unsigned char *p2 = data + len - 1;
80
81   while (p1 < p2)
82     {
83       unsigned char tmp = *p1;
84       *p1 = *p2;
85       *p2 = tmp;
86
87       --p2;
88       ++p1;
89     }
90 }
91
92 static dbus_uint32_t
93 unpack_uint32 (int                  byte_order,
94                const unsigned char *data)
95 {
96   _dbus_assert (DBUS_ALIGN_ADDRESS (data, 4) == data);
97   
98   if (byte_order == DBUS_LITTLE_ENDIAN)
99     return DBUS_UINT32_FROM_LE (*(dbus_uint32_t*)data);
100   else
101     return DBUS_UINT32_FROM_BE (*(dbus_uint32_t*)data);
102 }             
103
104 static dbus_int32_t
105 unpack_int32 (int                  byte_order,
106               const unsigned char *data)
107 {
108   _dbus_assert (DBUS_ALIGN_ADDRESS (data, 4) == data);
109   
110   if (byte_order == DBUS_LITTLE_ENDIAN)
111     return DBUS_INT32_FROM_LE (*(dbus_int32_t*)data);
112   else
113     return DBUS_INT32_FROM_BE (*(dbus_int32_t*)data);
114 }
115
116 /**
117  * @defgroup DBusMarshal marshaling and unmarshaling
118  * @ingroup  DBusInternals
119  * @brief functions to marshal/unmarshal data from the wire
120  *
121  * Types and functions related to converting primitive data types from
122  * wire format to native machine format, and vice versa.
123  *
124  * @{
125  */
126
127 /**
128  * Marshals a double value.
129  *
130  * @param str the string to append the marshalled value to
131  * @param byte_order the byte order to use
132  * @param value the value
133  * @returns #TRUE on success
134  */
135 dbus_bool_t
136 _dbus_marshal_double (DBusString *str,
137                       int         byte_order,
138                       double      value)
139 {
140   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
141     swap_bytes ((unsigned char *)&value, sizeof (double));
142
143   return _dbus_string_append_len (str, (const char *)&value, sizeof (double));
144 }
145
146 /**
147  * Marshals a 32 bit signed integer value.
148  *
149  * @param str the string to append the marshalled value to
150  * @param byte_order the byte order to use
151  * @param value the value
152  * @returns #TRUE on success
153  */
154 dbus_bool_t
155 _dbus_marshal_int32  (DBusString   *str,
156                       int           byte_order,
157                       dbus_int32_t  value)
158 {
159   if (!_dbus_string_set_length (str,
160                                 DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
161                                                   sizeof (dbus_int32_t))))
162     return FALSE;
163   
164   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
165     swap_bytes ((unsigned char *)&value, sizeof (dbus_int32_t));
166
167   return _dbus_string_append_len (str, (const char *)&value, sizeof (dbus_int32_t));
168 }
169
170 /**
171  * Marshals a 32 bit unsigned integer value.
172  *
173  * @param str the string to append the marshalled value to
174  * @param byte_order the byte order to use
175  * @param value the value
176  * @returns #TRUE on success
177  */
178 dbus_bool_t
179 _dbus_marshal_uint32 (DBusString    *str,
180                       int            byte_order,
181                       dbus_uint32_t  value)
182 {
183   if (!_dbus_string_set_length (str,
184                                 DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
185                                                   sizeof (dbus_uint32_t))))
186     return FALSE;
187
188   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
189     swap_bytes ((unsigned char *)&value, sizeof (dbus_uint32_t));
190
191   return _dbus_string_append_len (str, (const char *)&value, sizeof (dbus_uint32_t));
192 }
193
194 /**
195  * Marshals a UTF-8 string
196  *
197  * @param str the string to append the marshalled value to
198  * @param byte_order the byte order to use
199  * @param value the string
200  * @returns #TRUE on success
201  */
202 dbus_bool_t
203 _dbus_marshal_string (DBusString    *str,
204                       int            byte_order,
205                       const char    *value)
206 {
207   int len, old_string_len;
208
209   old_string_len = _dbus_string_get_length (str);
210   
211   len = strlen (value);
212
213   if (!_dbus_marshal_uint32 (str, byte_order, len))
214     {
215       /* Restore the previous length */
216       _dbus_string_set_length (str, old_string_len);
217
218       return FALSE;
219     }
220
221   return _dbus_string_append_len (str, value, len + 1);
222 }
223
224 /**
225  * Marshals a byte array
226  *
227  * @param str the string to append the marshalled value to
228  * @param byte_order the byte order to use
229  * @param value the byte array
230  * @param len the length of the byte array
231  * @returns #TRUE on success
232  */
233 dbus_bool_t
234 _dbus_marshal_byte_array (DBusString          *str,
235                           int                  byte_order,
236                           const unsigned char *value,
237                           int                  len)
238 {
239   int old_string_len;
240
241   old_string_len = _dbus_string_get_length (str);
242   
243   if (!_dbus_marshal_uint32 (str, byte_order, len))
244     {
245       /* Restore the previous length */
246       _dbus_string_set_length (str, old_string_len);
247
248       return FALSE;
249     }
250
251   return _dbus_string_append_len (str, value, len);
252 }
253
254 /**
255  * Demarshals a double.
256  *
257  * @param str the string containing the data
258  * @param byte_order the byte order
259  * @param pos the position in the string
260  * @param new_pos the new position of the string
261  * @returns the demarshaled double.
262  */
263 double
264 _dbus_demarshal_double (DBusString  *str,
265                         int          byte_order,
266                         int          pos,
267                         int         *new_pos)
268 {
269   double retval;
270   const char *buffer;
271
272   pos = DBUS_ALIGN_VALUE (pos, sizeof (double));
273   
274   _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (double));
275
276   retval = *(double *)buffer;
277   
278   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
279     swap_bytes ((unsigned char *)&retval, sizeof (double));
280
281   if (new_pos)
282     *new_pos = pos + sizeof (double);
283   
284   return retval;  
285 }
286
287 /**
288  * Demarshals a 32 bit signed integer.
289  *
290  * @param str the string containing the data
291  * @param byte_order the byte order
292  * @param pos the position in the string
293  * @param new_pos the new position of the string
294  * @returns the demarshaled integer.
295  */
296 dbus_int32_t
297 _dbus_demarshal_int32  (DBusString *str,
298                         int         byte_order,
299                         int         pos,
300                         int        *new_pos)
301 {
302   const char *buffer;
303
304   pos = DBUS_ALIGN_VALUE (pos, sizeof (dbus_int32_t));
305   
306   _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (dbus_int32_t));
307
308   if (new_pos)
309     *new_pos = pos + sizeof (dbus_int32_t);
310
311   return unpack_int32 (byte_order, buffer);
312 }
313
314 /**
315  * Demarshals a 32 bit unsigned integer.
316  *
317  * @param str the string containing the data
318  * @param byte_order the byte order
319  * @param pos the position in the string
320  * @param new_pos the new position of the string
321  * @returns the demarshaled integer.
322  */
323 dbus_uint32_t
324 _dbus_demarshal_uint32  (DBusString *str,
325                          int         byte_order,
326                          int         pos,
327                          int        *new_pos)
328 {
329   const char *buffer;
330
331   pos = DBUS_ALIGN_VALUE (pos, sizeof (dbus_uint32_t));
332   
333   _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (dbus_uint32_t));
334
335   if (new_pos)
336     *new_pos = pos + sizeof (dbus_uint32_t);
337
338   return unpack_uint32 (byte_order, buffer);
339 }
340
341 /**
342  * Demarshals an UTF-8 string.
343  *
344  * @todo Should we check the string to make sure
345  * that it's  valid UTF-8, and maybe "fix" the string
346  * if it's broken?
347  *
348  * @param str the string containing the data
349  * @param byte_order the byte order
350  * @param pos the position in the string
351  * @param new_pos the new position of the string
352  * @returns the demarshaled string.
353  */
354 char *
355 _dbus_demarshal_string (DBusString *str,
356                         int         byte_order,
357                         int         pos,
358                         int        *new_pos)
359 {
360   int len;
361   char *retval;
362   const char *data;
363
364   len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
365
366   retval = dbus_malloc (len + 1);
367
368   if (!retval)
369     return NULL;
370
371   _dbus_string_get_const_data_len (str, &data, pos, 3);
372
373   if (!data)
374     return NULL;
375
376   memcpy (retval, data, len + 1);
377
378   if (new_pos)
379     *new_pos = pos + len + 1;
380   
381   return retval;
382 }
383
384 /**
385  * If in verbose mode, print a block of binary data.
386  *
387  * @param data the data
388  * @param len the length of the data
389  */
390 void
391 _dbus_verbose_bytes (const unsigned char *data,
392                      int                  len)
393 {
394   int i;
395   const unsigned char *aligned;
396
397   /* Print blanks on first row if appropriate */
398   aligned = DBUS_ALIGN_ADDRESS (data, 4);
399   if (aligned > data)
400     aligned -= 4;
401   _dbus_assert (aligned <= data);
402
403   if (aligned != data)
404     {
405       _dbus_verbose ("%5d\t%p: ", - (data - aligned), aligned); 
406       while (aligned != data)
407         {
408           _dbus_verbose ("    ");
409           ++aligned;
410         }
411     }
412
413   /* now print the bytes */
414   i = 0;
415   while (i < len)
416     {
417       if (DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i])
418         {
419           _dbus_verbose ("%5d\t%p: ",
420                    i, &data[i]);
421         }
422       
423       if (data[i] >= 32 &&
424           data[i] <= 126)
425         _dbus_verbose (" '%c' ", data[i]);
426       else
427         _dbus_verbose ("0x%s%x ",
428                  data[i] <= 0xf ? "0" : "", data[i]);
429
430       ++i;
431
432       if (DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i])
433         {
434           if (i > 3)
435             _dbus_verbose ("big: %d little: %d",
436                      unpack_uint32 (DBUS_BIG_ENDIAN, &data[i-4]),
437                      unpack_uint32 (DBUS_LITTLE_ENDIAN, &data[i-4]));
438           
439           _dbus_verbose ("\n");
440         }
441     }
442
443   _dbus_verbose ("\n");
444 }
445
446 /**
447  * Dump the given part of the string to verbose log.
448  *
449  * @param str the string
450  * @param start the start of range to dump
451  * @param len length of range
452  */
453 void
454 _dbus_verbose_bytes_of_string (const DBusString    *str,
455                                int                  start,
456                                int                  len)
457 {
458   const char *d;
459
460   _dbus_string_get_const_data_len (str, &d, start, len);
461
462   _dbus_verbose_bytes (d, len);
463 }
464
465 /** @} */
466
467 #ifdef DBUS_BUILD_TESTS
468 #include "dbus-test.h"
469 #include <stdio.h>
470
471 dbus_bool_t
472 _dbus_marshal_test (void)
473 {
474   DBusString str;
475   char *tmp1, *tmp2;
476   int pos = 0;
477   
478   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
479     _dbus_assert_not_reached ("failed to init string");
480
481
482   /* Marshal doubles */
483   if (!_dbus_marshal_double (&str, DBUS_BIG_ENDIAN, 3.14))
484     _dbus_assert_not_reached ("could not marshal double value");
485   _dbus_assert (_dbus_demarshal_double (&str, DBUS_BIG_ENDIAN, pos, &pos) == 3.14);
486
487   
488   if (!_dbus_marshal_double (&str, DBUS_LITTLE_ENDIAN, 3.14))
489     _dbus_assert_not_reached ("could not marshal double value");
490   _dbus_assert (_dbus_demarshal_double (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == 3.14);
491   
492   /* Marshal signed integers */
493   if (!_dbus_marshal_int32 (&str, DBUS_BIG_ENDIAN, -12345678))
494     _dbus_assert_not_reached ("could not marshal signed integer value");
495   _dbus_assert (_dbus_demarshal_int32 (&str, DBUS_BIG_ENDIAN, pos, &pos) == -12345678);
496
497   if (!_dbus_marshal_int32 (&str, DBUS_LITTLE_ENDIAN, -12345678))
498     _dbus_assert_not_reached ("could not marshal signed integer value");
499   _dbus_assert (_dbus_demarshal_int32 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == -12345678);
500   
501   /* Marshal unsigned integers */
502   if (!_dbus_marshal_uint32 (&str, DBUS_BIG_ENDIAN, 0x12345678))
503     _dbus_assert_not_reached ("could not marshal signed integer value");
504   _dbus_assert (_dbus_demarshal_uint32 (&str, DBUS_BIG_ENDIAN, pos, &pos) == 0x12345678);
505   
506   if (!_dbus_marshal_uint32 (&str, DBUS_LITTLE_ENDIAN, 0x12345678))
507     _dbus_assert_not_reached ("could not marshal signed integer value");
508   _dbus_assert (_dbus_demarshal_uint32 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == 0x12345678);
509
510   /* Marshal strings */
511   tmp1 = "This is the dbus test string";
512   if (!_dbus_marshal_string (&str, DBUS_BIG_ENDIAN, tmp1))
513     _dbus_assert_not_reached ("could not marshal string");
514   tmp2 = _dbus_demarshal_string (&str, DBUS_BIG_ENDIAN, pos, &pos);
515   _dbus_assert (strcmp (tmp1, tmp2) == 0);
516   dbus_free (tmp2);
517
518   tmp1 = "This is the dbus test string";
519   if (!_dbus_marshal_string (&str, DBUS_LITTLE_ENDIAN, tmp1))
520     _dbus_assert_not_reached ("could not marshal string");
521   tmp2 = _dbus_demarshal_string (&str, DBUS_LITTLE_ENDIAN, pos, &pos);
522   _dbus_assert (strcmp (tmp1, tmp2) == 0);
523   dbus_free (tmp2);
524
525   _dbus_string_free (&str);
526   
527   return TRUE;
528 }
529
530 #endif /* DBUS_BUILD_TESTS */