mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-31 22:25:38 -04:00
574 lines
16 KiB
C
574 lines
16 KiB
C
/* Spa */
|
|
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
|
/* SPDX-License-Identifier: MIT */
|
|
|
|
#ifndef SPA_POD_PARSER_H
|
|
#define SPA_POD_PARSER_H
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#include <errno.h>
|
|
#include <stdarg.h>
|
|
|
|
#include <spa/pod/iter.h>
|
|
#include <spa/pod/vararg.h>
|
|
|
|
/**
|
|
* \addtogroup spa_pod
|
|
* \{
|
|
*/
|
|
|
|
struct spa_pod_parser_state {
|
|
uint32_t offset;
|
|
uint32_t flags;
|
|
struct spa_pod_frame *frame;
|
|
};
|
|
|
|
struct spa_pod_parser {
|
|
const void *data;
|
|
uint32_t size;
|
|
uint32_t _padding;
|
|
struct spa_pod_parser_state state;
|
|
};
|
|
|
|
#define SPA_POD_PARSER_INIT(buffer,size) ((struct spa_pod_parser){ (buffer), (size), 0, {0,0,NULL}})
|
|
|
|
static inline void spa_pod_parser_init(struct spa_pod_parser *parser,
|
|
const void *data, uint32_t size)
|
|
{
|
|
*parser = SPA_POD_PARSER_INIT(data, size);
|
|
}
|
|
|
|
static inline void spa_pod_parser_pod(struct spa_pod_parser *parser,
|
|
const struct spa_pod *pod)
|
|
{
|
|
spa_pod_parser_init(parser, pod, SPA_POD_SIZE(pod));
|
|
}
|
|
|
|
static inline void
|
|
spa_pod_parser_get_state(struct spa_pod_parser *parser, struct spa_pod_parser_state *state)
|
|
{
|
|
*state = parser->state;
|
|
}
|
|
|
|
static inline void
|
|
spa_pod_parser_reset(struct spa_pod_parser *parser, struct spa_pod_parser_state *state)
|
|
{
|
|
parser->state = *state;
|
|
}
|
|
|
|
static inline struct spa_pod *
|
|
spa_pod_parser_deref(struct spa_pod_parser *parser, uint32_t offset, uint32_t size)
|
|
{
|
|
/* Cast to uint64_t to avoid wraparound. Add 8 for the pod itself. */
|
|
const uint64_t long_offset = (uint64_t)offset + 8;
|
|
if (long_offset <= size && (offset & 7) == 0) {
|
|
/* Use void* because creating a misaligned pointer is undefined. */
|
|
void *pod = SPA_PTROFF(parser->data, offset, void);
|
|
/*
|
|
* Check that the pointer is aligned and that the size (rounded
|
|
* to the next multiple of 8) is in bounds.
|
|
*/
|
|
if (SPA_IS_ALIGNED(pod, __alignof__(struct spa_pod)) &&
|
|
long_offset + SPA_ROUND_UP_N((uint64_t)SPA_POD_BODY_SIZE(pod), 8) <= size)
|
|
return (struct spa_pod *)pod;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static inline struct spa_pod *spa_pod_parser_frame(struct spa_pod_parser *parser, struct spa_pod_frame *frame)
|
|
{
|
|
return SPA_PTROFF(parser->data, frame->offset, struct spa_pod);
|
|
}
|
|
|
|
static inline void spa_pod_parser_push(struct spa_pod_parser *parser,
|
|
struct spa_pod_frame *frame, const struct spa_pod *pod, uint32_t offset)
|
|
{
|
|
frame->pod = *pod;
|
|
frame->offset = offset;
|
|
frame->parent = parser->state.frame;
|
|
frame->flags = parser->state.flags;
|
|
parser->state.frame = frame;
|
|
}
|
|
|
|
static inline struct spa_pod *spa_pod_parser_current(struct spa_pod_parser *parser)
|
|
{
|
|
struct spa_pod_frame *f = parser->state.frame;
|
|
uint32_t size = f ? f->offset + SPA_POD_SIZE(&f->pod) : parser->size;
|
|
return spa_pod_parser_deref(parser, parser->state.offset, size);
|
|
}
|
|
|
|
static inline void spa_pod_parser_advance(struct spa_pod_parser *parser, const struct spa_pod *pod)
|
|
{
|
|
parser->state.offset += SPA_ROUND_UP_N(SPA_POD_SIZE(pod), 8);
|
|
}
|
|
|
|
static inline struct spa_pod *spa_pod_parser_next(struct spa_pod_parser *parser)
|
|
{
|
|
struct spa_pod *pod = spa_pod_parser_current(parser);
|
|
if (pod)
|
|
spa_pod_parser_advance(parser, pod);
|
|
return pod;
|
|
}
|
|
|
|
static inline int spa_pod_parser_pop(struct spa_pod_parser *parser,
|
|
struct spa_pod_frame *frame)
|
|
{
|
|
parser->state.frame = frame->parent;
|
|
parser->state.offset = frame->offset + SPA_ROUND_UP_N(SPA_POD_SIZE(&frame->pod), 8);
|
|
return 0;
|
|
}
|
|
|
|
static inline int spa_pod_parser_get_bool(struct spa_pod_parser *parser, bool *value)
|
|
{
|
|
int res = -EPIPE;
|
|
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
|
if (pod != NULL && (res = spa_pod_get_bool(pod, value)) >= 0)
|
|
spa_pod_parser_advance(parser, pod);
|
|
return res;
|
|
}
|
|
|
|
static inline int spa_pod_parser_get_id(struct spa_pod_parser *parser, uint32_t *value)
|
|
{
|
|
int res = -EPIPE;
|
|
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
|
if (pod != NULL && (res = spa_pod_get_id(pod, value)) >= 0)
|
|
spa_pod_parser_advance(parser, pod);
|
|
return res;
|
|
}
|
|
|
|
static inline int spa_pod_parser_get_int(struct spa_pod_parser *parser, int32_t *value)
|
|
{
|
|
int res = -EPIPE;
|
|
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
|
if (pod != NULL && (res = spa_pod_get_int(pod, value)) >= 0)
|
|
spa_pod_parser_advance(parser, pod);
|
|
return res;
|
|
}
|
|
|
|
static inline int spa_pod_parser_get_long(struct spa_pod_parser *parser, int64_t *value)
|
|
{
|
|
int res = -EPIPE;
|
|
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
|
if (pod != NULL && (res = spa_pod_get_long(pod, value)) >= 0)
|
|
spa_pod_parser_advance(parser, pod);
|
|
return res;
|
|
}
|
|
|
|
static inline int spa_pod_parser_get_float(struct spa_pod_parser *parser, float *value)
|
|
{
|
|
int res = -EPIPE;
|
|
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
|
if (pod != NULL && (res = spa_pod_get_float(pod, value)) >= 0)
|
|
spa_pod_parser_advance(parser, pod);
|
|
return res;
|
|
}
|
|
|
|
static inline int spa_pod_parser_get_double(struct spa_pod_parser *parser, double *value)
|
|
{
|
|
int res = -EPIPE;
|
|
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
|
if (pod != NULL && (res = spa_pod_get_double(pod, value)) >= 0)
|
|
spa_pod_parser_advance(parser, pod);
|
|
return res;
|
|
}
|
|
|
|
static inline int spa_pod_parser_get_string(struct spa_pod_parser *parser, const char **value)
|
|
{
|
|
int res = -EPIPE;
|
|
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
|
if (pod != NULL && (res = spa_pod_get_string(pod, value)) >= 0)
|
|
spa_pod_parser_advance(parser, pod);
|
|
return res;
|
|
}
|
|
|
|
static inline int spa_pod_parser_get_bytes(struct spa_pod_parser *parser, const void **value, uint32_t *len)
|
|
{
|
|
int res = -EPIPE;
|
|
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
|
if (pod != NULL && (res = spa_pod_get_bytes(pod, value, len)) >= 0)
|
|
spa_pod_parser_advance(parser, pod);
|
|
return res;
|
|
}
|
|
|
|
static inline int spa_pod_parser_get_pointer(struct spa_pod_parser *parser, uint32_t *type, const void **value)
|
|
{
|
|
int res = -EPIPE;
|
|
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
|
if (pod != NULL && (res = spa_pod_get_pointer(pod, type, value)) >= 0)
|
|
spa_pod_parser_advance(parser, pod);
|
|
return res;
|
|
}
|
|
|
|
static inline int spa_pod_parser_get_fd(struct spa_pod_parser *parser, int64_t *value)
|
|
{
|
|
int res = -EPIPE;
|
|
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
|
if (pod != NULL && (res = spa_pod_get_fd(pod, value)) >= 0)
|
|
spa_pod_parser_advance(parser, pod);
|
|
return res;
|
|
}
|
|
|
|
static inline int spa_pod_parser_get_rectangle(struct spa_pod_parser *parser, struct spa_rectangle *value)
|
|
{
|
|
int res = -EPIPE;
|
|
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
|
if (pod != NULL && (res = spa_pod_get_rectangle(pod, value)) >= 0)
|
|
spa_pod_parser_advance(parser, pod);
|
|
return res;
|
|
}
|
|
|
|
static inline int spa_pod_parser_get_fraction(struct spa_pod_parser *parser, struct spa_fraction *value)
|
|
{
|
|
int res = -EPIPE;
|
|
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
|
if (pod != NULL && (res = spa_pod_get_fraction(pod, value)) >= 0)
|
|
spa_pod_parser_advance(parser, pod);
|
|
return res;
|
|
}
|
|
|
|
static inline int spa_pod_parser_get_pod(struct spa_pod_parser *parser, struct spa_pod **value)
|
|
{
|
|
struct spa_pod *pod = spa_pod_parser_current(parser);
|
|
if (pod == NULL)
|
|
return -EPIPE;
|
|
*value = pod;
|
|
spa_pod_parser_advance(parser, pod);
|
|
return 0;
|
|
}
|
|
static inline int spa_pod_parser_push_struct(struct spa_pod_parser *parser,
|
|
struct spa_pod_frame *frame)
|
|
{
|
|
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
|
if (pod == NULL)
|
|
return -EPIPE;
|
|
if (!spa_pod_is_struct(pod))
|
|
return -EINVAL;
|
|
spa_pod_parser_push(parser, frame, pod, parser->state.offset);
|
|
parser->state.offset += sizeof(struct spa_pod_struct);
|
|
return 0;
|
|
}
|
|
|
|
static inline int spa_pod_parser_push_object(struct spa_pod_parser *parser,
|
|
struct spa_pod_frame *frame, uint32_t type, uint32_t *id)
|
|
{
|
|
const struct spa_pod *pod = spa_pod_parser_current(parser);
|
|
if (pod == NULL)
|
|
return -EPIPE;
|
|
if (!spa_pod_is_object(pod))
|
|
return -EINVAL;
|
|
if (type != SPA_POD_OBJECT_TYPE(pod))
|
|
return -EPROTO;
|
|
if (id != NULL)
|
|
*id = SPA_POD_OBJECT_ID(pod);
|
|
spa_pod_parser_push(parser, frame, pod, parser->state.offset);
|
|
parser->state.offset = parser->size;
|
|
return 0;
|
|
}
|
|
|
|
static inline bool spa_pod_parser_can_collect(const struct spa_pod *pod, char type)
|
|
{
|
|
if (pod == NULL)
|
|
return false;
|
|
|
|
if (SPA_POD_TYPE(pod) == SPA_TYPE_Choice) {
|
|
if (!spa_pod_is_choice(pod))
|
|
return false;
|
|
if (type == 'V')
|
|
return true;
|
|
if (SPA_POD_CHOICE_TYPE(pod) != SPA_CHOICE_None)
|
|
return false;
|
|
pod = SPA_POD_CHOICE_CHILD(pod);
|
|
}
|
|
|
|
switch (type) {
|
|
case 'P':
|
|
return true;
|
|
case 'b':
|
|
return spa_pod_is_bool(pod);
|
|
case 'I':
|
|
return spa_pod_is_id(pod);
|
|
case 'i':
|
|
return spa_pod_is_int(pod);
|
|
case 'l':
|
|
return spa_pod_is_long(pod);
|
|
case 'f':
|
|
return spa_pod_is_float(pod);
|
|
case 'd':
|
|
return spa_pod_is_double(pod);
|
|
case 's':
|
|
return spa_pod_is_string(pod) || spa_pod_is_none(pod);
|
|
case 'S':
|
|
return spa_pod_is_string(pod);
|
|
case 'y':
|
|
return spa_pod_is_bytes(pod);
|
|
case 'R':
|
|
return spa_pod_is_rectangle(pod);
|
|
case 'F':
|
|
return spa_pod_is_fraction(pod);
|
|
case 'B':
|
|
return spa_pod_is_bitmap(pod);
|
|
case 'a':
|
|
return spa_pod_is_array(pod);
|
|
case 'p':
|
|
return spa_pod_is_pointer(pod);
|
|
case 'h':
|
|
return spa_pod_is_fd(pod);
|
|
case 'T':
|
|
return spa_pod_is_struct(pod) || spa_pod_is_none(pod);
|
|
case 'O':
|
|
return spa_pod_is_object(pod) || spa_pod_is_none(pod);
|
|
case 'V':
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#define SPA_POD_PARSER_COLLECT(pod,_type,args) \
|
|
do { \
|
|
switch (_type) { \
|
|
case 'b': \
|
|
*va_arg(args, bool*) = SPA_POD_VALUE(struct spa_pod_bool, pod); \
|
|
break; \
|
|
case 'I': \
|
|
case 'i': \
|
|
*va_arg(args, int32_t*) = SPA_POD_VALUE(struct spa_pod_int, pod); \
|
|
break; \
|
|
case 'l': \
|
|
*va_arg(args, int64_t*) = SPA_POD_VALUE(struct spa_pod_long, pod); \
|
|
break; \
|
|
case 'f': \
|
|
*va_arg(args, float*) = SPA_POD_VALUE(struct spa_pod_float, pod); \
|
|
break; \
|
|
case 'd': \
|
|
*va_arg(args, double*) = SPA_POD_VALUE(struct spa_pod_double, pod); \
|
|
break; \
|
|
case 's': \
|
|
*va_arg(args, char**) = \
|
|
((pod) == NULL || (SPA_POD_TYPE(pod) == SPA_TYPE_None) \
|
|
? NULL \
|
|
: (char *)SPA_POD_CONTENTS(struct spa_pod_string, pod)); \
|
|
break; \
|
|
case 'S': \
|
|
{ \
|
|
char *dest = va_arg(args, char*); \
|
|
uint32_t maxlen = va_arg(args, uint32_t); \
|
|
strncpy(dest, (char *)SPA_POD_CONTENTS(struct spa_pod_string, pod), maxlen-1); \
|
|
dest[maxlen-1] = '\0'; \
|
|
break; \
|
|
} \
|
|
case 'y': \
|
|
*(va_arg(args, void **)) = SPA_POD_CONTENTS(struct spa_pod_bytes, pod); \
|
|
*(va_arg(args, uint32_t *)) = SPA_POD_BODY_SIZE(pod); \
|
|
break; \
|
|
case 'R': \
|
|
*va_arg(args, struct spa_rectangle*) = \
|
|
SPA_POD_VALUE(struct spa_pod_rectangle, pod); \
|
|
break; \
|
|
case 'F': \
|
|
*va_arg(args, struct spa_fraction*) = \
|
|
SPA_POD_VALUE(struct spa_pod_fraction, pod); \
|
|
break; \
|
|
case 'B': \
|
|
*va_arg(args, uint32_t **) = \
|
|
(uint32_t *) SPA_POD_CONTENTS(struct spa_pod_bitmap, pod); \
|
|
break; \
|
|
case 'a': \
|
|
*va_arg(args, uint32_t*) = SPA_POD_ARRAY_VALUE_SIZE(pod); \
|
|
*va_arg(args, uint32_t*) = SPA_POD_ARRAY_VALUE_TYPE(pod); \
|
|
*va_arg(args, uint32_t*) = SPA_POD_ARRAY_N_VALUES(pod); \
|
|
*va_arg(args, void**) = SPA_POD_ARRAY_VALUES(pod); \
|
|
break; \
|
|
case 'p': \
|
|
{ \
|
|
struct spa_pod_pointer_body *b = \
|
|
(struct spa_pod_pointer_body *) SPA_POD_BODY(pod); \
|
|
*(va_arg(args, uint32_t *)) = b->type; \
|
|
*(va_arg(args, const void **)) = b->value; \
|
|
break; \
|
|
} \
|
|
case 'h': \
|
|
*va_arg(args, int64_t*) = SPA_POD_VALUE(struct spa_pod_fd, pod); \
|
|
break; \
|
|
case 'P': \
|
|
case 'T': \
|
|
case 'O': \
|
|
case 'V': \
|
|
{ \
|
|
const struct spa_pod **d = va_arg(args, const struct spa_pod**); \
|
|
if (d) \
|
|
*d = ((pod) == NULL || (SPA_POD_TYPE(pod) == SPA_TYPE_None) \
|
|
? NULL : (pod)); \
|
|
break; \
|
|
} \
|
|
default: \
|
|
break; \
|
|
} \
|
|
} while(false)
|
|
|
|
#define SPA_POD_PARSER_SKIP(_type,args) \
|
|
do { \
|
|
switch (_type) { \
|
|
case 'S': \
|
|
va_arg(args, char*); \
|
|
va_arg(args, uint32_t); \
|
|
break; \
|
|
case 'a': \
|
|
va_arg(args, void*); \
|
|
va_arg(args, void*); \
|
|
SPA_FALLTHROUGH \
|
|
case 'p': \
|
|
case 'y': \
|
|
va_arg(args, void*); \
|
|
SPA_FALLTHROUGH \
|
|
case 'b': \
|
|
case 'I': \
|
|
case 'i': \
|
|
case 'l': \
|
|
case 'f': \
|
|
case 'd': \
|
|
case 's': \
|
|
case 'R': \
|
|
case 'F': \
|
|
case 'B': \
|
|
case 'h': \
|
|
case 'V': \
|
|
case 'P': \
|
|
case 'T': \
|
|
case 'O': \
|
|
va_arg(args, void*); \
|
|
break; \
|
|
} \
|
|
} while(false)
|
|
|
|
static inline int spa_pod_parser_getv(struct spa_pod_parser *parser, va_list args)
|
|
{
|
|
struct spa_pod_frame *f = parser->state.frame;
|
|
uint32_t ftype = f ? f->pod.type : (uint32_t)SPA_TYPE_Struct;
|
|
const struct spa_pod_prop *prop = NULL;
|
|
int count = 0;
|
|
|
|
do {
|
|
bool optional;
|
|
const struct spa_pod *pod = NULL;
|
|
const char *format;
|
|
|
|
if (f && ftype == SPA_TYPE_Object) {
|
|
uint32_t key = va_arg(args, uint32_t);
|
|
const struct spa_pod_object *object;
|
|
|
|
if (key == 0)
|
|
break;
|
|
|
|
object = (const struct spa_pod_object *)spa_pod_parser_frame(parser, f);
|
|
prop = spa_pod_object_find_prop(object, prop, key);
|
|
pod = prop ? &prop->value : NULL;
|
|
}
|
|
|
|
if ((format = va_arg(args, char *)) == NULL)
|
|
break;
|
|
|
|
if (ftype == SPA_TYPE_Struct)
|
|
pod = spa_pod_parser_next(parser);
|
|
|
|
if ((optional = (*format == '?')))
|
|
format++;
|
|
|
|
if (!spa_pod_parser_can_collect(pod, *format)) {
|
|
if (!optional) {
|
|
if (pod == NULL)
|
|
return -ESRCH;
|
|
else
|
|
return -EPROTO;
|
|
}
|
|
SPA_POD_PARSER_SKIP(*format, args);
|
|
} else {
|
|
if (pod->type == SPA_TYPE_Choice && *format != 'V')
|
|
pod = SPA_POD_CHOICE_CHILD(pod);
|
|
|
|
SPA_POD_PARSER_COLLECT(pod, *format, args);
|
|
count++;
|
|
}
|
|
} while (true);
|
|
|
|
return count;
|
|
}
|
|
|
|
static inline int spa_pod_parser_get(struct spa_pod_parser *parser, ...)
|
|
{
|
|
int res;
|
|
va_list args;
|
|
|
|
va_start(args, parser);
|
|
res = spa_pod_parser_getv(parser, args);
|
|
va_end(args);
|
|
|
|
return res;
|
|
}
|
|
|
|
#define SPA_POD_OPT_Bool(val) "?" SPA_POD_Bool(val)
|
|
#define SPA_POD_OPT_Id(val) "?" SPA_POD_Id(val)
|
|
#define SPA_POD_OPT_Int(val) "?" SPA_POD_Int(val)
|
|
#define SPA_POD_OPT_Long(val) "?" SPA_POD_Long(val)
|
|
#define SPA_POD_OPT_Float(val) "?" SPA_POD_Float(val)
|
|
#define SPA_POD_OPT_Double(val) "?" SPA_POD_Double(val)
|
|
#define SPA_POD_OPT_String(val) "?" SPA_POD_String(val)
|
|
#define SPA_POD_OPT_Stringn(val,len) "?" SPA_POD_Stringn(val,len)
|
|
#define SPA_POD_OPT_Bytes(val,len) "?" SPA_POD_Bytes(val,len)
|
|
#define SPA_POD_OPT_Rectangle(val) "?" SPA_POD_Rectangle(val)
|
|
#define SPA_POD_OPT_Fraction(val) "?" SPA_POD_Fraction(val)
|
|
#define SPA_POD_OPT_Array(csize,ctype,n_vals,vals) "?" SPA_POD_Array(csize,ctype,n_vals,vals)
|
|
#define SPA_POD_OPT_Pointer(type,val) "?" SPA_POD_Pointer(type,val)
|
|
#define SPA_POD_OPT_Fd(val) "?" SPA_POD_Fd(val)
|
|
#define SPA_POD_OPT_Pod(val) "?" SPA_POD_Pod(val)
|
|
#define SPA_POD_OPT_PodObject(val) "?" SPA_POD_PodObject(val)
|
|
#define SPA_POD_OPT_PodStruct(val) "?" SPA_POD_PodStruct(val)
|
|
#define SPA_POD_OPT_PodChoice(val) "?" SPA_POD_PodChoice(val)
|
|
|
|
#define spa_pod_parser_get_object(p,type,id,...) \
|
|
({ \
|
|
struct spa_pod_frame _f; \
|
|
int _res; \
|
|
if ((_res = spa_pod_parser_push_object(p, &_f, type, id)) == 0) { \
|
|
_res = spa_pod_parser_get(p,##__VA_ARGS__, 0); \
|
|
spa_pod_parser_pop(p, &_f); \
|
|
} \
|
|
_res; \
|
|
})
|
|
|
|
#define spa_pod_parser_get_struct(p,...) \
|
|
({ \
|
|
struct spa_pod_frame _f; \
|
|
int _res; \
|
|
if ((_res = spa_pod_parser_push_struct(p, &_f)) == 0) { \
|
|
_res = spa_pod_parser_get(p,##__VA_ARGS__, NULL); \
|
|
spa_pod_parser_pop(p, &_f); \
|
|
} \
|
|
_res; \
|
|
})
|
|
|
|
#define spa_pod_parse_object(pod,type,id,...) \
|
|
({ \
|
|
struct spa_pod_parser _p; \
|
|
spa_pod_parser_pod(&_p, pod); \
|
|
spa_pod_parser_get_object(&_p,type,id,##__VA_ARGS__); \
|
|
})
|
|
|
|
#define spa_pod_parse_struct(pod,...) \
|
|
({ \
|
|
struct spa_pod_parser _p; \
|
|
spa_pod_parser_pod(&_p, pod); \
|
|
spa_pod_parser_get_struct(&_p,##__VA_ARGS__); \
|
|
})
|
|
|
|
/**
|
|
* \}
|
|
*/
|
|
|
|
#ifdef __cplusplus
|
|
} /* extern "C" */
|
|
#endif
|
|
|
|
#endif /* SPA_POD_PARSER_H */
|