2002-12-26 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 /* This alignment thing is from ORBit2 */
30 /* Align a value upward to a boundary, expressed as a number of bytes.
31    E.g. align to an 8-byte boundary with argument of 8.  */
32
33 /*
34  *   (this + boundary - 1)
35  *          &
36  *    ~(boundary - 1)
37  */
38
39 #define DBUS_ALIGN_VALUE(this, boundary) \
40   (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
41
42 #define DBUS_ALIGN_ADDRESS(this, boundary) \
43   ((void*)DBUS_ALIGN_VALUE(this, boundary))
44
45 /* from ORBit */
46 static void
47 swap_bytes (unsigned char *data,
48             unsigned int   len)
49 {
50   unsigned char *p1 = data;
51   unsigned char *p2 = data + len - 1;
52
53   while (p1 < p2)
54     {
55       unsigned char tmp = *p1;
56       *p1 = *p2;
57       *p2 = tmp;
58
59       --p2;
60       ++p1;
61     }
62 }
63
64 dbus_bool_t
65 _dbus_marshal_double (DBusString *str,
66                       int         byte_order,
67                       double      value)
68 {
69   if (!_dbus_string_set_length (str,
70                                 DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
71                                                   sizeof (double))))
72     return FALSE;
73   
74   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
75     swap_bytes ((unsigned char *)&value, sizeof (double));
76
77   return _dbus_string_append_len (str, (const char *)&value, sizeof (double));
78 }
79
80 dbus_bool_t
81 _dbus_marshal_int32  (DBusString   *str,
82                       int           byte_order,
83                       dbus_int32_t  value)
84 {
85   if (!_dbus_string_set_length (str,
86                                 DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
87                                                   sizeof (dbus_int32_t))))
88     return FALSE;
89   
90   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
91     swap_bytes ((unsigned char *)&value, sizeof (dbus_int32_t));
92
93   return _dbus_string_append_len (str, (const char *)&value, sizeof (dbus_int32_t));
94 }
95
96 dbus_bool_t
97 _dbus_marshal_uint32 (DBusString    *str,
98                       int            byte_order,
99                       dbus_uint32_t  value)
100 {
101   if (!_dbus_string_set_length (str,
102                                 DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
103                                                   sizeof (dbus_uint32_t))))
104     return FALSE;
105
106   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
107     swap_bytes ((unsigned char *)&value, sizeof (dbus_uint32_t));
108
109   return _dbus_string_append_len (str, (const char *)&value, sizeof (dbus_uint32_t));
110 }
111
112 dbus_bool_t
113 _dbus_marshal_string (DBusString    *str,
114                       int            byte_order,
115                       const char    *value)
116 {
117   int len;
118   
119   if (!_dbus_string_set_length (str,
120                                 DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
121                                                   sizeof (dbus_uint32_t))))
122     return FALSE;
123
124   len = strlen (value);
125   
126   if (!_dbus_string_lengthen (str, len + 1))
127     return FALSE;
128
129   if (!_dbus_marshal_uint32 (str, byte_order, len))
130     return FALSE;
131       
132   return _dbus_string_append_len (str, value, len + 1);
133 }
134
135
136 double
137 _dbus_demarshal_double (DBusString  *str,
138                         int          byte_order,
139                         int          pos,
140                         int         *new_pos)
141 {
142   double retval;
143   const char *buffer;
144   
145   _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (double));
146
147   retval = *(double *)buffer;
148   
149   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
150     swap_bytes ((unsigned char *)&retval, sizeof (double));
151
152   if (new_pos)
153     *new_pos = pos + sizeof (double);
154   
155   return retval;  
156 }
157
158 dbus_int32_t
159 _dbus_demarshal_int32  (DBusString *str,
160                         int         byte_order,
161                         int         pos,
162                         int        *new_pos)
163 {
164   dbus_int32_t retval;
165   const char *buffer;
166
167   _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (dbus_int32_t));
168
169   retval = *(dbus_int32_t *)buffer;
170
171   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
172     swap_bytes ((unsigned char *)&retval, sizeof (dbus_int32_t));
173
174   if (new_pos)
175     *new_pos = pos + sizeof (dbus_int32_t);
176   
177   return retval;  
178 }
179
180 dbus_uint32_t
181 _dbus_demarshal_uint32  (DBusString *str,
182                          int         byte_order,
183                          int         pos,
184                          int        *new_pos)
185 {
186   dbus_uint32_t retval;
187   const char *buffer;
188
189   _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (dbus_uint32_t));
190
191   retval = *(dbus_uint32_t *)buffer;
192
193   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
194     swap_bytes ((unsigned char *)&retval, sizeof (dbus_uint32_t));
195
196   if (new_pos)
197     *new_pos = pos + sizeof (dbus_uint32_t);
198   
199   return retval;  
200 }
201
202 char *
203 _dbus_demarshal_string (DBusString *str,
204                         int         byte_order,
205                         int         pos,
206                         int        *new_pos)
207 {
208   int len;
209   char *retval;
210   const char *data;
211   
212   len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
213
214   retval = dbus_malloc (len + 1);
215
216   if (!retval)
217     return NULL;
218
219   _dbus_string_get_const_data_len (str, &data, pos, len + 1);
220   
221   if (!data)
222     return NULL;
223
224   memcpy (retval, data, len + 1);
225
226   if (new_pos)
227     *new_pos = pos + len + 1;
228   
229   return retval;
230 }
231
232 /** @} */
233
234 #ifdef DBUS_BUILD_TESTS
235 #include "dbus-test.h"
236 #include <stdio.h>
237
238 dbus_bool_t
239 _dbus_marshal_test (void)
240 {
241   DBusString str;
242   int pos = 0;
243   
244   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
245     _dbus_assert_not_reached ("failed to init string");
246
247
248   /* Marshal doubles */
249   if (!_dbus_marshal_double (&str, DBUS_BIG_ENDIAN, 3.14))
250     _dbus_assert_not_reached ("could not marshal double value");
251   _dbus_assert (_dbus_demarshal_double (&str, DBUS_BIG_ENDIAN, pos, &pos) == 3.14);
252
253   
254   if (!_dbus_marshal_double (&str, DBUS_LITTLE_ENDIAN, 3.14))
255     _dbus_assert_not_reached ("could not marshal double value");
256   _dbus_assert (_dbus_demarshal_double (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == 3.14);
257   
258   /* Marshal signed integers */
259   if (!_dbus_marshal_int32 (&str, DBUS_BIG_ENDIAN, -12345678))
260     _dbus_assert_not_reached ("could not marshal signed integer value");
261   _dbus_assert (_dbus_demarshal_int32 (&str, DBUS_BIG_ENDIAN, pos, &pos) == -12345678);
262
263   if (!_dbus_marshal_int32 (&str, DBUS_LITTLE_ENDIAN, -12345678))
264     _dbus_assert_not_reached ("could not marshal signed integer value");
265   _dbus_assert (_dbus_demarshal_int32 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == -12345678);
266   
267   /* Marshal unsigned integers */
268   if (!_dbus_marshal_uint32 (&str, DBUS_LITTLE_ENDIAN, 0x12345678))
269     _dbus_assert_not_reached ("could not marshal signed integer value");
270   _dbus_assert (_dbus_demarshal_uint32 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == 0x12345678);
271   
272   _dbus_string_free (&str);
273
274   /* FIXME. Add string marshal tests */
275   
276   return TRUE;
277 }
278
279 #endif /* DBUS_BUILD_TESTS */