/src/dbus-broker/subprojects/libcdvar-1/src/c-dvar.h
Line | Count | Source |
1 | | #pragma once |
2 | | |
3 | | /* |
4 | | * D-Bus Variant Type-System |
5 | | * |
6 | | * This library implements the D-Bus type-system as a variant type, including |
7 | | * marshalling and demarshalling functionality. It is fully implemented in |
8 | | * ISO-C11 and has no external dependencies. |
9 | | * |
10 | | * This type-system strictly adheres to the D-Bus spec, including its |
11 | | * limitations in size and depth. Unlike the related GVariant type-system, it |
12 | | * is not suitable for use outside of D-Bus. Hence, this implementation does |
13 | | * not strive to be universally applicable, but solely meant to be used with |
14 | | * D-Bus IPC. |
15 | | */ |
16 | | |
17 | | #ifdef __cplusplus |
18 | | extern "C" { |
19 | | #endif |
20 | | |
21 | | #include <endian.h> |
22 | | #include <errno.h> |
23 | | #include <inttypes.h> |
24 | | #include <stdarg.h> |
25 | | #include <stdbool.h> |
26 | | #include <stdlib.h> |
27 | | #include <string.h> |
28 | | |
29 | | typedef struct CDVar CDVar; |
30 | | typedef struct CDVarLevel CDVarLevel; |
31 | | typedef struct CDVarType CDVarType; |
32 | | |
33 | | /** |
34 | | * C_DVAR_TYPE_LENGTH_MAX - Maximum length of a type signature |
35 | | * |
36 | | * Every valid D-Bus Type has a string representation, called its type |
37 | | * signature. The maximum length of such a signature of a single complete type |
38 | | * is defined by the D-Bus specification to be 255. The original limit only |
39 | | * affects the maximum length of a signature of concatenated types. This, |
40 | | * however, implies that a single type has the same limit. |
41 | | * |
42 | | * No signature of any type can ever exceed this length. There is no intention |
43 | | * to every support longer signatures. If bigger types are needed, you better |
44 | | * use a non-deprecated serialization like GVariant. |
45 | | */ |
46 | | #define C_DVAR_TYPE_LENGTH_MAX (255) |
47 | | |
48 | | /** |
49 | | * C_DVAR_TYPE_DEPTH_MAX - Maximum depth of a type signature |
50 | | * |
51 | | * Similar to C_DVAR_TYPE_LENGTH_MAX, this limits the complexity of any valid |
52 | | * type signature. This limits the maximum depth of containers to 64. It is |
53 | | * defined by the D-Bus specification and enforced by this implementation. The |
54 | | * specification further restricts the depth among the different container |
55 | | * types. See the specification for details. |
56 | | * |
57 | | * No signature of any type can ever exceed this depth. There is no intention |
58 | | * to every support deeper signatures. If needed, you better use a |
59 | | * non-deprecated serialization like GVariant. |
60 | | */ |
61 | | #define C_DVAR_TYPE_DEPTH_MAX (64) |
62 | | |
63 | | enum { |
64 | | _C_DVAR_E_SUCCESS, |
65 | | |
66 | | /* type/signature errors */ |
67 | | C_DVAR_E_OVERLONG_TYPE, |
68 | | C_DVAR_E_DEPTH_OVERFLOW, |
69 | | C_DVAR_E_INVALID_TYPE, |
70 | | |
71 | | /* data errors */ |
72 | | C_DVAR_E_CORRUPT_DATA, |
73 | | C_DVAR_E_OUT_OF_BOUNDS, |
74 | | C_DVAR_E_TYPE_MISMATCH, |
75 | | }; |
76 | | |
77 | | /** |
78 | | * struct CDVarType - D-Bus Type Information |
79 | | * @size: size in bytes required for the serialization, 0 if dynamic |
80 | | * @alignment: required alignment, given as power of 2 |
81 | | * @element: character code of this entry |
82 | | * @length: length of the full type, given as number of entries |
83 | | * @basic: whether this is a basic type |
84 | | * |
85 | | * Every valid D-Bus Type can be parsed into an array of CDVarType objects, |
86 | | * containing detailed information about the type. The length of a parsed |
87 | | * CDVarType array is the same as the length of the same type signature. That |
88 | | * is, each character code in the type signature is parsed into a CDVarType |
89 | | * object, based on its position in the signature. |
90 | | * |
91 | | * A CDVarType array contains recursive type-information for all sub-types of a |
92 | | * valid type signature. For instance, the type array of '{sv}' is found |
93 | | * unmodified in the type array of '(ua{sv})' at offset 3. |
94 | | */ |
95 | | struct CDVarType { |
96 | | uint32_t size : 11; |
97 | | uint32_t alignment : 2; |
98 | | uint32_t element : 7; |
99 | | uint32_t length : 8; |
100 | | uint32_t basic : 1; |
101 | | uint32_t __padding : 3; |
102 | | }; |
103 | | |
104 | | /** |
105 | | * struct CDVarLevel - D-Bus Variant Level information |
106 | | * @parent_types: type information of the parent signature |
107 | | * @i_type: current type position in parent signature |
108 | | * @n_parent_types: number of single complete types in @parent_types |
109 | | * @n_type: remaining length after @i_type |
110 | | * @container: cached parent container element |
111 | | * @allocated_parent_types: whether @parent_types is owned and allocated |
112 | | * @i_buffer: current data position |
113 | | * @n_buffer: remaining length after @i_buffer |
114 | | * @index: cached container-dependent index |
115 | | */ |
116 | | struct CDVarLevel { |
117 | | CDVarType *parent_types; |
118 | | CDVarType *i_type; |
119 | | uint8_t n_parent_types; |
120 | | uint8_t n_type; |
121 | | uint8_t container : 7; |
122 | | uint8_t allocated_parent_types : 1; |
123 | | size_t i_buffer; |
124 | | union { |
125 | | /* reader */ |
126 | | size_t n_buffer; |
127 | | /* writer */ |
128 | | size_t index; |
129 | | }; |
130 | | }; |
131 | | |
132 | | /** |
133 | | * struct CDVar - D-Bus Variant |
134 | | * @data: data buffer to parse or write |
135 | | * @n_data: length of @data in bytes |
136 | | * @poison: current object poison error code, or 0 |
137 | | * @n_root_type: cached total signature length of the root type |
138 | | * @ro: object is read-only |
139 | | * @big_endian: data is provided as big-endian |
140 | | * @current: current level position |
141 | | * @levels: container levels |
142 | | */ |
143 | | struct CDVar { |
144 | | uint8_t *data; |
145 | | size_t n_data; |
146 | | |
147 | | int poison; |
148 | | uint8_t n_root_type; |
149 | | bool ro : 1; |
150 | | bool big_endian : 1; |
151 | | |
152 | | CDVarLevel *current; |
153 | | CDVarLevel levels[C_DVAR_TYPE_DEPTH_MAX + 1]; |
154 | | }; |
155 | | |
156 | 11.2k | #define C_DVAR_INIT { .big_endian = !!(__BYTE_ORDER == __BIG_ENDIAN) } |
157 | | |
158 | | /* builtin */ |
159 | | |
160 | | #define C_DVAR_TYPE_y (1, 0, 'y', 1, 1) |
161 | | #define C_DVAR_TYPE_b (4, 2, 'b', 1, 1) |
162 | | #define C_DVAR_TYPE_n (2, 1, 'n', 1, 1) |
163 | | #define C_DVAR_TYPE_q (2, 1, 'q', 1, 1) |
164 | | #define C_DVAR_TYPE_i (4, 2, 'i', 1, 1) |
165 | | #define C_DVAR_TYPE_u (4, 2, 'u', 1, 1) |
166 | | #define C_DVAR_TYPE_x (8, 3, 'x', 1, 1) |
167 | | #define C_DVAR_TYPE_t (8, 3, 't', 1, 1) |
168 | | #define C_DVAR_TYPE_h (4, 2, 'h', 1, 1) |
169 | | #define C_DVAR_TYPE_d (8, 3, 'd', 1, 1) |
170 | | #define C_DVAR_TYPE_s (0, 2, 's', 1, 1) |
171 | | #define C_DVAR_TYPE_o (0, 2, 'o', 1, 1) |
172 | | #define C_DVAR_TYPE_g (0, 0, 'g', 1, 1) |
173 | | #define C_DVAR_TYPE_v (0, 0, 'v', 1, 0) |
174 | | |
175 | | extern const CDVarType c_dvar_type_y[]; |
176 | | extern const CDVarType c_dvar_type_b[]; |
177 | | extern const CDVarType c_dvar_type_n[]; |
178 | | extern const CDVarType c_dvar_type_q[]; |
179 | | extern const CDVarType c_dvar_type_i[]; |
180 | | extern const CDVarType c_dvar_type_u[]; |
181 | | extern const CDVarType c_dvar_type_x[]; |
182 | | extern const CDVarType c_dvar_type_t[]; |
183 | | extern const CDVarType c_dvar_type_h[]; |
184 | | extern const CDVarType c_dvar_type_d[]; |
185 | | extern const CDVarType c_dvar_type_s[]; |
186 | | extern const CDVarType c_dvar_type_o[]; |
187 | | extern const CDVarType c_dvar_type_g[]; |
188 | | extern const CDVarType c_dvar_type_v[]; |
189 | | extern const CDVarType c_dvar_type_unit[]; |
190 | | |
191 | | /* type handling */ |
192 | | |
193 | | int c_dvar_type_new_from_signature(CDVarType **typep, const char *signature, size_t n_signature); |
194 | | CDVarType *c_dvar_type_free(CDVarType *type); |
195 | | |
196 | | int c_dvar_type_compare_string(const CDVarType *subject, const char *object, size_t n_object); |
197 | | |
198 | | /* variant management */ |
199 | | |
200 | | int c_dvar_new(CDVar **varp); |
201 | | CDVar *c_dvar_free(CDVar *var); |
202 | | void c_dvar_init(CDVar *var); |
203 | | void c_dvar_deinit(CDVar *var); |
204 | | |
205 | | bool c_dvar_is_big_endian(CDVar *var); |
206 | | int c_dvar_get_poison(CDVar *var); |
207 | | void c_dvar_get_data(CDVar *var, void **datap, size_t *n_datap); |
208 | | void c_dvar_get_root_types(CDVar *var, const CDVarType **typesp, size_t *n_typesp); |
209 | | void c_dvar_get_parent_types(CDVar *var, const CDVarType **typesp, size_t *n_typesp); |
210 | | |
211 | | void c_dvar_begin_read(CDVar *var, bool big_endian, const CDVarType *types, size_t n_types, const void *data, size_t n_data); |
212 | | bool c_dvar_more(CDVar *var); |
213 | | int c_dvar_vread(CDVar *var, const char *format, va_list args); |
214 | | int c_dvar_vskip(CDVar *var, const char *format, va_list args); |
215 | | int c_dvar_end_read(CDVar *var); |
216 | | |
217 | | bool c_dvar_is_path(const char *string, size_t n_string); |
218 | | |
219 | | void c_dvar_begin_write(CDVar *var, bool big_endian, const CDVarType *types, size_t n_types); |
220 | | int c_dvar_vwrite(CDVar *var, const char *format, va_list args); |
221 | | int c_dvar_end_write(CDVar *var, void **datap, size_t *n_datap); |
222 | | |
223 | | /* inline helpers */ |
224 | | |
225 | | /** |
226 | | * c_dvar_type_new_from_string() - allocate new type information from string |
227 | | * @typep: output argument for newly allocated object |
228 | | * @str: string representation of the type |
229 | | * |
230 | | * This is similar to c_dvar_type_new_from_signature(), but it fails if @str is |
231 | | * not a single complete type. In case @str contains more than a single |
232 | | * complete type, C_DVAR_E_INVALID_TYPE is returned. |
233 | | * |
234 | | * Return: 0 on success, negative error code on fatal failure, positive error |
235 | | * code on parser errors. |
236 | | */ |
237 | 0 | static inline int c_dvar_type_new_from_string(CDVarType **typep, const char *str) { |
238 | 0 | CDVarType *type = *typep ? : NULL; |
239 | 0 | size_t n; |
240 | 0 | int r; |
241 | 0 |
|
242 | 0 | n = strlen(str); |
243 | 0 | r = c_dvar_type_new_from_signature(&type, str, n); |
244 | 0 | if (r) |
245 | 0 | return r; |
246 | 0 |
|
247 | 0 | if (n != type->length) { |
248 | 0 | if (!*typep) |
249 | 0 | c_dvar_type_free(type); |
250 | 0 | return C_DVAR_E_INVALID_TYPE; |
251 | 0 | } |
252 | 0 |
|
253 | 0 | *typep = type; |
254 | 0 | return 0; |
255 | 0 |
|
256 | 0 | } Unexecuted instantiation: message.c:c_dvar_type_new_from_string Unexecuted instantiation: c-dvar.c:c_dvar_type_new_from_string Unexecuted instantiation: c-dvar-reader.c:c_dvar_type_new_from_string Unexecuted instantiation: c-dvar-type.c:c_dvar_type_new_from_string |
257 | | |
258 | | /** |
259 | | * c_dvar_type_freep() - free type information |
260 | | * @type: type information to free |
261 | | * |
262 | | * This is the cleanup-helper for c_dvar_type_free(). |
263 | | */ |
264 | 12.1k | static inline void c_dvar_type_freep(CDVarType **type) { |
265 | 12.1k | if (*type) |
266 | 0 | c_dvar_type_free(*type); |
267 | 12.1k | } Unexecuted instantiation: message.c:c_dvar_type_freep Unexecuted instantiation: c-dvar.c:c_dvar_type_freep Unexecuted instantiation: c-dvar-reader.c:c_dvar_type_freep c-dvar-type.c:c_dvar_type_freep Line | Count | Source | 264 | 12.1k | static inline void c_dvar_type_freep(CDVarType **type) { | 265 | 12.1k | if (*type) | 266 | 0 | c_dvar_type_free(*type); | 267 | 12.1k | } |
|
268 | | |
269 | | /** |
270 | | * c_dvar_freep() - free variant |
271 | | * @var: variant to free |
272 | | * |
273 | | * This is the cleanup-helper for c_dvar_free(). |
274 | | */ |
275 | 0 | static inline void c_dvar_freep(CDVar **var) { |
276 | 0 | if (*var) |
277 | 0 | c_dvar_free(*var); |
278 | 0 | } Unexecuted instantiation: message.c:c_dvar_freep Unexecuted instantiation: c-dvar.c:c_dvar_freep Unexecuted instantiation: c-dvar-reader.c:c_dvar_freep Unexecuted instantiation: c-dvar-type.c:c_dvar_freep |
279 | | |
280 | | /** |
281 | | * c_dvar_deinitp() - reset variant |
282 | | * @var: variant to reset |
283 | | * |
284 | | * This is the cleanup-helper for c_dvar_deinit(). |
285 | | */ |
286 | 0 | static inline void c_dvar_deinitp(CDVar **var) { |
287 | 0 | if (*var) |
288 | 0 | c_dvar_deinit(*var); |
289 | 0 | } Unexecuted instantiation: message.c:c_dvar_deinitp Unexecuted instantiation: c-dvar.c:c_dvar_deinitp Unexecuted instantiation: c-dvar-reader.c:c_dvar_deinitp Unexecuted instantiation: c-dvar-type.c:c_dvar_deinitp |
290 | | |
291 | | /** |
292 | | * c_dvar_read() - read data from variant |
293 | | * @var: variant to operate on |
294 | | * @format: format string |
295 | | * |
296 | | * This is the va_arg-based equivalent of c_dvar_vread(). See its documentation |
297 | | * for details. |
298 | | * |
299 | | * Return: 0 on success, negative error code on fatal errors, positive error |
300 | | * code on parser failure. |
301 | | */ |
302 | 154k | static inline int c_dvar_read(CDVar *var, const char *format, ...) { |
303 | 154k | va_list args; |
304 | 154k | int r; |
305 | | |
306 | 154k | va_start(args, format); |
307 | 154k | r = c_dvar_vread(var, format, args); |
308 | 154k | va_end(args); |
309 | 154k | return r; |
310 | 154k | } Line | Count | Source | 302 | 16.0k | static inline int c_dvar_read(CDVar *var, const char *format, ...) { | 303 | 16.0k | va_list args; | 304 | 16.0k | int r; | 305 | | | 306 | 16.0k | va_start(args, format); | 307 | 16.0k | r = c_dvar_vread(var, format, args); | 308 | | va_end(args); | 309 | 16.0k | return r; | 310 | 16.0k | } |
Unexecuted instantiation: c-dvar.c:c_dvar_read c-dvar-reader.c:c_dvar_read Line | Count | Source | 302 | 138k | static inline int c_dvar_read(CDVar *var, const char *format, ...) { | 303 | 138k | va_list args; | 304 | 138k | int r; | 305 | | | 306 | 138k | va_start(args, format); | 307 | 138k | r = c_dvar_vread(var, format, args); | 308 | | va_end(args); | 309 | 138k | return r; | 310 | 138k | } |
Unexecuted instantiation: c-dvar-type.c:c_dvar_read |
311 | | |
312 | | /** |
313 | | * c_dvar_skip() - skip over data from variant |
314 | | * @var: variant to operate on |
315 | | * @format: format string |
316 | | * |
317 | | * This is the va_arg-based equivalent of c_dvar_vskip(). See its documentation |
318 | | * for details. |
319 | | * |
320 | | * Return: 0 on success, negative error code on fatal errors, positive error |
321 | | * code on parser failure. |
322 | | */ |
323 | 10.6k | static inline int c_dvar_skip(CDVar *var, const char *format, ...) { |
324 | 10.6k | va_list args; |
325 | 10.6k | int r; |
326 | | |
327 | 10.6k | va_start(args, format); |
328 | 10.6k | r = c_dvar_vskip(var, format, args); |
329 | 10.6k | va_end(args); |
330 | 10.6k | return r; |
331 | 10.6k | } Line | Count | Source | 323 | 10.6k | static inline int c_dvar_skip(CDVar *var, const char *format, ...) { | 324 | 10.6k | va_list args; | 325 | 10.6k | int r; | 326 | | | 327 | 10.6k | va_start(args, format); | 328 | 10.6k | r = c_dvar_vskip(var, format, args); | 329 | | va_end(args); | 330 | 10.6k | return r; | 331 | 10.6k | } |
Unexecuted instantiation: c-dvar.c:c_dvar_skip Unexecuted instantiation: c-dvar-reader.c:c_dvar_skip Unexecuted instantiation: c-dvar-type.c:c_dvar_skip |
332 | | |
333 | | /** |
334 | | * c_dvar_write() - write data to variant |
335 | | * @var: variant to operate on |
336 | | * @format: format string |
337 | | * |
338 | | * This is the va_arg-based equivalent of c_dvar_vwrite(). See its |
339 | | * documentation for details. |
340 | | * |
341 | | * Return: 0 on success, negative error code on fatal errors, positive error |
342 | | * code on builder failure. |
343 | | */ |
344 | 0 | static inline int c_dvar_write(CDVar *var, const char *format, ...) { |
345 | 0 | va_list args; |
346 | 0 | int r; |
347 | 0 |
|
348 | 0 | va_start(args, format); |
349 | 0 | r = c_dvar_vwrite(var, format, args); |
350 | 0 | va_end(args); |
351 | 0 | return r; |
352 | 0 | } Unexecuted instantiation: message.c:c_dvar_write Unexecuted instantiation: c-dvar.c:c_dvar_write Unexecuted instantiation: c-dvar-reader.c:c_dvar_write Unexecuted instantiation: c-dvar-type.c:c_dvar_write |
353 | | |
354 | | #ifdef __cplusplus |
355 | | } |
356 | | #endif |