2003-01-02 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 dbus_bool_t
128 _dbus_marshal_double (DBusString *str,
129                       int         byte_order,
130                       double      value)
131 {
132   if (!_dbus_string_set_length (str,
133                                 DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
134                                                   sizeof (double))))
135     return FALSE;
136   
137   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
138     swap_bytes ((unsigned char *)&value, sizeof (double));
139
140   return _dbus_string_append_len (str, (const char *)&value, sizeof (double));
141 }
142
143 dbus_bool_t
144 _dbus_marshal_int32  (DBusString   *str,
145                       int           byte_order,
146                       dbus_int32_t  value)
147 {
148   if (!_dbus_string_set_length (str,
149                                 DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
150                                                   sizeof (dbus_int32_t))))
151     return FALSE;
152   
153   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
154     swap_bytes ((unsigned char *)&value, sizeof (dbus_int32_t));
155
156   return _dbus_string_append_len (str, (const char *)&value, sizeof (dbus_int32_t));
157 }
158
159 dbus_bool_t
160 _dbus_marshal_uint32 (DBusString    *str,
161                       int            byte_order,
162                       dbus_uint32_t  value)
163 {
164   if (!_dbus_string_set_length (str,
165                                 DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
166                                                   sizeof (dbus_uint32_t))))
167     return FALSE;
168
169   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
170     swap_bytes ((unsigned char *)&value, sizeof (dbus_uint32_t));
171
172   return _dbus_string_append_len (str, (const char *)&value, sizeof (dbus_uint32_t));
173 }
174
175 dbus_bool_t
176 _dbus_marshal_utf8_string (DBusString    *str,
177                            int            byte_order,
178                            const char    *value)
179 {
180   int len;
181
182   len = strlen (value);
183
184   if (!_dbus_marshal_uint32 (str, byte_order, len))
185     return FALSE;
186
187   return _dbus_string_append_len (str, value, len + 1);
188 }
189
190 dbus_bool_t
191 _dbus_marshal_byte_array (DBusString          *str,
192                           int                  byte_order,
193                           const unsigned char *value,
194                           int                  len)
195 {
196   if (!_dbus_marshal_uint32 (str, byte_order, len))
197     return FALSE;
198
199   return _dbus_string_append_len (str, value, len);
200 }
201
202 double
203 _dbus_demarshal_double (DBusString  *str,
204                         int          byte_order,
205                         int          pos,
206                         int         *new_pos)
207 {
208   double retval;
209   const char *buffer;
210
211   pos = DBUS_ALIGN_VALUE (pos, sizeof (double));
212   
213   _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (double));
214
215   retval = *(double *)buffer;
216   
217   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
218     swap_bytes ((unsigned char *)&retval, sizeof (double));
219
220   if (new_pos)
221     *new_pos = pos + sizeof (double);
222   
223   return retval;  
224 }
225
226 dbus_int32_t
227 _dbus_demarshal_int32  (DBusString *str,
228                         int         byte_order,
229                         int         pos,
230                         int        *new_pos)
231 {
232   const char *buffer;
233
234   pos = DBUS_ALIGN_VALUE (pos, sizeof (dbus_int32_t));
235   
236   _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (dbus_int32_t));
237
238   if (new_pos)
239     *new_pos = pos + sizeof (dbus_int32_t);
240
241   return unpack_int32 (byte_order, buffer);
242 }
243
244 dbus_uint32_t
245 _dbus_demarshal_uint32  (DBusString *str,
246                          int         byte_order,
247                          int         pos,
248                          int        *new_pos)
249 {
250   const char *buffer;
251
252   pos = DBUS_ALIGN_VALUE (pos, sizeof (dbus_uint32_t));
253   
254   _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (dbus_uint32_t));
255
256   if (new_pos)
257     *new_pos = pos + sizeof (dbus_uint32_t);
258
259   return unpack_uint32 (byte_order, buffer);
260 }
261
262 char *
263 _dbus_demarshal_utf8_string (DBusString *str,
264                              int         byte_order,
265                              int         pos,
266                              int        *new_pos)
267 {
268   int len;
269   char *retval;
270   const char *data;
271
272   len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
273
274   retval = dbus_malloc (len + 1);
275
276   if (!retval)
277     return NULL;
278
279   _dbus_string_get_const_data_len (str, &data, pos, 3);
280
281   if (!data)
282     return NULL;
283
284   memcpy (retval, data, len + 1);
285
286   if (new_pos)
287     *new_pos = pos + len + 1;
288   
289   return retval;
290 }
291
292 /**
293  * If in verbose mode, print a block of binary data.
294  *
295  * @param data the data
296  * @param len the length of the data
297  */
298 void
299 _dbus_verbose_bytes (const unsigned char *data,
300                      int                  len)
301 {
302   int i;
303   const unsigned char *aligned;
304
305   /* Print blanks on first row if appropriate */
306   aligned = DBUS_ALIGN_ADDRESS (data, 4);
307   if (aligned > data)
308     aligned -= 4;
309   _dbus_assert (aligned <= data);
310
311   if (aligned != data)
312     {
313       _dbus_verbose ("%5d\t%p: ", - (data - aligned), aligned); 
314       while (aligned != data)
315         {
316           _dbus_verbose ("    ");
317           ++aligned;
318         }
319     }
320
321   /* now print the bytes */
322   i = 0;
323   while (i < len)
324     {
325       if (DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i])
326         {
327           _dbus_verbose ("%5d\t%p: ",
328                    i, &data[i]);
329         }
330       
331       if (data[i] >= 32 &&
332           data[i] <= 126)
333         _dbus_verbose (" '%c' ", data[i]);
334       else
335         _dbus_verbose ("0x%s%x ",
336                  data[i] <= 0xf ? "0" : "", data[i]);
337
338       ++i;
339
340       if (DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i])
341         {
342           if (i > 3)
343             _dbus_verbose ("big: %d little: %d",
344                      unpack_uint32 (DBUS_BIG_ENDIAN, &data[i-4]),
345                      unpack_uint32 (DBUS_LITTLE_ENDIAN, &data[i-4]));
346           
347           _dbus_verbose ("\n");
348         }
349     }
350
351   _dbus_verbose ("\n");
352 }
353
354 /**
355  * Dump the given part of the string to verbose log.
356  *
357  * @param str the string
358  * @param start the start of range to dump
359  * @param len length of range
360  */
361 void
362 _dbus_verbose_bytes_of_string (const DBusString    *str,
363                                int                  start,
364                                int                  len)
365 {
366   const char *d;
367
368   _dbus_string_get_const_data_len (str, &d, start, len);
369
370   _dbus_verbose_bytes (d, len);
371 }
372
373 /** @} */
374
375 #ifdef DBUS_BUILD_TESTS
376 #include "dbus-test.h"
377 #include <stdio.h>
378
379 dbus_bool_t
380 _dbus_marshal_test (void)
381 {
382   DBusString str;
383   char *tmp1, *tmp2;
384   int pos = 0;
385   
386   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
387     _dbus_assert_not_reached ("failed to init string");
388
389
390   /* Marshal doubles */
391   if (!_dbus_marshal_double (&str, DBUS_BIG_ENDIAN, 3.14))
392     _dbus_assert_not_reached ("could not marshal double value");
393   _dbus_assert (_dbus_demarshal_double (&str, DBUS_BIG_ENDIAN, pos, &pos) == 3.14);
394
395   
396   if (!_dbus_marshal_double (&str, DBUS_LITTLE_ENDIAN, 3.14))
397     _dbus_assert_not_reached ("could not marshal double value");
398   _dbus_assert (_dbus_demarshal_double (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == 3.14);
399   
400   /* Marshal signed integers */
401   if (!_dbus_marshal_int32 (&str, DBUS_BIG_ENDIAN, -12345678))
402     _dbus_assert_not_reached ("could not marshal signed integer value");
403   _dbus_assert (_dbus_demarshal_int32 (&str, DBUS_BIG_ENDIAN, pos, &pos) == -12345678);
404
405   if (!_dbus_marshal_int32 (&str, DBUS_LITTLE_ENDIAN, -12345678))
406     _dbus_assert_not_reached ("could not marshal signed integer value");
407   _dbus_assert (_dbus_demarshal_int32 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == -12345678);
408   
409   /* Marshal unsigned integers */
410   if (!_dbus_marshal_uint32 (&str, DBUS_BIG_ENDIAN, 0x12345678))
411     _dbus_assert_not_reached ("could not marshal signed integer value");
412   _dbus_assert (_dbus_demarshal_uint32 (&str, DBUS_BIG_ENDIAN, pos, &pos) == 0x12345678);
413   
414   if (!_dbus_marshal_uint32 (&str, DBUS_LITTLE_ENDIAN, 0x12345678))
415     _dbus_assert_not_reached ("could not marshal signed integer value");
416   _dbus_assert (_dbus_demarshal_uint32 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == 0x12345678);
417
418   /* Marshal strings */
419   tmp1 = "This is the dbus test string";
420   if (!_dbus_marshal_utf8_string (&str, DBUS_BIG_ENDIAN, tmp1))
421     _dbus_assert_not_reached ("could not marshal string");
422   tmp2 = _dbus_demarshal_utf8_string (&str, DBUS_BIG_ENDIAN, pos, &pos);
423   _dbus_assert (strcmp (tmp1, tmp2) == 0);
424   dbus_free (tmp2);
425
426   tmp1 = "This is the dbus test string";
427   if (!_dbus_marshal_utf8_string (&str, DBUS_LITTLE_ENDIAN, tmp1))
428     _dbus_assert_not_reached ("could not marshal string");
429   tmp2 = _dbus_demarshal_utf8_string (&str, DBUS_LITTLE_ENDIAN, pos, &pos);
430   _dbus_assert (strcmp (tmp1, tmp2) == 0);
431   dbus_free (tmp2);
432
433   _dbus_string_free (&str);
434   
435   return TRUE;
436 }
437
438 #endif /* DBUS_BUILD_TESTS */