diff options
Diffstat (limited to 'third_party/pipewire/spa/pod/parser.h')
-rw-r--r-- | third_party/pipewire/spa/pod/parser.h | 583 |
1 files changed, 583 insertions, 0 deletions
diff --git a/third_party/pipewire/spa/pod/parser.h b/third_party/pipewire/spa/pod/parser.h new file mode 100644 index 0000000000..c0a3099da6 --- /dev/null +++ b/third_party/pipewire/spa/pod/parser.h @@ -0,0 +1,583 @@ +/* Spa + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#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, {} } + +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) +{ + if (offset + 8 <= size) { + struct spa_pod *pod = SPA_PTROFF(parser->data, offset, struct spa_pod); + if (offset + SPA_POD_SIZE(pod) <= size) + return 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_is_choice(pod) && + SPA_POD_CHOICE_TYPE(pod) == SPA_CHOICE_None && + spa_pod_parser_can_collect(SPA_POD_CHOICE_CHILD(pod), type)) + return true; + + 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': + return spa_pod_is_choice(pod); + 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 (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' && + SPA_POD_CHOICE_TYPE(pod) == SPA_CHOICE_None) + 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 */ |