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