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