]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/bus-gvariant.c
sd-bus: fix marshaling of unary type
[thirdparty/systemd.git] / src / libsystemd / sd-bus / bus-gvariant.c
CommitLineData
c1b9d935
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
c1b9d935
LP
22#include "bus-type.h"
23#include "bus-gvariant.h"
24#include "bus-signature.h"
25
6647dc66
LP
26int bus_gvariant_get_size(const char *signature) {
27 const char *p;
28 int sum = 0, r;
c1b9d935 29
6647dc66 30 /* For fixed size structs. Fails for variable size structs. */
c1b9d935 31
6647dc66
LP
32 p = signature;
33 while (*p != 0) {
34 size_t n;
c1b9d935 35
6647dc66
LP
36 r = signature_element_length(p, &n);
37 if (r < 0)
38 return r;
39 else {
40 char t[n+1];
41
42 memcpy(t, p, n);
43 t[n] = 0;
c1b9d935 44
6647dc66
LP
45 r = bus_gvariant_get_alignment(t);
46 if (r < 0)
47 return r;
c1b9d935 48
6647dc66
LP
49 sum = ALIGN_TO(sum, r);
50 }
51
52 switch (*p) {
53
54 case SD_BUS_TYPE_BOOLEAN:
55 case SD_BUS_TYPE_BYTE:
56 sum += 1;
57 break;
58
59 case SD_BUS_TYPE_INT16:
60 case SD_BUS_TYPE_UINT16:
61 sum += 2;
62 break;
63
64 case SD_BUS_TYPE_INT32:
65 case SD_BUS_TYPE_UINT32:
66 case SD_BUS_TYPE_UNIX_FD:
67 sum += 4;
68 break;
69
70 case SD_BUS_TYPE_INT64:
71 case SD_BUS_TYPE_UINT64:
72 case SD_BUS_TYPE_DOUBLE:
73 sum += 8;
74 break;
75
76 case SD_BUS_TYPE_STRUCT_BEGIN:
77 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
e53d21d0
DH
78 if (n == 2) {
79 /* unary type () has fixed size of 1 */
80 r = 1;
81 } else {
82 char t[n-1];
83
84 memcpy(t, p + 1, n - 2);
85 t[n - 2] = 0;
86
87 r = bus_gvariant_get_size(t);
88 if (r < 0)
89 return r;
90 }
6647dc66
LP
91
92 sum += r;
93 break;
94 }
95
96 case SD_BUS_TYPE_STRING:
97 case SD_BUS_TYPE_OBJECT_PATH:
98 case SD_BUS_TYPE_SIGNATURE:
99 case SD_BUS_TYPE_ARRAY:
100 case SD_BUS_TYPE_VARIANT:
101 return -EINVAL;
102
103 default:
104 assert_not_reached("Unknown signature type");
105 }
106
107 p += n;
c1b9d935
LP
108 }
109
6647dc66
LP
110 r = bus_gvariant_get_alignment(signature);
111 if (r < 0)
112 return r;
113
114 return ALIGN_TO(sum, r);
c1b9d935
LP
115}
116
117int bus_gvariant_get_alignment(const char *signature) {
118 size_t alignment = 1;
119 const char *p;
120 int r;
121
122 p = signature;
123 while (*p != 0 && alignment < 8) {
124 size_t n;
125 int a;
126
127 r = signature_element_length(p, &n);
128 if (r < 0)
129 return r;
130
131 switch (*p) {
132
133 case SD_BUS_TYPE_BYTE:
134 case SD_BUS_TYPE_BOOLEAN:
135 case SD_BUS_TYPE_STRING:
136 case SD_BUS_TYPE_OBJECT_PATH:
137 case SD_BUS_TYPE_SIGNATURE:
138 a = 1;
139 break;
140
141 case SD_BUS_TYPE_INT16:
142 case SD_BUS_TYPE_UINT16:
143 a = 2;
144 break;
145
146 case SD_BUS_TYPE_INT32:
147 case SD_BUS_TYPE_UINT32:
148 case SD_BUS_TYPE_UNIX_FD:
149 a = 4;
150 break;
151
152 case SD_BUS_TYPE_INT64:
153 case SD_BUS_TYPE_UINT64:
154 case SD_BUS_TYPE_DOUBLE:
155 case SD_BUS_TYPE_VARIANT:
156 a = 8;
157 break;
158
159 case SD_BUS_TYPE_ARRAY: {
160 char t[n];
161
162 memcpy(t, p + 1, n - 1);
163 t[n - 1] = 0;
164
165 a = bus_gvariant_get_alignment(t);
166 break;
167 }
168
169 case SD_BUS_TYPE_STRUCT_BEGIN:
170 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
171 char t[n-1];
172
173 memcpy(t, p + 1, n - 2);
174 t[n - 2] = 0;
175
176 a = bus_gvariant_get_alignment(t);
177 break;
178 }
179
180 default:
181 assert_not_reached("Unknown signature type");
182 }
183
184 if (a < 0)
185 return a;
186
187 assert(a > 0 && a <= 8);
188 if ((size_t) a > alignment)
189 alignment = (size_t) a;
190
191 p += n;
192 }
193
194 return alignment;
195}
196
197int bus_gvariant_is_fixed_size(const char *signature) {
198 const char *p;
199 int r;
200
201 assert(signature);
202
203 p = signature;
204 while (*p != 0) {
205 size_t n;
206
207 r = signature_element_length(p, &n);
208 if (r < 0)
209 return r;
210
211 switch (*p) {
212
213 case SD_BUS_TYPE_STRING:
214 case SD_BUS_TYPE_OBJECT_PATH:
215 case SD_BUS_TYPE_SIGNATURE:
216 case SD_BUS_TYPE_ARRAY:
217 case SD_BUS_TYPE_VARIANT:
218 return 0;
219
220 case SD_BUS_TYPE_BYTE:
221 case SD_BUS_TYPE_BOOLEAN:
222 case SD_BUS_TYPE_INT16:
223 case SD_BUS_TYPE_UINT16:
224 case SD_BUS_TYPE_INT32:
225 case SD_BUS_TYPE_UINT32:
226 case SD_BUS_TYPE_UNIX_FD:
227 case SD_BUS_TYPE_INT64:
228 case SD_BUS_TYPE_UINT64:
229 case SD_BUS_TYPE_DOUBLE:
230 break;
231
232 case SD_BUS_TYPE_STRUCT_BEGIN:
233 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
234 char t[n-1];
235
236 memcpy(t, p + 1, n - 2);
237 t[n - 2] = 0;
238
239 r = bus_gvariant_is_fixed_size(t);
240 if (r <= 0)
241 return r;
242 break;
243 }
244
245 default:
246 assert_not_reached("Unknown signature type");
247 }
248
249 p += n;
250 }
251
252 return true;
253}
2ac7c17f
LP
254
255size_t bus_gvariant_determine_word_size(size_t sz, size_t extra) {
256 if (sz + extra <= 0xFF)
257 return 1;
258 else if (sz + extra*2 <= 0xFFFF)
259 return 2;
260 else if (sz + extra*4 <= 0xFFFFFFFF)
261 return 4;
262 else
263 return 8;
264}
265
266size_t bus_gvariant_read_word_le(void *p, size_t sz) {
267 union {
268 uint16_t u16;
269 uint32_t u32;
270 uint64_t u64;
271 } x;
272
273 assert(p);
274
275 if (sz == 1)
276 return *(uint8_t*) p;
277
278 memcpy(&x, p, sz);
279
280 if (sz == 2)
281 return le16toh(x.u16);
282 else if (sz == 4)
283 return le32toh(x.u32);
284 else if (sz == 8)
285 return le64toh(x.u64);
286
287 assert_not_reached("unknown word width");
288}
289
290void bus_gvariant_write_word_le(void *p, size_t sz, size_t value) {
291 union {
292 uint16_t u16;
293 uint32_t u32;
294 uint64_t u64;
295 } x;
296
297 assert(p);
298 assert(sz == 8 || (value < (1ULL << (sz*8))));
299
300 if (sz == 1) {
301 *(uint8_t*) p = value;
302 return;
303 } else if (sz == 2)
304 x.u16 = htole16((uint16_t) value);
305 else if (sz == 4)
306 x.u32 = htole32((uint32_t) value);
307 else if (sz == 8)
308 x.u64 = htole64((uint64_t) value);
309 else
310 assert_not_reached("unknown word width");
311
312 memcpy(p, &x, sz);
313}