1 /* Spa
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_PARSER_H
26 #define SPA_POD_PARSER_H
27 
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31 
32 #include <errno.h>
33 #include <stdarg.h>
34 
35 #include <spa/pod/iter.h>
36 #include <spa/pod/vararg.h>
37 
38 /**
39  * \addtogroup spa_pod
40  * \{
41  */
42 
43 struct spa_pod_parser_state {
44 	uint32_t offset;
45 	uint32_t flags;
46 	struct spa_pod_frame *frame;
47 };
48 
49 struct spa_pod_parser {
50 	const void *data;
51 	uint32_t size;
52 	uint32_t _padding;
53 	struct spa_pod_parser_state state;
54 };
55 
56 #define SPA_POD_PARSER_INIT(buffer,size)  (struct spa_pod_parser){ buffer, size, 0, {} }
57 
spa_pod_parser_init(struct spa_pod_parser * parser,const void * data,uint32_t size)58 static inline void spa_pod_parser_init(struct spa_pod_parser *parser,
59 				       const void *data, uint32_t size)
60 {
61 	*parser = SPA_POD_PARSER_INIT(data, size);
62 }
63 
spa_pod_parser_pod(struct spa_pod_parser * parser,const struct spa_pod * pod)64 static inline void spa_pod_parser_pod(struct spa_pod_parser *parser,
65 				      const struct spa_pod *pod)
66 {
67 	spa_pod_parser_init(parser, pod, SPA_POD_SIZE(pod));
68 }
69 
70 static inline void
spa_pod_parser_get_state(struct spa_pod_parser * parser,struct spa_pod_parser_state * state)71 spa_pod_parser_get_state(struct spa_pod_parser *parser, struct spa_pod_parser_state *state)
72 {
73 	*state = parser->state;
74 }
75 
76 static inline void
spa_pod_parser_reset(struct spa_pod_parser * parser,struct spa_pod_parser_state * state)77 spa_pod_parser_reset(struct spa_pod_parser *parser, struct spa_pod_parser_state *state)
78 {
79 	parser->state = *state;
80 }
81 
82 static inline struct spa_pod *
spa_pod_parser_deref(struct spa_pod_parser * parser,uint32_t offset,uint32_t size)83 spa_pod_parser_deref(struct spa_pod_parser *parser, uint32_t offset, uint32_t size)
84 {
85 	if (offset + 8 <= size) {
86 		struct spa_pod *pod = SPA_PTROFF(parser->data, offset, struct spa_pod);
87 		if (offset + SPA_POD_SIZE(pod) <= size)
88 			return pod;
89 	}
90         return NULL;
91 }
92 
spa_pod_parser_frame(struct spa_pod_parser * parser,struct spa_pod_frame * frame)93 static inline struct spa_pod *spa_pod_parser_frame(struct spa_pod_parser *parser, struct spa_pod_frame *frame)
94 {
95 	return SPA_PTROFF(parser->data, frame->offset, struct spa_pod);
96 }
97 
spa_pod_parser_push(struct spa_pod_parser * parser,struct spa_pod_frame * frame,const struct spa_pod * pod,uint32_t offset)98 static inline void spa_pod_parser_push(struct spa_pod_parser *parser,
99 		      struct spa_pod_frame *frame, const struct spa_pod *pod, uint32_t offset)
100 {
101 	frame->pod = *pod;
102 	frame->offset = offset;
103 	frame->parent = parser->state.frame;
104 	frame->flags = parser->state.flags;
105 	parser->state.frame = frame;
106 }
107 
spa_pod_parser_current(struct spa_pod_parser * parser)108 static inline struct spa_pod *spa_pod_parser_current(struct spa_pod_parser *parser)
109 {
110 	struct spa_pod_frame *f = parser->state.frame;
111 	uint32_t size = f ? f->offset + SPA_POD_SIZE(&f->pod) : parser->size;
112 	return spa_pod_parser_deref(parser, parser->state.offset, size);
113 }
114 
spa_pod_parser_advance(struct spa_pod_parser * parser,const struct spa_pod * pod)115 static inline void spa_pod_parser_advance(struct spa_pod_parser *parser, const struct spa_pod *pod)
116 {
117 	parser->state.offset += SPA_ROUND_UP_N(SPA_POD_SIZE(pod), 8);
118 }
119 
spa_pod_parser_next(struct spa_pod_parser * parser)120 static inline struct spa_pod *spa_pod_parser_next(struct spa_pod_parser *parser)
121 {
122 	struct spa_pod *pod = spa_pod_parser_current(parser);
123 	if (pod)
124 		spa_pod_parser_advance(parser, pod);
125 	return pod;
126 }
127 
spa_pod_parser_pop(struct spa_pod_parser * parser,struct spa_pod_frame * frame)128 static inline int spa_pod_parser_pop(struct spa_pod_parser *parser,
129 		      struct spa_pod_frame *frame)
130 {
131 	parser->state.frame = frame->parent;
132 	parser->state.offset = frame->offset + SPA_ROUND_UP_N(SPA_POD_SIZE(&frame->pod), 8);
133 	return 0;
134 }
135 
spa_pod_parser_get_bool(struct spa_pod_parser * parser,bool * value)136 static inline int spa_pod_parser_get_bool(struct spa_pod_parser *parser, bool *value)
137 {
138 	int res = -EPIPE;
139 	const struct spa_pod *pod = spa_pod_parser_current(parser);
140 	if (pod != NULL && (res = spa_pod_get_bool(pod, value)) >= 0)
141 		spa_pod_parser_advance(parser, pod);
142 	return res;
143 }
144 
spa_pod_parser_get_id(struct spa_pod_parser * parser,uint32_t * value)145 static inline int spa_pod_parser_get_id(struct spa_pod_parser *parser, uint32_t *value)
146 {
147 	int res = -EPIPE;
148 	const struct spa_pod *pod = spa_pod_parser_current(parser);
149 	if (pod != NULL && (res = spa_pod_get_id(pod, value)) >= 0)
150 		spa_pod_parser_advance(parser, pod);
151 	return res;
152 }
153 
spa_pod_parser_get_int(struct spa_pod_parser * parser,int32_t * value)154 static inline int spa_pod_parser_get_int(struct spa_pod_parser *parser, int32_t *value)
155 {
156 	int res = -EPIPE;
157 	const struct spa_pod *pod = spa_pod_parser_current(parser);
158 	if (pod != NULL && (res = spa_pod_get_int(pod, value)) >= 0)
159 		spa_pod_parser_advance(parser, pod);
160 	return res;
161 }
162 
spa_pod_parser_get_long(struct spa_pod_parser * parser,int64_t * value)163 static inline int spa_pod_parser_get_long(struct spa_pod_parser *parser, int64_t *value)
164 {
165 	int res = -EPIPE;
166 	const struct spa_pod *pod = spa_pod_parser_current(parser);
167 	if (pod != NULL && (res = spa_pod_get_long(pod, value)) >= 0)
168 		spa_pod_parser_advance(parser, pod);
169 	return res;
170 }
171 
spa_pod_parser_get_float(struct spa_pod_parser * parser,float * value)172 static inline int spa_pod_parser_get_float(struct spa_pod_parser *parser, float *value)
173 {
174 	int res = -EPIPE;
175 	const struct spa_pod *pod = spa_pod_parser_current(parser);
176 	if (pod != NULL && (res = spa_pod_get_float(pod, value)) >= 0)
177 		spa_pod_parser_advance(parser, pod);
178 	return res;
179 }
180 
spa_pod_parser_get_double(struct spa_pod_parser * parser,double * value)181 static inline int spa_pod_parser_get_double(struct spa_pod_parser *parser, double *value)
182 {
183 	int res = -EPIPE;
184 	const struct spa_pod *pod = spa_pod_parser_current(parser);
185 	if (pod != NULL && (res = spa_pod_get_double(pod, value)) >= 0)
186 		spa_pod_parser_advance(parser, pod);
187 	return res;
188 }
189 
spa_pod_parser_get_string(struct spa_pod_parser * parser,const char ** value)190 static inline int spa_pod_parser_get_string(struct spa_pod_parser *parser, const char **value)
191 {
192 	int res = -EPIPE;
193 	const struct spa_pod *pod = spa_pod_parser_current(parser);
194 	if (pod != NULL && (res = spa_pod_get_string(pod, value)) >= 0)
195 		spa_pod_parser_advance(parser, pod);
196 	return res;
197 }
198 
spa_pod_parser_get_bytes(struct spa_pod_parser * parser,const void ** value,uint32_t * len)199 static inline int spa_pod_parser_get_bytes(struct spa_pod_parser *parser, const void **value, uint32_t *len)
200 {
201 	int res = -EPIPE;
202 	const struct spa_pod *pod = spa_pod_parser_current(parser);
203 	if (pod != NULL && (res = spa_pod_get_bytes(pod, value, len)) >= 0)
204 		spa_pod_parser_advance(parser, pod);
205 	return res;
206 }
207 
spa_pod_parser_get_pointer(struct spa_pod_parser * parser,uint32_t * type,const void ** value)208 static inline int spa_pod_parser_get_pointer(struct spa_pod_parser *parser, uint32_t *type, const void **value)
209 {
210 	int res = -EPIPE;
211 	const struct spa_pod *pod = spa_pod_parser_current(parser);
212 	if (pod != NULL && (res = spa_pod_get_pointer(pod, type, value)) >= 0)
213 		spa_pod_parser_advance(parser, pod);
214 	return res;
215 }
216 
spa_pod_parser_get_fd(struct spa_pod_parser * parser,int64_t * value)217 static inline int spa_pod_parser_get_fd(struct spa_pod_parser *parser, int64_t *value)
218 {
219 	int res = -EPIPE;
220 	const struct spa_pod *pod = spa_pod_parser_current(parser);
221 	if (pod != NULL && (res = spa_pod_get_fd(pod, value)) >= 0)
222 		spa_pod_parser_advance(parser, pod);
223 	return res;
224 }
225 
spa_pod_parser_get_rectangle(struct spa_pod_parser * parser,struct spa_rectangle * value)226 static inline int spa_pod_parser_get_rectangle(struct spa_pod_parser *parser, struct spa_rectangle *value)
227 {
228 	int res = -EPIPE;
229 	const struct spa_pod *pod = spa_pod_parser_current(parser);
230 	if (pod != NULL && (res = spa_pod_get_rectangle(pod, value)) >= 0)
231 		spa_pod_parser_advance(parser, pod);
232 	return res;
233 }
234 
spa_pod_parser_get_fraction(struct spa_pod_parser * parser,struct spa_fraction * value)235 static inline int spa_pod_parser_get_fraction(struct spa_pod_parser *parser, struct spa_fraction *value)
236 {
237 	int res = -EPIPE;
238 	const struct spa_pod *pod = spa_pod_parser_current(parser);
239 	if (pod != NULL && (res = spa_pod_get_fraction(pod, value)) >= 0)
240 		spa_pod_parser_advance(parser, pod);
241 	return res;
242 }
243 
spa_pod_parser_get_pod(struct spa_pod_parser * parser,struct spa_pod ** value)244 static inline int spa_pod_parser_get_pod(struct spa_pod_parser *parser, struct spa_pod **value)
245 {
246 	struct spa_pod *pod = spa_pod_parser_current(parser);
247 	if (pod == NULL)
248 		return -EPIPE;
249 	*value = pod;
250 	spa_pod_parser_advance(parser, pod);
251 	return 0;
252 }
spa_pod_parser_push_struct(struct spa_pod_parser * parser,struct spa_pod_frame * frame)253 static inline int spa_pod_parser_push_struct(struct spa_pod_parser *parser,
254 		struct spa_pod_frame *frame)
255 {
256 	const struct spa_pod *pod = spa_pod_parser_current(parser);
257 	if (pod == NULL)
258 		return -EPIPE;
259 	if (!spa_pod_is_struct(pod))
260 		return -EINVAL;
261 	spa_pod_parser_push(parser, frame, pod, parser->state.offset);
262 	parser->state.offset += sizeof(struct spa_pod_struct);
263 	return 0;
264 }
265 
spa_pod_parser_push_object(struct spa_pod_parser * parser,struct spa_pod_frame * frame,uint32_t type,uint32_t * id)266 static inline int spa_pod_parser_push_object(struct spa_pod_parser *parser,
267 		struct spa_pod_frame *frame, uint32_t type, uint32_t *id)
268 {
269 	const struct spa_pod *pod = spa_pod_parser_current(parser);
270 	if (pod == NULL)
271 		return -EPIPE;
272 	if (!spa_pod_is_object(pod))
273 		return -EINVAL;
274 	if (type != SPA_POD_OBJECT_TYPE(pod))
275 		return -EPROTO;
276 	if (id != NULL)
277 		*id = SPA_POD_OBJECT_ID(pod);
278 	spa_pod_parser_push(parser, frame, pod, parser->state.offset);
279 	parser->state.offset = parser->size;
280 	return 0;
281 }
282 
spa_pod_parser_can_collect(const struct spa_pod * pod,char type)283 static inline bool spa_pod_parser_can_collect(const struct spa_pod *pod, char type)
284 {
285 	if (pod == NULL)
286 		return false;
287 
288 	if (spa_pod_is_choice(pod) &&
289 	    SPA_POD_CHOICE_TYPE(pod) == SPA_CHOICE_None &&
290 	    spa_pod_parser_can_collect(SPA_POD_CHOICE_CHILD(pod), type))
291 		return true;
292 
293 	switch (type) {
294 	case 'P':
295 		return true;
296 	case 'b':
297 		return spa_pod_is_bool(pod);
298 	case 'I':
299 		return spa_pod_is_id(pod);
300 	case 'i':
301 		return spa_pod_is_int(pod);
302 	case 'l':
303 		return spa_pod_is_long(pod);
304 	case 'f':
305 		return spa_pod_is_float(pod);
306 	case 'd':
307 		return spa_pod_is_double(pod);
308 	case 's':
309 		return spa_pod_is_string(pod) || spa_pod_is_none(pod);
310 	case 'S':
311 		return spa_pod_is_string(pod);
312 	case 'y':
313 		return spa_pod_is_bytes(pod);
314 	case 'R':
315 		return spa_pod_is_rectangle(pod);
316 	case 'F':
317 		return spa_pod_is_fraction(pod);
318 	case 'B':
319 		return spa_pod_is_bitmap(pod);
320 	case 'a':
321 		return spa_pod_is_array(pod);
322 	case 'p':
323 		return spa_pod_is_pointer(pod);
324 	case 'h':
325 		return spa_pod_is_fd(pod);
326 	case 'T':
327 		return spa_pod_is_struct(pod) || spa_pod_is_none(pod);
328 	case 'O':
329 		return spa_pod_is_object(pod) || spa_pod_is_none(pod);
330 	case 'V':
331 		return spa_pod_is_choice(pod);
332 	default:
333 		return false;
334 	}
335 }
336 
337 #define SPA_POD_PARSER_COLLECT(pod,_type,args)						\
338 do {											\
339 	switch (_type) {								\
340 	case 'b':									\
341 		*va_arg(args, bool*) = SPA_POD_VALUE(struct spa_pod_bool, pod);		\
342 		break;									\
343 	case 'I':									\
344 	case 'i':									\
345 		*va_arg(args, int32_t*) = SPA_POD_VALUE(struct spa_pod_int, pod);	\
346 		break;									\
347 	case 'l':									\
348 		*va_arg(args, int64_t*) = SPA_POD_VALUE(struct spa_pod_long, pod);	\
349 		break;									\
350 	case 'f':									\
351 		*va_arg(args, float*) = SPA_POD_VALUE(struct spa_pod_float, pod);	\
352 		break;									\
353 	case 'd':									\
354 		*va_arg(args, double*) = SPA_POD_VALUE(struct spa_pod_double, pod);	\
355 		break;									\
356 	case 's':									\
357 		*va_arg(args, char**) =							\
358 			(pod == NULL || (SPA_POD_TYPE(pod) == SPA_TYPE_None)		\
359 				? NULL							\
360 				: (char *)SPA_POD_CONTENTS(struct spa_pod_string, pod));	\
361 		break;									\
362 	case 'S':									\
363 	{										\
364 		char *dest = va_arg(args, char*);					\
365 		uint32_t maxlen = va_arg(args, uint32_t);				\
366 		strncpy(dest, (char *)SPA_POD_CONTENTS(struct spa_pod_string, pod), maxlen-1);	\
367 		dest[maxlen-1] = '\0';							\
368 		break;									\
369 	}										\
370 	case 'y':									\
371 		*(va_arg(args, void **)) = SPA_POD_CONTENTS(struct spa_pod_bytes, pod);	\
372 		*(va_arg(args, uint32_t *)) = SPA_POD_BODY_SIZE(pod);			\
373 		break;									\
374 	case 'R':									\
375 		*va_arg(args, struct spa_rectangle*) =					\
376 				SPA_POD_VALUE(struct spa_pod_rectangle, pod);		\
377 		break;									\
378 	case 'F':									\
379 		*va_arg(args, struct spa_fraction*) =					\
380 				SPA_POD_VALUE(struct spa_pod_fraction, pod);		\
381 		break;									\
382 	case 'B':									\
383 		*va_arg(args, uint32_t **) =						\
384 			(uint32_t *) SPA_POD_CONTENTS(struct spa_pod_bitmap, pod);	\
385 		break;									\
386 	case 'a':									\
387 		*va_arg(args, uint32_t*) = SPA_POD_ARRAY_VALUE_SIZE(pod);		\
388 		*va_arg(args, uint32_t*) = SPA_POD_ARRAY_VALUE_TYPE(pod);		\
389 		*va_arg(args, uint32_t*) = SPA_POD_ARRAY_N_VALUES(pod);			\
390 		*va_arg(args, void**) = SPA_POD_ARRAY_VALUES(pod);			\
391 		break;									\
392 	case 'p':									\
393 	{										\
394 		struct spa_pod_pointer_body *b =					\
395 				(struct spa_pod_pointer_body *) SPA_POD_BODY(pod);	\
396 		*(va_arg(args, uint32_t *)) = b->type;					\
397 		*(va_arg(args, const void **)) = b->value;				\
398 		break;									\
399 	}										\
400 	case 'h':									\
401 		*va_arg(args, int64_t*) = SPA_POD_VALUE(struct spa_pod_fd, pod);	\
402 		break;									\
403 	case 'P':									\
404 	case 'T':									\
405 	case 'O':									\
406 	case 'V':									\
407 	{										\
408 		const struct spa_pod **d = va_arg(args, const struct spa_pod**);	\
409 		if (d)									\
410 			*d = (pod == NULL || (SPA_POD_TYPE(pod) == SPA_TYPE_None)	\
411 				? NULL : pod);						\
412 		break;									\
413 	}										\
414 	default:									\
415 		break;									\
416 	}										\
417 } while(false)
418 
419 #define SPA_POD_PARSER_SKIP(_type,args)							\
420 do {											\
421 	switch (_type) {								\
422 	case 'S':									\
423 		va_arg(args, char*);							\
424 		va_arg(args, uint32_t);							\
425 		break;									\
426 	case 'a':									\
427 		va_arg(args, void*);							\
428 		va_arg(args, void*);							\
429 		SPA_FALLTHROUGH 							\
430 	case 'p':									\
431 	case 'y':									\
432 		va_arg(args, void*);							\
433 		SPA_FALLTHROUGH 							\
434 	case 'b':									\
435 	case 'I':									\
436 	case 'i':									\
437 	case 'l':									\
438 	case 'f':									\
439 	case 'd':									\
440 	case 's':									\
441 	case 'R':									\
442 	case 'F':									\
443 	case 'B':									\
444 	case 'h':									\
445 	case 'V':									\
446 	case 'P':									\
447 	case 'T':									\
448 	case 'O':									\
449 		va_arg(args, void*);							\
450 		break;									\
451 	}										\
452 } while(false)
453 
spa_pod_parser_getv(struct spa_pod_parser * parser,va_list args)454 static inline int spa_pod_parser_getv(struct spa_pod_parser *parser, va_list args)
455 {
456 	struct spa_pod_frame *f = parser->state.frame;
457         uint32_t ftype = f ? f->pod.type : (uint32_t)SPA_TYPE_Struct;
458 	const struct spa_pod_prop *prop = NULL;
459 	int count = 0;
460 
461 	do {
462 		bool optional;
463 		const struct spa_pod *pod = NULL;
464 		const char *format;
465 
466 		if (ftype == SPA_TYPE_Object) {
467 			uint32_t key = va_arg(args, uint32_t);
468 			const struct spa_pod_object *object;
469 
470 			if (key == 0)
471 				break;
472 
473 			object = (const struct spa_pod_object *)spa_pod_parser_frame(parser, f);
474 			prop = spa_pod_object_find_prop(object, prop, key);
475 			pod = prop ? &prop->value : NULL;
476 		}
477 
478 		if ((format = va_arg(args, char *)) == NULL)
479 			break;
480 
481 		if (ftype == SPA_TYPE_Struct)
482 			pod = spa_pod_parser_next(parser);
483 
484 		if ((optional = (*format == '?')))
485 			format++;
486 
487 		if (!spa_pod_parser_can_collect(pod, *format)) {
488 			if (!optional) {
489 				if (pod == NULL)
490 					return -ESRCH;
491 				else
492 					return -EPROTO;
493 			}
494 			SPA_POD_PARSER_SKIP(*format, args);
495 		} else {
496 			if (pod->type == SPA_TYPE_Choice && *format != 'V' &&
497 			    SPA_POD_CHOICE_TYPE(pod) == SPA_CHOICE_None)
498 				pod = SPA_POD_CHOICE_CHILD(pod);
499 
500 			SPA_POD_PARSER_COLLECT(pod, *format, args);
501 			count++;
502 		}
503 	} while (true);
504 
505 	return count;
506 }
507 
spa_pod_parser_get(struct spa_pod_parser * parser,...)508 static inline int spa_pod_parser_get(struct spa_pod_parser *parser, ...)
509 {
510 	int res;
511 	va_list args;
512 
513 	va_start(args, parser);
514 	res = spa_pod_parser_getv(parser, args);
515 	va_end(args);
516 
517 	return res;
518 }
519 
520 #define SPA_POD_OPT_Bool(val)				"?" SPA_POD_Bool(val)
521 #define SPA_POD_OPT_Id(val)				"?" SPA_POD_Id(val)
522 #define SPA_POD_OPT_Int(val)				"?" SPA_POD_Int(val)
523 #define SPA_POD_OPT_Long(val)				"?" SPA_POD_Long(val)
524 #define SPA_POD_OPT_Float(val)				"?" SPA_POD_Float(val)
525 #define SPA_POD_OPT_Double(val)				"?" SPA_POD_Double(val)
526 #define SPA_POD_OPT_String(val)				"?" SPA_POD_String(val)
527 #define SPA_POD_OPT_Stringn(val,len)			"?" SPA_POD_Stringn(val,len)
528 #define SPA_POD_OPT_Bytes(val,len)			"?" SPA_POD_Bytes(val,len)
529 #define SPA_POD_OPT_Rectangle(val)			"?" SPA_POD_Rectangle(val)
530 #define SPA_POD_OPT_Fraction(val)			"?" SPA_POD_Fraction(val)
531 #define SPA_POD_OPT_Array(csize,ctype,n_vals,vals)	"?" SPA_POD_Array(csize,ctype,n_vals,vals)
532 #define SPA_POD_OPT_Pointer(type,val)			"?" SPA_POD_Pointer(type,val)
533 #define SPA_POD_OPT_Fd(val)				"?" SPA_POD_Fd(val)
534 #define SPA_POD_OPT_Pod(val)				"?" SPA_POD_Pod(val)
535 #define SPA_POD_OPT_PodObject(val)			"?" SPA_POD_PodObject(val)
536 #define SPA_POD_OPT_PodStruct(val)			"?" SPA_POD_PodStruct(val)
537 #define SPA_POD_OPT_PodChoice(val)			"?" SPA_POD_PodChoice(val)
538 
539 #define spa_pod_parser_get_object(p,type,id,...)				\
540 ({										\
541 	struct spa_pod_frame _f;						\
542 	int _res;								\
543 	if ((_res = spa_pod_parser_push_object(p, &_f, type, id)) == 0) {	\
544 		_res = spa_pod_parser_get(p,##__VA_ARGS__, 0);			\
545 		spa_pod_parser_pop(p, &_f);					\
546 	}									\
547 	_res;									\
548 })
549 
550 #define spa_pod_parser_get_struct(p,...)				\
551 ({									\
552 	struct spa_pod_frame _f;					\
553 	int _res;							\
554 	if ((_res = spa_pod_parser_push_struct(p, &_f)) == 0) {		\
555 		_res = spa_pod_parser_get(p,##__VA_ARGS__, NULL);	\
556 		spa_pod_parser_pop(p, &_f);				\
557 	}								\
558 	_res;							\
559 })
560 
561 #define spa_pod_parse_object(pod,type,id,...)			\
562 ({								\
563 	struct spa_pod_parser _p;				\
564 	spa_pod_parser_pod(&_p, pod);				\
565 	spa_pod_parser_get_object(&_p,type,id,##__VA_ARGS__);	\
566 })
567 
568 #define spa_pod_parse_struct(pod,...)				\
569 ({								\
570 	struct spa_pod_parser _p;				\
571 	spa_pod_parser_pod(&_p, pod);				\
572 	spa_pod_parser_get_struct(&_p,##__VA_ARGS__);		\
573 })
574 
575 /**
576  * \}
577  */
578 
579 #ifdef __cplusplus
580 }  /* extern "C" */
581 #endif
582 
583 #endif /* SPA_POD_PARSER_H */
584