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