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