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