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_BUILDER_H
26 #define SPA_POD_BUILDER_H
27 
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31 
32 #include <stdarg.h>
33 
34 #include <spa/utils/hook.h>
35 #include <spa/pod/iter.h>
36 #include <spa/pod/vararg.h>
37 
38 struct spa_pod_builder_state {
39 	uint32_t offset;
40 #define SPA_POD_BUILDER_FLAG_BODY	(1<<0)
41 #define SPA_POD_BUILDER_FLAG_FIRST	(1<<1)
42 	uint32_t flags;
43 	struct spa_pod_frame *frame;
44 };
45 
46 struct spa_pod_builder;
47 
48 struct spa_pod_builder_callbacks {
49 #define SPA_VERSION_POD_BUILDER_CALLBACKS 0
50 	uint32_t version;
51 
52 	int (*overflow) (void *data, uint32_t size);
53 };
54 
55 struct spa_pod_builder {
56 	void *data;
57 	uint32_t size;
58 	uint32_t _padding;
59 	struct spa_pod_builder_state state;
60 	struct spa_callbacks callbacks;
61 };
62 
63 #define SPA_POD_BUILDER_INIT(buffer,size)  (struct spa_pod_builder){ buffer, size, }
64 
65 static inline void
spa_pod_builder_get_state(struct spa_pod_builder * builder,struct spa_pod_builder_state * state)66 spa_pod_builder_get_state(struct spa_pod_builder *builder, struct spa_pod_builder_state *state)
67 {
68 	*state = builder->state;
69 }
70 
71 static inline void
spa_pod_builder_set_callbacks(struct spa_pod_builder * builder,const struct spa_pod_builder_callbacks * callbacks,void * data)72 spa_pod_builder_set_callbacks(struct spa_pod_builder *builder,
73 		const struct spa_pod_builder_callbacks *callbacks, void *data)
74 {
75 	builder->callbacks = SPA_CALLBACKS_INIT(callbacks, data);
76 }
77 
78 static inline void
spa_pod_builder_reset(struct spa_pod_builder * builder,struct spa_pod_builder_state * state)79 spa_pod_builder_reset(struct spa_pod_builder *builder, struct spa_pod_builder_state *state)
80 {
81 	struct spa_pod_frame *f;
82 	uint32_t size = builder->state.offset - state->offset;
83 	builder->state = *state;
84 	for (f = builder->state.frame; f ; f = f->parent)
85 		f->pod.size -= size;
86 }
87 
spa_pod_builder_init(struct spa_pod_builder * builder,void * data,uint32_t size)88 static inline void spa_pod_builder_init(struct spa_pod_builder *builder, void *data, uint32_t size)
89 {
90 	*builder = SPA_POD_BUILDER_INIT(data, size);
91 }
92 
93 static inline struct spa_pod *
spa_pod_builder_deref(struct spa_pod_builder * builder,uint32_t offset)94 spa_pod_builder_deref(struct spa_pod_builder *builder, uint32_t offset)
95 {
96 	uint32_t size = builder->size;
97 	if (offset + 8 <= size) {
98 		struct spa_pod *pod = SPA_MEMBER(builder->data, offset, struct spa_pod);
99 		if (offset + SPA_POD_SIZE(pod) <= size)
100 			return pod;
101 	}
102 	return NULL;
103 }
104 
105 static inline struct spa_pod *
spa_pod_builder_frame(struct spa_pod_builder * builder,struct spa_pod_frame * frame)106 spa_pod_builder_frame(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
107 {
108 	if (frame->offset + SPA_POD_SIZE(&frame->pod) <= builder->size)
109 		return SPA_MEMBER(builder->data, frame->offset, struct spa_pod);
110 	return NULL;
111 }
112 
113 static inline void
spa_pod_builder_push(struct spa_pod_builder * builder,struct spa_pod_frame * frame,const struct spa_pod * pod,uint32_t offset)114 spa_pod_builder_push(struct spa_pod_builder *builder,
115 		     struct spa_pod_frame *frame,
116 		     const struct spa_pod *pod,
117 		     uint32_t offset)
118 {
119 	frame->pod = *pod;
120 	frame->offset = offset;
121 	frame->parent = builder->state.frame;
122 	frame->flags = builder->state.flags;
123 	builder->state.frame = frame;
124 
125 	if (frame->pod.type == SPA_TYPE_Array || frame->pod.type == SPA_TYPE_Choice)
126 		builder->state.flags = SPA_POD_BUILDER_FLAG_FIRST | SPA_POD_BUILDER_FLAG_BODY;
127 }
128 
spa_pod_builder_raw(struct spa_pod_builder * builder,const void * data,uint32_t size)129 static inline int spa_pod_builder_raw(struct spa_pod_builder *builder, const void *data, uint32_t size)
130 {
131 	int res = 0;
132 	struct spa_pod_frame *f;
133 	uint32_t offset = builder->state.offset;
134 
135 	if (offset + size > builder->size) {
136 		res = -ENOSPC;
137 		spa_callbacks_call_res(&builder->callbacks, struct spa_pod_builder_callbacks, res,
138 				overflow, 0, offset + size);
139 	}
140 	if (res == 0 && data)
141 		memcpy(SPA_MEMBER(builder->data, offset, void), data, size);
142 
143 	builder->state.offset += size;
144 
145 	for (f = builder->state.frame; f ; f = f->parent)
146 		f->pod.size += size;
147 
148 	return res;
149 }
150 
spa_pod_builder_pad(struct spa_pod_builder * builder,uint32_t size)151 static inline int spa_pod_builder_pad(struct spa_pod_builder *builder, uint32_t size)
152 {
153 	uint64_t zeroes = 0;
154 	size = SPA_ROUND_UP_N(size, 8) - size;
155 	return size ? spa_pod_builder_raw(builder, &zeroes, size) : 0;
156 }
157 
158 static inline int
spa_pod_builder_raw_padded(struct spa_pod_builder * builder,const void * data,uint32_t size)159 spa_pod_builder_raw_padded(struct spa_pod_builder *builder, const void *data, uint32_t size)
160 {
161 	int r, res = spa_pod_builder_raw(builder, data, size);
162 	if ((r = spa_pod_builder_pad(builder, size)) < 0)
163 		res = r;
164 	return res;
165 }
166 
spa_pod_builder_pop(struct spa_pod_builder * builder,struct spa_pod_frame * frame)167 static inline void *spa_pod_builder_pop(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
168 {
169 	struct spa_pod *pod;
170 
171 	if ((pod = (struct spa_pod*)spa_pod_builder_frame(builder, frame)) != NULL)
172 		*pod = frame->pod;
173 
174 	builder->state.frame = frame->parent;
175 	builder->state.flags = frame->flags;
176 	spa_pod_builder_pad(builder, builder->state.offset);
177 	return pod;
178 }
179 
180 static inline int
spa_pod_builder_primitive(struct spa_pod_builder * builder,const struct spa_pod * p)181 spa_pod_builder_primitive(struct spa_pod_builder *builder, const struct spa_pod *p)
182 {
183 	const void *data;
184 	uint32_t size;
185 	int r, res;
186 
187 	if (builder->state.flags == SPA_POD_BUILDER_FLAG_BODY) {
188 		data = SPA_POD_BODY_CONST(p);
189 		size = SPA_POD_BODY_SIZE(p);
190 	} else {
191 		data = p;
192 		size = SPA_POD_SIZE(p);
193 		SPA_FLAG_CLEAR(builder->state.flags, SPA_POD_BUILDER_FLAG_FIRST);
194 	}
195 	res = spa_pod_builder_raw(builder, data, size);
196 	if (builder->state.flags != SPA_POD_BUILDER_FLAG_BODY)
197 		if ((r = spa_pod_builder_pad(builder, size)) < 0)
198 			res = r;
199 	return res;
200 }
201 
202 #define SPA_POD_INIT(size,type) (struct spa_pod) { size, type }
203 
204 #define SPA_POD_INIT_None() SPA_POD_INIT(0, SPA_TYPE_None)
205 
spa_pod_builder_none(struct spa_pod_builder * builder)206 static inline int spa_pod_builder_none(struct spa_pod_builder *builder)
207 {
208 	const struct spa_pod p = SPA_POD_INIT_None();
209 	return spa_pod_builder_primitive(builder, &p);
210 }
211 
212 #define SPA_POD_INIT_Bool(val) (struct spa_pod_bool){ { sizeof(uint32_t), SPA_TYPE_Bool }, val ? 1 : 0, 0 }
213 
spa_pod_builder_bool(struct spa_pod_builder * builder,bool val)214 static inline int spa_pod_builder_bool(struct spa_pod_builder *builder, bool val)
215 {
216 	const struct spa_pod_bool p = SPA_POD_INIT_Bool(val);
217 	return spa_pod_builder_primitive(builder, &p.pod);
218 }
219 
220 #define SPA_POD_INIT_Id(val) (struct spa_pod_id){ { sizeof(uint32_t), SPA_TYPE_Id }, (uint32_t)val, 0 }
221 
spa_pod_builder_id(struct spa_pod_builder * builder,uint32_t val)222 static inline int spa_pod_builder_id(struct spa_pod_builder *builder, uint32_t val)
223 {
224 	const struct spa_pod_id p = SPA_POD_INIT_Id(val);
225 	return spa_pod_builder_primitive(builder, &p.pod);
226 }
227 
228 #define SPA_POD_INIT_Int(val) (struct spa_pod_int){ { sizeof(int32_t), SPA_TYPE_Int }, (int32_t)val, 0 }
229 
spa_pod_builder_int(struct spa_pod_builder * builder,int32_t val)230 static inline int spa_pod_builder_int(struct spa_pod_builder *builder, int32_t val)
231 {
232 	const struct spa_pod_int p = SPA_POD_INIT_Int(val);
233 	return spa_pod_builder_primitive(builder, &p.pod);
234 }
235 
236 #define SPA_POD_INIT_Long(val) (struct spa_pod_long){ { sizeof(int64_t), SPA_TYPE_Long }, (int64_t)val }
237 
spa_pod_builder_long(struct spa_pod_builder * builder,int64_t val)238 static inline int spa_pod_builder_long(struct spa_pod_builder *builder, int64_t val)
239 {
240 	const struct spa_pod_long p = SPA_POD_INIT_Long(val);
241 	return spa_pod_builder_primitive(builder, &p.pod);
242 }
243 
244 #define SPA_POD_INIT_Float(val) (struct spa_pod_float){ { sizeof(float), SPA_TYPE_Float }, val }
245 
spa_pod_builder_float(struct spa_pod_builder * builder,float val)246 static inline int spa_pod_builder_float(struct spa_pod_builder *builder, float val)
247 {
248 	const struct spa_pod_float p = SPA_POD_INIT_Float(val);
249 	return spa_pod_builder_primitive(builder, &p.pod);
250 }
251 
252 #define SPA_POD_INIT_Double(val) (struct spa_pod_double){ { sizeof(double), SPA_TYPE_Double }, val }
253 
spa_pod_builder_double(struct spa_pod_builder * builder,double val)254 static inline int spa_pod_builder_double(struct spa_pod_builder *builder, double val)
255 {
256 	const struct spa_pod_double p = SPA_POD_INIT_Double(val);
257 	return spa_pod_builder_primitive(builder, &p.pod);
258 }
259 
260 #define SPA_POD_INIT_String(len) (struct spa_pod_string){ { len, SPA_TYPE_String } }
261 
262 static inline int
spa_pod_builder_write_string(struct spa_pod_builder * builder,const char * str,uint32_t len)263 spa_pod_builder_write_string(struct spa_pod_builder *builder, const char *str, uint32_t len)
264 {
265 	int r, res;
266 	res = spa_pod_builder_raw(builder, str, len);
267 	if ((r = spa_pod_builder_raw(builder, "", 1)) < 0)
268 		res = r;
269 	if ((r = spa_pod_builder_pad(builder, builder->state.offset)) < 0)
270 		res = r;
271 	return res;
272 }
273 
274 static inline int
spa_pod_builder_string_len(struct spa_pod_builder * builder,const char * str,uint32_t len)275 spa_pod_builder_string_len(struct spa_pod_builder *builder, const char *str, uint32_t len)
276 {
277 	const struct spa_pod_string p = SPA_POD_INIT_String(len+1);
278 	int r, res = spa_pod_builder_raw(builder, &p, sizeof(p));
279 	if ((r = spa_pod_builder_write_string(builder, str, len)) < 0)
280 		res = r;
281 	return res;
282 }
283 
spa_pod_builder_string(struct spa_pod_builder * builder,const char * str)284 static inline int spa_pod_builder_string(struct spa_pod_builder *builder, const char *str)
285 {
286 	uint32_t len = str ? strlen(str) : 0;
287 	return spa_pod_builder_string_len(builder, str ? str : "", len);
288 }
289 
290 #define SPA_POD_INIT_Bytes(len) (struct spa_pod_bytes){ { len, SPA_TYPE_Bytes } }
291 
292 static inline int
spa_pod_builder_bytes(struct spa_pod_builder * builder,const void * bytes,uint32_t len)293 spa_pod_builder_bytes(struct spa_pod_builder *builder, const void *bytes, uint32_t len)
294 {
295 	const struct spa_pod_bytes p = SPA_POD_INIT_Bytes(len);
296 	int r, res = spa_pod_builder_raw(builder, &p, sizeof(p));
297 	if ((r = spa_pod_builder_raw_padded(builder, bytes, len)) < 0)
298 		res = r;
299 	return res;
300 }
301 static inline void *
spa_pod_builder_reserve_bytes(struct spa_pod_builder * builder,uint32_t len)302 spa_pod_builder_reserve_bytes(struct spa_pod_builder *builder, uint32_t len)
303 {
304 	uint32_t offset = builder->state.offset;
305 	if (spa_pod_builder_bytes(builder, NULL, len) < 0)
306 		return NULL;
307 	return SPA_POD_BODY(spa_pod_builder_deref(builder, offset));
308 }
309 
310 #define SPA_POD_INIT_Pointer(type,value) (struct spa_pod_pointer){ { sizeof(struct spa_pod_pointer_body), SPA_TYPE_Pointer }, { type, 0, value } }
311 
312 static inline int
spa_pod_builder_pointer(struct spa_pod_builder * builder,uint32_t type,const void * val)313 spa_pod_builder_pointer(struct spa_pod_builder *builder, uint32_t type, const void *val)
314 {
315 	const struct spa_pod_pointer p = SPA_POD_INIT_Pointer(type, val);
316 	return spa_pod_builder_primitive(builder, &p.pod);
317 }
318 
319 #define SPA_POD_INIT_Fd(fd) (struct spa_pod_fd){ { sizeof(int64_t), SPA_TYPE_Fd }, fd }
320 
spa_pod_builder_fd(struct spa_pod_builder * builder,int64_t fd)321 static inline int spa_pod_builder_fd(struct spa_pod_builder *builder, int64_t fd)
322 {
323 	const struct spa_pod_fd p = SPA_POD_INIT_Fd(fd);
324 	return spa_pod_builder_primitive(builder, &p.pod);
325 }
326 
327 #define SPA_POD_INIT_Rectangle(val) (struct spa_pod_rectangle){ { sizeof(struct spa_rectangle), SPA_TYPE_Rectangle }, val }
328 
329 static inline int
spa_pod_builder_rectangle(struct spa_pod_builder * builder,uint32_t width,uint32_t height)330 spa_pod_builder_rectangle(struct spa_pod_builder *builder, uint32_t width, uint32_t height)
331 {
332 	const struct spa_pod_rectangle p = SPA_POD_INIT_Rectangle(SPA_RECTANGLE(width, height));
333 	return spa_pod_builder_primitive(builder, &p.pod);
334 }
335 
336 #define SPA_POD_INIT_Fraction(val) (struct spa_pod_fraction){ { sizeof(struct spa_fraction), SPA_TYPE_Fraction }, val }
337 
338 static inline int
spa_pod_builder_fraction(struct spa_pod_builder * builder,uint32_t num,uint32_t denom)339 spa_pod_builder_fraction(struct spa_pod_builder *builder, uint32_t num, uint32_t denom)
340 {
341 	const struct spa_pod_fraction p = SPA_POD_INIT_Fraction(SPA_FRACTION(num, denom));
342 	return spa_pod_builder_primitive(builder, &p.pod);
343 }
344 
345 static inline int
spa_pod_builder_push_array(struct spa_pod_builder * builder,struct spa_pod_frame * frame)346 spa_pod_builder_push_array(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
347 {
348 	const struct spa_pod_array p =
349 	    { {sizeof(struct spa_pod_array_body) - sizeof(struct spa_pod), SPA_TYPE_Array},
350 	    {{0, 0}} };
351 	uint32_t offset = builder->state.offset;
352 	int res = spa_pod_builder_raw(builder, &p, sizeof(p) - sizeof(struct spa_pod));
353 	spa_pod_builder_push(builder, frame, &p.pod, offset);
354 	return res;
355 }
356 
357 static inline int
spa_pod_builder_array(struct spa_pod_builder * builder,uint32_t child_size,uint32_t child_type,uint32_t n_elems,const void * elems)358 spa_pod_builder_array(struct spa_pod_builder *builder,
359 		      uint32_t child_size, uint32_t child_type, uint32_t n_elems, const void *elems)
360 {
361 	const struct spa_pod_array p = {
362 		{(uint32_t)(sizeof(struct spa_pod_array_body) + n_elems * child_size), SPA_TYPE_Array},
363 		{{child_size, child_type}}
364 	};
365 	int r, res = spa_pod_builder_raw(builder, &p, sizeof(p));
366 	if ((r = spa_pod_builder_raw_padded(builder, elems, child_size * n_elems)) < 0)
367 		res = r;
368 	return res;
369 }
370 
371 #define SPA_POD_INIT_CHOICE_BODY(type, flags, child_size, child_type)				\
372 	(struct spa_pod_choice_body) { type, flags, { child_size, child_type }}
373 
374 #define SPA_POD_INIT_Choice(type, ctype, child_type, n_vals, ...)				\
375 	(struct { struct spa_pod_choice choice; ctype vals[n_vals];})				\
376 	{ { { n_vals * sizeof(ctype) + sizeof(struct spa_pod_choice_body), SPA_TYPE_Choice },	\
377 		{ type, 0, { sizeof(ctype), child_type } } }, { __VA_ARGS__ } }
378 
379 static inline int
spa_pod_builder_push_choice(struct spa_pod_builder * builder,struct spa_pod_frame * frame,uint32_t type,uint32_t flags)380 spa_pod_builder_push_choice(struct spa_pod_builder *builder, struct spa_pod_frame *frame,
381 		uint32_t type, uint32_t flags)
382 {
383 	const struct spa_pod_choice p =
384 	    { {sizeof(struct spa_pod_choice_body) - sizeof(struct spa_pod), SPA_TYPE_Choice},
385 	    { type, flags, {0, 0}} };
386 	uint32_t offset = builder->state.offset;
387 	int res = spa_pod_builder_raw(builder, &p, sizeof(p) - sizeof(struct spa_pod));
388 	spa_pod_builder_push(builder, frame, &p.pod, offset);
389 	return res;
390 }
391 
392 #define SPA_POD_INIT_Struct(size) (struct spa_pod_struct){ { size, SPA_TYPE_Struct } }
393 
394 static inline int
spa_pod_builder_push_struct(struct spa_pod_builder * builder,struct spa_pod_frame * frame)395 spa_pod_builder_push_struct(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
396 {
397 	const struct spa_pod_struct p = SPA_POD_INIT_Struct(0);
398 	uint32_t offset = builder->state.offset;
399 	int res = spa_pod_builder_raw(builder, &p, sizeof(p));
400 	spa_pod_builder_push(builder, frame, &p.pod, offset);
401 	return res;
402 }
403 
404 #define SPA_POD_INIT_Object(size,type,id,...)	(struct spa_pod_object){ { size, SPA_TYPE_Object }, { type, id }, ##__VA_ARGS__ }
405 
406 static inline int
spa_pod_builder_push_object(struct spa_pod_builder * builder,struct spa_pod_frame * frame,uint32_t type,uint32_t id)407 spa_pod_builder_push_object(struct spa_pod_builder *builder, struct spa_pod_frame *frame,
408 		uint32_t type, uint32_t id)
409 {
410 	const struct spa_pod_object p =
411 	    SPA_POD_INIT_Object(sizeof(struct spa_pod_object_body), type, id);
412 	uint32_t offset = builder->state.offset;
413 	int res = spa_pod_builder_raw(builder, &p, sizeof(p));
414 	spa_pod_builder_push(builder, frame, &p.pod, offset);
415 	return res;
416 }
417 
418 #define SPA_POD_INIT_Prop(key,flags,size,type)	\
419 	(struct spa_pod_prop){ key, flags, { size, type } }
420 
421 static inline int
spa_pod_builder_prop(struct spa_pod_builder * builder,uint32_t key,uint32_t flags)422 spa_pod_builder_prop(struct spa_pod_builder *builder, uint32_t key, uint32_t flags)
423 {
424 	const struct { uint32_t key; uint32_t flags; } p = { key, flags };
425 	return spa_pod_builder_raw(builder, &p, sizeof(p));
426 }
427 
428 #define SPA_POD_INIT_Sequence(size,unit)	\
429 	(struct spa_pod_sequence){ { size, SPA_TYPE_Sequence}, {unit, 0 } }
430 
431 static inline int
spa_pod_builder_push_sequence(struct spa_pod_builder * builder,struct spa_pod_frame * frame,uint32_t unit)432 spa_pod_builder_push_sequence(struct spa_pod_builder *builder, struct spa_pod_frame *frame, uint32_t unit)
433 {
434 	const struct spa_pod_sequence p =
435 	    SPA_POD_INIT_Sequence(sizeof(struct spa_pod_sequence_body), unit);
436 	uint32_t offset = builder->state.offset;
437 	int res = spa_pod_builder_raw(builder, &p, sizeof(p));
438 	spa_pod_builder_push(builder, frame, &p.pod, offset);
439 	return res;
440 }
441 
442 static inline uint32_t
spa_pod_builder_control(struct spa_pod_builder * builder,uint32_t offset,uint32_t type)443 spa_pod_builder_control(struct spa_pod_builder *builder, uint32_t offset, uint32_t type)
444 {
445 	const struct { uint32_t offset; uint32_t type; } p = { offset, type };
446 	return spa_pod_builder_raw(builder, &p, sizeof(p));
447 }
448 
spa_choice_from_id(char id)449 static inline uint32_t spa_choice_from_id(char id)
450 {
451 	switch (id) {
452 	case 'r':
453 		return SPA_CHOICE_Range;
454 	case 's':
455 		return SPA_CHOICE_Step;
456 	case 'e':
457 		return SPA_CHOICE_Enum;
458 	case 'f':
459 		return SPA_CHOICE_Flags;
460 	case 'n':
461 	default:
462 		return SPA_CHOICE_None;
463 	}
464 }
465 
466 #define SPA_POD_BUILDER_COLLECT(builder,type,args)				\
467 do {										\
468 	switch (type) {								\
469 	case 'b':								\
470 		spa_pod_builder_bool(builder, !!va_arg(args, int));		\
471 		break;								\
472 	case 'I':								\
473 		spa_pod_builder_id(builder, va_arg(args, uint32_t));		\
474 		break;								\
475 	case 'i':								\
476 		spa_pod_builder_int(builder, va_arg(args, int));		\
477 		break;								\
478 	case 'l':								\
479 		spa_pod_builder_long(builder, va_arg(args, int64_t));		\
480 		break;								\
481 	case 'f':								\
482 		spa_pod_builder_float(builder, va_arg(args, double));		\
483 		break;								\
484 	case 'd':								\
485 		spa_pod_builder_double(builder, va_arg(args, double));		\
486 		break;								\
487 	case 's':								\
488 	{									\
489 		char *strval = va_arg(args, char *);				\
490 		if (strval != NULL) {						\
491 			size_t len = strlen(strval);				\
492 			spa_pod_builder_string_len(builder, strval, len);	\
493 		}								\
494 		else								\
495 			spa_pod_builder_none(builder);				\
496 		break;								\
497 	}									\
498 	case 'S':								\
499 	{									\
500 		char *strval = va_arg(args, char *);				\
501 		size_t len = va_arg(args, int);					\
502 		spa_pod_builder_string_len(builder, strval, len);		\
503 		break;								\
504 	}									\
505 	case 'y':								\
506 	{									\
507 		void *ptr  = va_arg(args, void *);				\
508 		int len = va_arg(args, int);					\
509 		spa_pod_builder_bytes(builder, ptr, len);			\
510 		break;								\
511 	}									\
512 	case 'R':								\
513 	{									\
514 		struct spa_rectangle *rectval =					\
515 			va_arg(args, struct spa_rectangle *);			\
516 		spa_pod_builder_rectangle(builder,				\
517 				rectval->width, rectval->height);		\
518 		break;								\
519 	}									\
520 	case 'F':								\
521 	{									\
522 		struct spa_fraction *fracval =					\
523 			va_arg(args, struct spa_fraction *);			\
524 		spa_pod_builder_fraction(builder, fracval->num, fracval->denom);\
525 		break;								\
526 	}									\
527 	case 'a':								\
528 	{									\
529 		int child_size = va_arg(args, int);				\
530 		int child_type = va_arg(args, int);				\
531 		int n_elems = va_arg(args, int);				\
532 		void *elems = va_arg(args, void *);				\
533 		spa_pod_builder_array(builder, child_size,			\
534 				child_type, n_elems, elems);			\
535 		break;								\
536 	}									\
537 	case 'p':								\
538 	{									\
539 		int t = va_arg(args, uint32_t);					\
540 		spa_pod_builder_pointer(builder, t, va_arg(args, void *));	\
541 		break;								\
542 	}									\
543 	case 'h':								\
544 		spa_pod_builder_fd(builder, va_arg(args, int));			\
545 		break;								\
546 	case 'P':								\
547 	case 'O':								\
548 	case 'T':								\
549 	case 'V':								\
550 	{									\
551 		struct spa_pod *pod = va_arg(args, struct spa_pod *);		\
552 		if (pod == NULL)						\
553 			spa_pod_builder_none(builder);				\
554 		else								\
555 			spa_pod_builder_primitive(builder, pod);		\
556 		break;								\
557 	}									\
558 	}									\
559 } while(false)
560 
561 static inline int
spa_pod_builder_addv(struct spa_pod_builder * builder,va_list args)562 spa_pod_builder_addv(struct spa_pod_builder *builder, va_list args)
563 {
564 	int res = 0;
565 	struct spa_pod_frame *f = builder->state.frame;
566 	uint32_t ftype = f ? f->pod.type : (uint32_t)SPA_TYPE_None;
567 
568 	do {
569 		const char *format;
570 		int n_values = 1;
571 		struct spa_pod_frame f;
572 		bool choice;
573 
574 		switch (ftype) {
575 		case SPA_TYPE_Object:
576 		{
577 			uint32_t key = va_arg(args, uint32_t);
578 			if (key == 0)
579 				goto exit;
580 			spa_pod_builder_prop(builder, key, 0);
581 			break;
582 		}
583 		case SPA_TYPE_Sequence:
584 		{
585 			uint32_t offset = va_arg(args, uint32_t);
586 			uint32_t type = va_arg(args, uint32_t);
587 			if (type == 0)
588 				goto exit;
589 			spa_pod_builder_control(builder, offset, type);
590 		}
591 		default:
592 			break;
593 		}
594 		if ((format = va_arg(args, const char *)) == NULL)
595 			break;
596 
597 		choice = *format == '?';
598 		if (choice) {
599 			uint32_t type = spa_choice_from_id(*++format);
600 			if (*format != '\0')
601 				format++;
602 
603 			spa_pod_builder_push_choice(builder, &f, type, 0);
604 
605 			n_values = va_arg(args, int);
606 		}
607 		while (n_values-- > 0)
608 			SPA_POD_BUILDER_COLLECT(builder, *format, args);
609 
610 		if (choice)
611 			spa_pod_builder_pop(builder, &f);
612 	} while (true);
613 
614       exit:
615 	return res;
616 }
617 
spa_pod_builder_add(struct spa_pod_builder * builder,...)618 static inline int spa_pod_builder_add(struct spa_pod_builder *builder, ...)
619 {
620 	int res;
621 	va_list args;
622 
623 	va_start(args, builder);
624 	res = spa_pod_builder_addv(builder, args);
625 	va_end(args);
626 
627 	return res;
628 }
629 
630 #define spa_pod_builder_add_object(b,type,id,...)				\
631 ({										\
632 	struct spa_pod_frame _f;						\
633 	spa_pod_builder_push_object(b, &_f, type, id);				\
634 	spa_pod_builder_add(b, ##__VA_ARGS__, 0);				\
635 	spa_pod_builder_pop(b, &_f);						\
636 })
637 
638 #define spa_pod_builder_add_struct(b,...)					\
639 ({										\
640 	struct spa_pod_frame _f;						\
641 	spa_pod_builder_push_struct(b, &_f);					\
642 	spa_pod_builder_add(b, ##__VA_ARGS__, NULL);				\
643 	spa_pod_builder_pop(b, &_f);						\
644 })
645 
646 #define spa_pod_builder_add_sequence(b,unit,...)				\
647 ({										\
648 	struct spa_pod_frame _f;						\
649 	spa_pod_builder_push_sequence(b, &_f, unit);				\
650 	spa_pod_builder_add(b, ##__VA_ARGS__, 0, 0);				\
651 	spa_pod_builder_pop(b, &_f);						\
652 })
653 
654 /** Copy a pod structure */
655 static inline struct spa_pod *
spa_pod_copy(const struct spa_pod * pod)656 spa_pod_copy(const struct spa_pod *pod)
657 {
658 	size_t size;
659 	struct spa_pod *c;
660 
661 	size = SPA_POD_SIZE(pod);
662 	if ((c = (struct spa_pod *) malloc(size)) == NULL)
663 		return NULL;
664 	return (struct spa_pod *) memcpy(c, pod, size);
665 }
666 
667 #ifdef __cplusplus
668 }  /* extern "C" */
669 #endif
670 
671 #endif /* SPA_POD_BUILDER_H */
672