1 /* Simple Plugin API
2 *
3 * Copyright © 2018 Wim Taymans
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25 #ifndef SPA_POD_ITER_H
26 #define SPA_POD_ITER_H
27
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31
32 #include <errno.h>
33 #include <sys/types.h>
34
35 #include <spa/pod/pod.h>
36
37 struct spa_pod_frame {
38 struct spa_pod pod;
39 struct spa_pod_frame *parent;
40 uint32_t offset;
41 uint32_t flags;
42 };
43
spa_pod_is_inside(const void * pod,uint32_t size,const void * iter)44 static inline bool spa_pod_is_inside(const void *pod, uint32_t size, const void *iter)
45 {
46 return SPA_POD_BODY(iter) <= SPA_MEMBER(pod, size, void) &&
47 SPA_MEMBER(iter, SPA_POD_SIZE(iter), void) <= SPA_MEMBER(pod, size, void);
48 }
49
spa_pod_next(const void * iter)50 static inline void *spa_pod_next(const void *iter)
51 {
52 return SPA_MEMBER(iter, SPA_ROUND_UP_N(SPA_POD_SIZE(iter), 8), void);
53 }
54
spa_pod_prop_first(const struct spa_pod_object_body * body)55 static inline struct spa_pod_prop *spa_pod_prop_first(const struct spa_pod_object_body *body)
56 {
57 return SPA_MEMBER(body, sizeof(struct spa_pod_object_body), struct spa_pod_prop);
58 }
59
spa_pod_prop_is_inside(const struct spa_pod_object_body * body,uint32_t size,const struct spa_pod_prop * iter)60 static inline bool spa_pod_prop_is_inside(const struct spa_pod_object_body *body,
61 uint32_t size, const struct spa_pod_prop *iter)
62 {
63 return SPA_POD_CONTENTS(struct spa_pod_prop, iter) <= SPA_MEMBER(body, size, void) &&
64 SPA_MEMBER(iter, SPA_POD_PROP_SIZE(iter), void) <= SPA_MEMBER(body, size, void);
65 }
66
spa_pod_prop_next(const struct spa_pod_prop * iter)67 static inline struct spa_pod_prop *spa_pod_prop_next(const struct spa_pod_prop *iter)
68 {
69 return SPA_MEMBER(iter, SPA_ROUND_UP_N(SPA_POD_PROP_SIZE(iter), 8), struct spa_pod_prop);
70 }
71
spa_pod_control_first(const struct spa_pod_sequence_body * body)72 static inline struct spa_pod_control *spa_pod_control_first(const struct spa_pod_sequence_body *body)
73 {
74 return SPA_MEMBER(body, sizeof(struct spa_pod_sequence_body), struct spa_pod_control);
75 }
76
spa_pod_control_is_inside(const struct spa_pod_sequence_body * body,uint32_t size,const struct spa_pod_control * iter)77 static inline bool spa_pod_control_is_inside(const struct spa_pod_sequence_body *body,
78 uint32_t size, const struct spa_pod_control *iter)
79 {
80 return SPA_POD_CONTENTS(struct spa_pod_control, iter) <= SPA_MEMBER(body, size, void) &&
81 SPA_MEMBER(iter, SPA_POD_CONTROL_SIZE(iter), void) <= SPA_MEMBER(body, size, void);
82 }
83
spa_pod_control_next(const struct spa_pod_control * iter)84 static inline struct spa_pod_control *spa_pod_control_next(const struct spa_pod_control *iter)
85 {
86 return SPA_MEMBER(iter, SPA_ROUND_UP_N(SPA_POD_CONTROL_SIZE(iter), 8), struct spa_pod_control);
87 }
88
89 #define SPA_POD_ARRAY_BODY_FOREACH(body, _size, iter) \
90 for ((iter) = (__typeof__(iter))SPA_MEMBER((body), sizeof(struct spa_pod_array_body), void); \
91 (iter) < (__typeof__(iter))SPA_MEMBER((body), (_size), void); \
92 (iter) = (__typeof__(iter))SPA_MEMBER((iter), (body)->child.size, void))
93
94 #define SPA_POD_ARRAY_FOREACH(obj, iter) \
95 SPA_POD_ARRAY_BODY_FOREACH(&(obj)->body, SPA_POD_BODY_SIZE(obj), iter)
96
97 #define SPA_POD_CHOICE_BODY_FOREACH(body, _size, iter) \
98 for ((iter) = (__typeof__(iter))SPA_MEMBER((body), sizeof(struct spa_pod_choice_body), void); \
99 (iter) < (__typeof__(iter))SPA_MEMBER((body), (_size), void); \
100 (iter) = (__typeof__(iter))SPA_MEMBER((iter), (body)->child.size, void))
101
102 #define SPA_POD_CHOICE_FOREACH(obj, iter) \
103 SPA_POD_CHOICE_BODY_FOREACH(&(obj)->body, SPA_POD_BODY_SIZE(obj), iter)
104
105 #define SPA_POD_FOREACH(pod, size, iter) \
106 for ((iter) = (pod); \
107 spa_pod_is_inside(pod, size, iter); \
108 (iter) = (__typeof__(iter))spa_pod_next(iter))
109
110 #define SPA_POD_STRUCT_FOREACH(obj, iter) \
111 SPA_POD_FOREACH(SPA_POD_BODY(obj), SPA_POD_BODY_SIZE(obj), iter)
112
113 #define SPA_POD_OBJECT_BODY_FOREACH(body, size, iter) \
114 for ((iter) = spa_pod_prop_first(body); \
115 spa_pod_prop_is_inside(body, size, iter); \
116 (iter) = spa_pod_prop_next(iter))
117
118 #define SPA_POD_OBJECT_FOREACH(obj, iter) \
119 SPA_POD_OBJECT_BODY_FOREACH(&(obj)->body, SPA_POD_BODY_SIZE(obj), iter)
120
121 #define SPA_POD_SEQUENCE_BODY_FOREACH(body, size, iter) \
122 for ((iter) = spa_pod_control_first(body); \
123 spa_pod_control_is_inside(body, size, iter); \
124 (iter) = spa_pod_control_next(iter))
125
126 #define SPA_POD_SEQUENCE_FOREACH(seq, iter) \
127 SPA_POD_SEQUENCE_BODY_FOREACH(&(seq)->body, SPA_POD_BODY_SIZE(seq), iter)
128
129
spa_pod_from_data(void * data,size_t maxsize,off_t offset,size_t size)130 static inline void *spa_pod_from_data(void *data, size_t maxsize, off_t offset, size_t size)
131 {
132 void *pod;
133 if (size < sizeof(struct spa_pod) || offset + size > maxsize)
134 return NULL;
135 pod = SPA_MEMBER(data, offset, void);
136 if (SPA_POD_SIZE(pod) > size)
137 return NULL;
138 return pod;
139 }
140
spa_pod_is_none(const struct spa_pod * pod)141 static inline int spa_pod_is_none(const struct spa_pod *pod)
142 {
143 return (SPA_POD_TYPE(pod) == SPA_TYPE_None);
144 }
145
spa_pod_is_bool(const struct spa_pod * pod)146 static inline int spa_pod_is_bool(const struct spa_pod *pod)
147 {
148 return (SPA_POD_TYPE(pod) == SPA_TYPE_Bool && SPA_POD_BODY_SIZE(pod) >= sizeof(int32_t));
149 }
150
spa_pod_get_bool(const struct spa_pod * pod,bool * value)151 static inline int spa_pod_get_bool(const struct spa_pod *pod, bool *value)
152 {
153 if (!spa_pod_is_bool(pod))
154 return -EINVAL;
155 *value = !!SPA_POD_VALUE(struct spa_pod_bool, pod);
156 return 0;
157 }
158
spa_pod_is_id(const struct spa_pod * pod)159 static inline int spa_pod_is_id(const struct spa_pod *pod)
160 {
161 return (SPA_POD_TYPE(pod) == SPA_TYPE_Id && SPA_POD_BODY_SIZE(pod) >= sizeof(uint32_t));
162 }
163
spa_pod_get_id(const struct spa_pod * pod,uint32_t * value)164 static inline int spa_pod_get_id(const struct spa_pod *pod, uint32_t *value)
165 {
166 if (!spa_pod_is_id(pod))
167 return -EINVAL;
168 *value = SPA_POD_VALUE(struct spa_pod_id, pod);
169 return 0;
170 }
171
spa_pod_is_int(const struct spa_pod * pod)172 static inline int spa_pod_is_int(const struct spa_pod *pod)
173 {
174 return (SPA_POD_TYPE(pod) == SPA_TYPE_Int && SPA_POD_BODY_SIZE(pod) >= sizeof(int32_t));
175 }
176
spa_pod_get_int(const struct spa_pod * pod,int32_t * value)177 static inline int spa_pod_get_int(const struct spa_pod *pod, int32_t *value)
178 {
179 if (!spa_pod_is_int(pod))
180 return -EINVAL;
181 *value = SPA_POD_VALUE(struct spa_pod_int, pod);
182 return 0;
183 }
184
spa_pod_is_long(const struct spa_pod * pod)185 static inline int spa_pod_is_long(const struct spa_pod *pod)
186 {
187 return (SPA_POD_TYPE(pod) == SPA_TYPE_Long && SPA_POD_BODY_SIZE(pod) >= sizeof(int64_t));
188 }
189
spa_pod_get_long(const struct spa_pod * pod,int64_t * value)190 static inline int spa_pod_get_long(const struct spa_pod *pod, int64_t *value)
191 {
192 if (!spa_pod_is_long(pod))
193 return -EINVAL;
194 *value = SPA_POD_VALUE(struct spa_pod_long, pod);
195 return 0;
196 }
197
spa_pod_is_float(const struct spa_pod * pod)198 static inline int spa_pod_is_float(const struct spa_pod *pod)
199 {
200 return (SPA_POD_TYPE(pod) == SPA_TYPE_Float && SPA_POD_BODY_SIZE(pod) >= sizeof(float));
201 }
202
spa_pod_get_float(const struct spa_pod * pod,float * value)203 static inline int spa_pod_get_float(const struct spa_pod *pod, float *value)
204 {
205 if (!spa_pod_is_float(pod))
206 return -EINVAL;
207 *value = SPA_POD_VALUE(struct spa_pod_float, pod);
208 return 0;
209 }
210
spa_pod_is_double(const struct spa_pod * pod)211 static inline int spa_pod_is_double(const struct spa_pod *pod)
212 {
213 return (SPA_POD_TYPE(pod) == SPA_TYPE_Double && SPA_POD_BODY_SIZE(pod) >= sizeof(double));
214 }
215
spa_pod_get_double(const struct spa_pod * pod,double * value)216 static inline int spa_pod_get_double(const struct spa_pod *pod, double *value)
217 {
218 if (!spa_pod_is_double(pod))
219 return -EINVAL;
220 *value = SPA_POD_VALUE(struct spa_pod_double, pod);
221 return 0;
222 }
223
spa_pod_is_string(const struct spa_pod * pod)224 static inline int spa_pod_is_string(const struct spa_pod *pod)
225 {
226 const char *s = (const char *)SPA_POD_CONTENTS(struct spa_pod_string, pod);
227 return (SPA_POD_TYPE(pod) == SPA_TYPE_String &&
228 SPA_POD_BODY_SIZE(pod) > 0 &&
229 s[SPA_POD_BODY_SIZE(pod)-1] == '\0');
230 }
231
spa_pod_get_string(const struct spa_pod * pod,const char ** value)232 static inline int spa_pod_get_string(const struct spa_pod *pod, const char **value)
233 {
234 if (!spa_pod_is_string(pod))
235 return -EINVAL;
236 *value = (const char *)SPA_POD_CONTENTS(struct spa_pod_string, pod);
237 return 0;
238 }
239
spa_pod_copy_string(const struct spa_pod * pod,size_t maxlen,char * dest)240 static inline int spa_pod_copy_string(const struct spa_pod *pod, size_t maxlen, char *dest)
241 {
242 const char *s = (const char *)SPA_POD_CONTENTS(struct spa_pod_string, pod);
243 if (!spa_pod_is_string(pod) || maxlen < 1)
244 return -EINVAL;
245 strncpy(dest, s, maxlen-1);
246 dest[maxlen-1]= '\0';
247 return 0;
248 }
249
spa_pod_is_bytes(const struct spa_pod * pod)250 static inline int spa_pod_is_bytes(const struct spa_pod *pod)
251 {
252 return SPA_POD_TYPE(pod) == SPA_TYPE_Bytes;
253 }
254
spa_pod_get_bytes(const struct spa_pod * pod,const void ** value,uint32_t * len)255 static inline int spa_pod_get_bytes(const struct spa_pod *pod, const void **value, uint32_t *len)
256 {
257 if (!spa_pod_is_bytes(pod))
258 return -EINVAL;
259 *value = (const void *)SPA_POD_CONTENTS(struct spa_pod_bytes, pod);
260 *len = SPA_POD_BODY_SIZE(pod);
261 return 0;
262 }
263
spa_pod_is_pointer(const struct spa_pod * pod)264 static inline int spa_pod_is_pointer(const struct spa_pod *pod)
265 {
266 return (SPA_POD_TYPE(pod) == SPA_TYPE_Pointer &&
267 SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_pod_pointer_body));
268 }
269
spa_pod_get_pointer(const struct spa_pod * pod,uint32_t * type,const void ** value)270 static inline int spa_pod_get_pointer(const struct spa_pod *pod, uint32_t *type, const void **value)
271 {
272 if (!spa_pod_is_pointer(pod))
273 return -EINVAL;
274 *type = ((struct spa_pod_pointer*)pod)->body.type;
275 *value = ((struct spa_pod_pointer*)pod)->body.value;
276 return 0;
277 }
278
spa_pod_is_fd(const struct spa_pod * pod)279 static inline int spa_pod_is_fd(const struct spa_pod *pod)
280 {
281 return (SPA_POD_TYPE(pod) == SPA_TYPE_Fd &&
282 SPA_POD_BODY_SIZE(pod) >= sizeof(int64_t));
283 }
284
spa_pod_get_fd(const struct spa_pod * pod,int64_t * value)285 static inline int spa_pod_get_fd(const struct spa_pod *pod, int64_t *value)
286 {
287 if (!spa_pod_is_fd(pod))
288 return -EINVAL;
289 *value = SPA_POD_VALUE(struct spa_pod_fd, pod);
290 return 0;
291 }
292
spa_pod_is_rectangle(const struct spa_pod * pod)293 static inline int spa_pod_is_rectangle(const struct spa_pod *pod)
294 {
295 return (SPA_POD_TYPE(pod) == SPA_TYPE_Rectangle &&
296 SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_rectangle));
297 }
298
spa_pod_get_rectangle(const struct spa_pod * pod,struct spa_rectangle * value)299 static inline int spa_pod_get_rectangle(const struct spa_pod *pod, struct spa_rectangle *value)
300 {
301 if (!spa_pod_is_rectangle(pod))
302 return -EINVAL;
303 *value = SPA_POD_VALUE(struct spa_pod_rectangle, pod);
304 return 0;
305 }
306
spa_pod_is_fraction(const struct spa_pod * pod)307 static inline int spa_pod_is_fraction(const struct spa_pod *pod)
308 {
309 return (SPA_POD_TYPE(pod) == SPA_TYPE_Fraction &&
310 SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_fraction));
311 }
312
spa_pod_get_fraction(const struct spa_pod * pod,struct spa_fraction * value)313 static inline int spa_pod_get_fraction(const struct spa_pod *pod, struct spa_fraction *value)
314 {
315 spa_return_val_if_fail(spa_pod_is_fraction(pod), -EINVAL);
316 *value = SPA_POD_VALUE(struct spa_pod_fraction, pod);
317 return 0;
318 }
319
spa_pod_is_bitmap(const struct spa_pod * pod)320 static inline int spa_pod_is_bitmap(const struct spa_pod *pod)
321 {
322 return (SPA_POD_TYPE(pod) == SPA_TYPE_Bitmap &&
323 SPA_POD_BODY_SIZE(pod) >= sizeof(uint8_t));
324 }
325
spa_pod_is_array(const struct spa_pod * pod)326 static inline int spa_pod_is_array(const struct spa_pod *pod)
327 {
328 return (SPA_POD_TYPE(pod) == SPA_TYPE_Array &&
329 SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_pod_array_body));
330 }
331
spa_pod_get_array(const struct spa_pod * pod,uint32_t * n_values)332 static inline void *spa_pod_get_array(const struct spa_pod *pod, uint32_t *n_values)
333 {
334 spa_return_val_if_fail(spa_pod_is_array(pod), NULL);
335 *n_values = SPA_POD_ARRAY_N_VALUES(pod);
336 return SPA_POD_ARRAY_VALUES(pod);
337 }
338
spa_pod_copy_array(const struct spa_pod * pod,uint32_t type,void * values,uint32_t max_values)339 static inline uint32_t spa_pod_copy_array(const struct spa_pod *pod, uint32_t type,
340 void *values, uint32_t max_values)
341 {
342 uint32_t n_values;
343 void *v = spa_pod_get_array(pod, &n_values);
344 if (v == NULL || max_values == 0 || SPA_POD_ARRAY_VALUE_TYPE(pod) != type)
345 return 0;
346 n_values = SPA_MIN(n_values, max_values);
347 memcpy(values, v, SPA_POD_ARRAY_VALUE_SIZE(pod) * n_values);
348 return n_values;
349 }
350
spa_pod_is_choice(const struct spa_pod * pod)351 static inline int spa_pod_is_choice(const struct spa_pod *pod)
352 {
353 return (SPA_POD_TYPE(pod) == SPA_TYPE_Choice &&
354 SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_pod_choice_body));
355 }
356
spa_pod_get_values(const struct spa_pod * pod,uint32_t * n_vals,uint32_t * choice)357 static inline struct spa_pod *spa_pod_get_values(const struct spa_pod *pod, uint32_t *n_vals, uint32_t *choice)
358 {
359 if (pod->type == SPA_TYPE_Choice) {
360 *choice = SPA_POD_CHOICE_TYPE(pod);
361 *n_vals = *choice == SPA_CHOICE_None ? 1 : SPA_POD_CHOICE_N_VALUES(pod);
362 return (struct spa_pod*)SPA_POD_CHOICE_CHILD(pod);
363 } else {
364 *n_vals = 1;
365 *choice = SPA_CHOICE_None;
366 return (struct spa_pod*)pod;
367 }
368 }
369
spa_pod_is_struct(const struct spa_pod * pod)370 static inline int spa_pod_is_struct(const struct spa_pod *pod)
371 {
372 return (SPA_POD_TYPE(pod) == SPA_TYPE_Struct);
373 }
374
spa_pod_is_object(const struct spa_pod * pod)375 static inline int spa_pod_is_object(const struct spa_pod *pod)
376 {
377 return (SPA_POD_TYPE(pod) == SPA_TYPE_Object &&
378 SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_pod_object_body));
379 }
380
spa_pod_is_object_type(const struct spa_pod * pod,uint32_t type)381 static inline bool spa_pod_is_object_type(const struct spa_pod *pod, uint32_t type)
382 {
383 return (pod && spa_pod_is_object(pod) && SPA_POD_OBJECT_TYPE(pod) == type);
384 }
385
spa_pod_is_object_id(const struct spa_pod * pod,uint32_t id)386 static inline bool spa_pod_is_object_id(const struct spa_pod *pod, uint32_t id)
387 {
388 return (pod && spa_pod_is_object(pod) && SPA_POD_OBJECT_ID(pod) == id);
389 }
390
spa_pod_is_sequence(const struct spa_pod * pod)391 static inline int spa_pod_is_sequence(const struct spa_pod *pod)
392 {
393 return (SPA_POD_TYPE(pod) == SPA_TYPE_Sequence &&
394 SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_pod_sequence_body));
395 }
396
spa_pod_object_find_prop(const struct spa_pod_object * pod,const struct spa_pod_prop * start,uint32_t key)397 static inline const struct spa_pod_prop *spa_pod_object_find_prop(const struct spa_pod_object *pod,
398 const struct spa_pod_prop *start, uint32_t key)
399 {
400 const struct spa_pod_prop *first, *res;
401
402 first = spa_pod_prop_first(&pod->body);
403 start = start ? spa_pod_prop_next(start) : first;
404
405 for (res = start; spa_pod_prop_is_inside(&pod->body, pod->pod.size, res);
406 res = spa_pod_prop_next(res)) {
407 if (res->key == key)
408 return res;
409 }
410 for (res = first; res != start; res = spa_pod_prop_next(res)) {
411 if (res->key == key)
412 return res;
413 }
414 return NULL;
415 }
416
spa_pod_find_prop(const struct spa_pod * pod,const struct spa_pod_prop * start,uint32_t key)417 static inline const struct spa_pod_prop *spa_pod_find_prop(const struct spa_pod *pod,
418 const struct spa_pod_prop *start, uint32_t key)
419 {
420 if (!spa_pod_is_object(pod))
421 return NULL;
422 return spa_pod_object_find_prop((const struct spa_pod_object *)pod, start, key);
423 }
424
spa_pod_object_fixate(struct spa_pod_object * pod)425 static inline int spa_pod_object_fixate(struct spa_pod_object *pod)
426 {
427 struct spa_pod_prop *res;
428 SPA_POD_OBJECT_FOREACH(pod, res) {
429 if (res->value.type == SPA_TYPE_Choice)
430 ((struct spa_pod_choice*)&res->value)->body.type = SPA_CHOICE_None;
431 }
432 return 0;
433 }
434
spa_pod_fixate(struct spa_pod * pod)435 static inline int spa_pod_fixate(struct spa_pod *pod)
436 {
437 if (!spa_pod_is_object(pod))
438 return -EINVAL;
439 return spa_pod_object_fixate((struct spa_pod_object *)pod);
440 }
441
442 #ifdef __cplusplus
443 } /* extern "C" */
444 #endif
445
446 #endif /* SPA_POD_H */
447