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