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