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