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