2002-12-25 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
28 /* This alignment thing is from ORBit2 */
29 /* Align a value upward to a boundary, expressed as a number of bytes.
30    E.g. align to an 8-byte boundary with argument of 8.  */
31
32 /*
33  *   (this + boundary - 1)
34  *          &
35  *    ~(boundary - 1)
36  */
37
38 #define DBUS_ALIGN_VALUE(this, boundary) \
39   (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
40
41 #define DBUS_ALIGN_ADDRESS(this, boundary) \
42   ((void*)DBUS_ALIGN_VALUE(this, boundary))
43
44 /* from ORBit */
45 static void
46 swap_bytes (unsigned char *data,
47             unsigned int   len)
48 {
49   unsigned char *p1 = data;
50   unsigned char *p2 = data + len - 1;
51
52   while (p1 < p2)
53     {
54       unsigned char tmp = *p1;
55       *p1 = *p2;
56       *p2 = tmp;
57
58       --p2;
59       ++p1;
60     }
61 }
62
63 dbus_bool_t
64 _dbus_marshal_double (DBusString *str,
65                       int         byte_order,
66                       double      value)
67 {
68   if (!_dbus_string_set_length (str,
69                                 DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
70                                                   sizeof (double))))
71     return FALSE;
72   
73   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
74     swap_bytes ((unsigned char *)&value, sizeof (double));
75
76   return _dbus_string_append_len (str, (const char *)&value, sizeof (double));
77 }
78
79 dbus_bool_t
80 _dbus_marshal_int32  (DBusString   *str,
81                       int           byte_order,
82                       dbus_int32_t  value)
83 {
84   if (!_dbus_string_set_length (str,
85                                 DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
86                                                   sizeof (dbus_int32_t))))
87     return FALSE;
88   
89   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
90     swap_bytes ((unsigned char *)&value, sizeof (dbus_int32_t));
91
92   return _dbus_string_append_len (str, (const char *)&value, sizeof (dbus_int32_t));
93 }
94
95 dbus_bool_t
96 _dbus_marshal_uint32 (DBusString    *str,
97                       int            byte_order,
98                       dbus_uint32_t  value)
99 {
100   if (!_dbus_string_set_length (str,
101                                 DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
102                                                   sizeof (dbus_uint32_t))))
103     return FALSE;
104
105   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
106     swap_bytes ((unsigned char *)&value, sizeof (dbus_uint32_t));
107
108   return _dbus_string_append_len (str, (const char *)&value, sizeof (dbus_uint32_t));
109 }
110
111
112
113 double
114 _dbus_demarshal_double (DBusString  *str,
115                         int          byte_order,
116                         int          start)
117 {
118   double retval;
119   const char *buffer;
120   
121   _dbus_string_get_const_data_len (str, &buffer, start, sizeof (double));
122
123   retval = *(double *)buffer;
124   
125   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
126     swap_bytes ((unsigned char *)&retval, sizeof (double));
127
128   return retval;  
129 }
130
131 dbus_int32_t
132 _dbus_demarshal_int32  (DBusString *str,
133                         int         byte_order,
134                         int         start)
135 {
136   dbus_int32_t retval;
137   const char *buffer;
138
139   _dbus_string_get_const_data_len (str, &buffer, start, sizeof (dbus_int32_t));
140
141   retval = *(dbus_int32_t *)buffer;
142
143   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
144     swap_bytes ((unsigned char *)&retval, sizeof (dbus_int32_t));
145
146   return retval;  
147 }
148
149 dbus_uint32_t
150 _dbus_demarshal_uint32  (DBusString *str,
151                          int         byte_order,
152                          int         start)
153 {
154   dbus_uint32_t retval;
155   const char *buffer;
156
157   _dbus_string_get_const_data_len (str, &buffer, start, sizeof (dbus_uint32_t));
158
159   retval = *(dbus_uint32_t *)buffer;
160
161   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
162     swap_bytes ((unsigned char *)&retval, sizeof (dbus_uint32_t));
163
164   return retval;  
165 }
166
167 /** @} */
168
169 #ifdef DBUS_BUILD_TESTS
170 #include "dbus-test.h"
171 #include <stdio.h>
172
173 dbus_bool_t
174 _dbus_marshal_test (void)
175 {
176   DBusString str;
177   int pos = 0;
178   
179   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
180     _dbus_assert_not_reached ("failed to init string");
181
182
183   /* Marshal doubles */
184   if (!_dbus_marshal_double (&str, DBUS_BIG_ENDIAN, 3.14))
185     _dbus_assert_not_reached ("could not marshal double value");
186   _dbus_assert (_dbus_demarshal_double (&str, DBUS_BIG_ENDIAN, pos) == 3.14);
187   pos += 8;
188   
189   if (!_dbus_marshal_double (&str, DBUS_LITTLE_ENDIAN, 3.14))
190     _dbus_assert_not_reached ("could not marshal double value");
191   _dbus_assert (_dbus_demarshal_double (&str, DBUS_LITTLE_ENDIAN, pos) == 3.14);
192   pos += 8;
193   
194   /* Marshal signed integers */
195   if (!_dbus_marshal_int32 (&str, DBUS_BIG_ENDIAN, -12345678))
196     _dbus_assert_not_reached ("could not marshal signed integer value");
197   _dbus_assert (_dbus_demarshal_int32 (&str, DBUS_BIG_ENDIAN, pos) == -12345678);
198   pos += 4;
199
200   if (!_dbus_marshal_int32 (&str, DBUS_LITTLE_ENDIAN, -12345678))
201     _dbus_assert_not_reached ("could not marshal signed integer value");
202   _dbus_assert (_dbus_demarshal_int32 (&str, DBUS_LITTLE_ENDIAN, pos) == -12345678);
203   pos += 4;
204   
205   /* Marshal unsigned integers */
206   if (!_dbus_marshal_uint32 (&str, DBUS_LITTLE_ENDIAN, 0x12345678))
207     _dbus_assert_not_reached ("could not marshal signed integer value");
208   _dbus_assert (_dbus_demarshal_uint32 (&str, DBUS_LITTLE_ENDIAN, pos) == 0x12345678);
209   pos += 4;
210   
211   _dbus_string_free (&str);
212
213   return TRUE;
214 }
215
216 #endif /* DBUS_BUILD_TESTS */