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