mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-03-30 11:10:29 -04:00
pod: improve parser and builder
Remove the spa_pod_iter helpers Remove builder/parser vararg recurse option, you have to manually recurse into structures when needed. This simplifies things a lot. Pass spa_pod_frames to builder and parser explicitly, we don't have to keep an internal stack anymore. The parser is now almost a mirror image of the builder. Make the parser safer when iterating over objects, add functions to check and get pod contents in a safe way. Make the builder return errno style results on errors Improve performance of object properties when they are stored and retrieved in the same order. Add many more tests for the builder and parser Add some benchmarks
This commit is contained in:
parent
878ae769ef
commit
351fb9ce29
36 changed files with 1605 additions and 973 deletions
|
|
@ -31,37 +31,31 @@ extern "C" {
|
|||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <spa/pod/pod.h>
|
||||
|
||||
struct spa_pod_frame {
|
||||
struct spa_pod pod;
|
||||
uint32_t ref;
|
||||
uint32_t _padding;
|
||||
};
|
||||
#include <spa/pod/iter.h>
|
||||
|
||||
struct spa_pod_builder_state {
|
||||
uint32_t offset;
|
||||
#define SPA_POD_BUILDER_FLAG_BODY (1<<0)
|
||||
#define SPA_POD_BUILDER_FLAG_FIRST (1<<1)
|
||||
#define SPA_POD_BUILDER_FLAG_OBJECT (1<<2)
|
||||
#define SPA_POD_BUILDER_FLAG_SEQUENCE (1<<3)
|
||||
#define SPA_POD_BUILDER_FLAG_HEADER (1<<4)
|
||||
uint32_t flags;
|
||||
uint32_t depth;
|
||||
uint32_t _padding;
|
||||
struct spa_pod_frame *frame;
|
||||
};
|
||||
|
||||
struct spa_pod_builder;
|
||||
|
||||
struct spa_pod_builder_callbacks {
|
||||
#define SPA_VERSION_POD_BUILDER_CALLBACKS 0
|
||||
uint32_t version;
|
||||
int (*overflow) (void *callbacks_data, uint32_t size);
|
||||
};
|
||||
|
||||
struct spa_pod_builder {
|
||||
void *data;
|
||||
uint32_t size;
|
||||
uint32_t _padding;
|
||||
|
||||
uint32_t (*write) (struct spa_pod_builder *builder, const void *data, uint32_t size);
|
||||
void * (*deref) (struct spa_pod_builder *builder, uint32_t ref, bool safe);
|
||||
void (*reset) (struct spa_pod_builder *builder, struct spa_pod_builder_state *state);
|
||||
|
||||
struct spa_pod_builder_state state;
|
||||
struct spa_pod_frame frame[SPA_POD_MAX_DEPTH];
|
||||
const struct spa_pod_builder_callbacks *callbacks;
|
||||
void *callbacks_data;
|
||||
};
|
||||
|
||||
#define SPA_POD_BUILDER_INIT(buffer,size) (struct spa_pod_builder){ buffer, size, }
|
||||
|
|
@ -75,10 +69,7 @@ spa_pod_builder_get_state(struct spa_pod_builder *builder, struct spa_pod_builde
|
|||
static inline void
|
||||
spa_pod_builder_reset(struct spa_pod_builder *builder, struct spa_pod_builder_state *state)
|
||||
{
|
||||
if (builder->reset)
|
||||
builder->reset(builder, state);
|
||||
else
|
||||
builder->state = *state;
|
||||
builder->state = *state;
|
||||
}
|
||||
|
||||
static inline void spa_pod_builder_init(struct spa_pod_builder *builder, void *data, uint32_t size)
|
||||
|
|
@ -86,128 +77,97 @@ static inline void spa_pod_builder_init(struct spa_pod_builder *builder, void *d
|
|||
*builder = SPA_POD_BUILDER_INIT(data, size);
|
||||
}
|
||||
|
||||
static inline struct spa_pod_frame *
|
||||
spa_pod_builder_top(struct spa_pod_builder *builder)
|
||||
static inline struct spa_pod *
|
||||
spa_pod_builder_deref(struct spa_pod_builder *builder, uint32_t offset, uint32_t size)
|
||||
{
|
||||
return builder->state.depth > 0 ? &builder->frame[builder->state.depth-1] : NULL;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
spa_pod_builder_deref_checked(struct spa_pod_builder *builder, uint32_t ref, bool safe)
|
||||
{
|
||||
if (ref == SPA_ID_INVALID)
|
||||
return NULL;
|
||||
else if (builder->deref)
|
||||
return builder->deref(builder, ref, safe);
|
||||
else if (ref + 8 <= builder->size) {
|
||||
struct spa_pod *pod = SPA_MEMBER(builder->data, ref, struct spa_pod);
|
||||
if (!safe || SPA_POD_SIZE(pod) <= builder->size)
|
||||
return (void *) pod;
|
||||
if (offset + 8 <= size) {
|
||||
struct spa_pod *pod = SPA_MEMBER(builder->data, offset, struct spa_pod);
|
||||
if (offset + SPA_POD_SIZE(pod) <= size)
|
||||
return pod;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
spa_pod_builder_deref(struct spa_pod_builder *builder, uint32_t ref)
|
||||
static inline struct spa_pod *
|
||||
spa_pod_builder_frame(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
|
||||
{
|
||||
return spa_pod_builder_deref_checked(builder, ref, false);
|
||||
return spa_pod_builder_deref(builder, frame->offset, builder->size);
|
||||
}
|
||||
|
||||
static inline void
|
||||
spa_pod_builder_update_frame(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
|
||||
{
|
||||
switch (frame->pod.type) {
|
||||
case SPA_TYPE_Array:
|
||||
case SPA_TYPE_Choice:
|
||||
builder->state.flags = SPA_POD_BUILDER_FLAG_BODY;
|
||||
break;
|
||||
case SPA_TYPE_Object:
|
||||
builder->state.flags = SPA_POD_BUILDER_FLAG_OBJECT;
|
||||
break;
|
||||
case SPA_TYPE_Sequence:
|
||||
builder->state.flags = SPA_POD_BUILDER_FLAG_SEQUENCE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
spa_pod_builder_push(struct spa_pod_builder *builder,
|
||||
struct spa_pod_frame *frame,
|
||||
const struct spa_pod *pod,
|
||||
uint32_t ref)
|
||||
uint32_t offset)
|
||||
{
|
||||
struct spa_pod_frame *frame = &builder->frame[builder->state.depth++];
|
||||
frame->pod = *pod;
|
||||
frame->ref = ref;
|
||||
spa_pod_builder_update_frame(builder, frame);
|
||||
if (builder->state.flags & SPA_POD_BUILDER_FLAG_BODY)
|
||||
SPA_FLAG_SET(builder->state.flags, SPA_POD_BUILDER_FLAG_FIRST);
|
||||
return ref;
|
||||
frame->offset = offset;
|
||||
frame->parent = builder->state.frame;
|
||||
frame->flags = builder->state.flags;
|
||||
builder->state.frame = frame;
|
||||
|
||||
if (frame->pod.type == SPA_TYPE_Array || frame->pod.type == SPA_TYPE_Choice)
|
||||
builder->state.flags = SPA_POD_BUILDER_FLAG_FIRST | SPA_POD_BUILDER_FLAG_BODY;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
spa_pod_builder_raw(struct spa_pod_builder *builder, const void *data, uint32_t size)
|
||||
static inline int spa_pod_builder_raw(struct spa_pod_builder *builder, const void *data, uint32_t size)
|
||||
{
|
||||
uint32_t i, ref;
|
||||
int res = 0;
|
||||
struct spa_pod_frame *f;
|
||||
uint32_t offset = builder->state.offset;
|
||||
|
||||
if (builder->write) {
|
||||
ref = builder->write(builder, data, size);
|
||||
} else {
|
||||
ref = builder->state.offset;
|
||||
if (ref + size > builder->size)
|
||||
ref = SPA_ID_INVALID;
|
||||
if (offset + size > builder->size) {
|
||||
if (builder->callbacks && builder->callbacks->overflow)
|
||||
res = builder->callbacks->overflow(builder->callbacks_data, offset + size);
|
||||
else
|
||||
memcpy(SPA_MEMBER(builder->data, ref, void), data, size);
|
||||
res = -ENOSPC;
|
||||
}
|
||||
if (res == 0)
|
||||
memcpy(SPA_MEMBER(builder->data, offset, void), data, size);
|
||||
|
||||
builder->state.offset += size;
|
||||
|
||||
for (i = 0; i < builder->state.depth; i++)
|
||||
builder->frame[i].pod.size += size;
|
||||
for (f = builder->state.frame; f ; f = f->parent)
|
||||
f->pod.size += size;
|
||||
|
||||
return ref;
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline void spa_pod_builder_pad(struct spa_pod_builder *builder, uint32_t size)
|
||||
static inline int spa_pod_builder_pad(struct spa_pod_builder *builder, uint32_t size)
|
||||
{
|
||||
uint64_t zeroes = 0;
|
||||
size = SPA_ROUND_UP_N(size, 8) - size;
|
||||
if (size)
|
||||
spa_pod_builder_raw(builder, &zeroes, size);
|
||||
SPA_FLAG_UNSET(builder->state.flags, SPA_POD_BUILDER_FLAG_HEADER);
|
||||
return size ? spa_pod_builder_raw(builder, &zeroes, size) : 0;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
static inline int
|
||||
spa_pod_builder_raw_padded(struct spa_pod_builder *builder, const void *data, uint32_t size)
|
||||
{
|
||||
uint32_t ref = size ? spa_pod_builder_raw(builder, data, size) : SPA_ID_INVALID;
|
||||
spa_pod_builder_pad(builder, size);
|
||||
return ref;
|
||||
int r, res = spa_pod_builder_raw(builder, data, size);
|
||||
if ((r = spa_pod_builder_pad(builder, size)) < 0)
|
||||
res = r;
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline void *spa_pod_builder_pop(struct spa_pod_builder *builder)
|
||||
static inline void *spa_pod_builder_pop(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
|
||||
{
|
||||
struct spa_pod_frame *frame;
|
||||
struct spa_pod *pod;
|
||||
|
||||
frame = &builder->frame[--builder->state.depth];
|
||||
if ((pod = (struct spa_pod *) spa_pod_builder_deref_checked(builder, frame->ref, true)) != NULL)
|
||||
if ((pod = (struct spa_pod *) spa_pod_builder_frame(builder, frame)) != NULL)
|
||||
*pod = frame->pod;
|
||||
|
||||
if ((frame = spa_pod_builder_top(builder)) != NULL)
|
||||
spa_pod_builder_update_frame(builder, frame);
|
||||
else
|
||||
builder->state.flags = 0;
|
||||
|
||||
builder->state.frame = frame->parent;
|
||||
builder->state.flags = frame->flags;
|
||||
spa_pod_builder_pad(builder, builder->state.offset);
|
||||
|
||||
return pod;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
static inline int
|
||||
spa_pod_builder_primitive(struct spa_pod_builder *builder, const struct spa_pod *p)
|
||||
{
|
||||
const void *data;
|
||||
uint32_t size, ref;
|
||||
uint32_t size;
|
||||
int r, res;
|
||||
|
||||
if (builder->state.flags == SPA_POD_BUILDER_FLAG_BODY) {
|
||||
data = SPA_POD_BODY_CONST(p);
|
||||
|
|
@ -217,18 +177,18 @@ spa_pod_builder_primitive(struct spa_pod_builder *builder, const struct spa_pod
|
|||
size = SPA_POD_SIZE(p);
|
||||
SPA_FLAG_UNSET(builder->state.flags, SPA_POD_BUILDER_FLAG_FIRST);
|
||||
}
|
||||
ref = spa_pod_builder_raw(builder, data, size);
|
||||
res = spa_pod_builder_raw(builder, data, size);
|
||||
if (builder->state.flags != SPA_POD_BUILDER_FLAG_BODY)
|
||||
spa_pod_builder_pad(builder, size);
|
||||
|
||||
return ref;
|
||||
if ((r = spa_pod_builder_pad(builder, size)) < 0)
|
||||
res = r;
|
||||
return res;
|
||||
}
|
||||
|
||||
#define SPA_POD_INIT(size,type) (struct spa_pod) { size, type }
|
||||
|
||||
#define SPA_POD_INIT_None() SPA_POD_INIT(0, SPA_TYPE_None)
|
||||
|
||||
static inline uint32_t spa_pod_builder_none(struct spa_pod_builder *builder)
|
||||
static inline int spa_pod_builder_none(struct spa_pod_builder *builder)
|
||||
{
|
||||
const struct spa_pod p = SPA_POD_INIT_None();
|
||||
return spa_pod_builder_primitive(builder, &p);
|
||||
|
|
@ -236,7 +196,7 @@ static inline uint32_t spa_pod_builder_none(struct spa_pod_builder *builder)
|
|||
|
||||
#define SPA_POD_INIT_Bool(val) (struct spa_pod_bool){ { sizeof(uint32_t), SPA_TYPE_Bool }, val ? 1 : 0, 0 }
|
||||
|
||||
static inline uint32_t spa_pod_builder_bool(struct spa_pod_builder *builder, bool val)
|
||||
static inline int spa_pod_builder_bool(struct spa_pod_builder *builder, bool val)
|
||||
{
|
||||
const struct spa_pod_bool p = SPA_POD_INIT_Bool(val);
|
||||
return spa_pod_builder_primitive(builder, &p.pod);
|
||||
|
|
@ -244,7 +204,7 @@ static inline uint32_t spa_pod_builder_bool(struct spa_pod_builder *builder, boo
|
|||
|
||||
#define SPA_POD_INIT_Id(val) (struct spa_pod_id){ { sizeof(uint32_t), SPA_TYPE_Id }, (uint32_t)val, 0 }
|
||||
|
||||
static inline uint32_t spa_pod_builder_id(struct spa_pod_builder *builder, uint32_t val)
|
||||
static inline int spa_pod_builder_id(struct spa_pod_builder *builder, uint32_t val)
|
||||
{
|
||||
const struct spa_pod_id p = SPA_POD_INIT_Id(val);
|
||||
return spa_pod_builder_primitive(builder, &p.pod);
|
||||
|
|
@ -252,7 +212,7 @@ static inline uint32_t spa_pod_builder_id(struct spa_pod_builder *builder, uint3
|
|||
|
||||
#define SPA_POD_INIT_Int(val) (struct spa_pod_int){ { sizeof(int32_t), SPA_TYPE_Int }, (int32_t)val, 0 }
|
||||
|
||||
static inline uint32_t spa_pod_builder_int(struct spa_pod_builder *builder, int32_t val)
|
||||
static inline int spa_pod_builder_int(struct spa_pod_builder *builder, int32_t val)
|
||||
{
|
||||
const struct spa_pod_int p = SPA_POD_INIT_Int(val);
|
||||
return spa_pod_builder_primitive(builder, &p.pod);
|
||||
|
|
@ -260,7 +220,7 @@ static inline uint32_t spa_pod_builder_int(struct spa_pod_builder *builder, int3
|
|||
|
||||
#define SPA_POD_INIT_Long(val) (struct spa_pod_long){ { sizeof(int64_t), SPA_TYPE_Long }, (int64_t)val }
|
||||
|
||||
static inline uint32_t spa_pod_builder_long(struct spa_pod_builder *builder, int64_t val)
|
||||
static inline int spa_pod_builder_long(struct spa_pod_builder *builder, int64_t val)
|
||||
{
|
||||
const struct spa_pod_long p = SPA_POD_INIT_Long(val);
|
||||
return spa_pod_builder_primitive(builder, &p.pod);
|
||||
|
|
@ -268,7 +228,7 @@ static inline uint32_t spa_pod_builder_long(struct spa_pod_builder *builder, int
|
|||
|
||||
#define SPA_POD_INIT_Float(val) (struct spa_pod_float){ { sizeof(float), SPA_TYPE_Float }, val }
|
||||
|
||||
static inline uint32_t spa_pod_builder_float(struct spa_pod_builder *builder, float val)
|
||||
static inline int spa_pod_builder_float(struct spa_pod_builder *builder, float val)
|
||||
{
|
||||
const struct spa_pod_float p = SPA_POD_INIT_Float(val);
|
||||
return spa_pod_builder_primitive(builder, &p.pod);
|
||||
|
|
@ -276,7 +236,7 @@ static inline uint32_t spa_pod_builder_float(struct spa_pod_builder *builder, fl
|
|||
|
||||
#define SPA_POD_INIT_Double(val) (struct spa_pod_double){ { sizeof(double), SPA_TYPE_Double }, val }
|
||||
|
||||
static inline uint32_t spa_pod_builder_double(struct spa_pod_builder *builder, double val)
|
||||
static inline int spa_pod_builder_double(struct spa_pod_builder *builder, double val)
|
||||
{
|
||||
const struct spa_pod_double p = SPA_POD_INIT_Double(val);
|
||||
return spa_pod_builder_primitive(builder, &p.pod);
|
||||
|
|
@ -284,29 +244,29 @@ static inline uint32_t spa_pod_builder_double(struct spa_pod_builder *builder, d
|
|||
|
||||
#define SPA_POD_INIT_String(len) (struct spa_pod_string){ { len, SPA_TYPE_String } }
|
||||
|
||||
static inline uint32_t
|
||||
static inline int
|
||||
spa_pod_builder_write_string(struct spa_pod_builder *builder, const char *str, uint32_t len)
|
||||
{
|
||||
uint32_t ref = 0;
|
||||
if (spa_pod_builder_raw(builder, str, len) == SPA_ID_INVALID)
|
||||
ref = SPA_ID_INVALID;
|
||||
if (spa_pod_builder_raw(builder, "", 1) == SPA_ID_INVALID)
|
||||
ref = SPA_ID_INVALID;
|
||||
spa_pod_builder_pad(builder, builder->state.offset);
|
||||
return ref;
|
||||
int r, res;
|
||||
res = spa_pod_builder_raw(builder, str, len);
|
||||
if ((r = spa_pod_builder_raw(builder, "", 1)) < 0)
|
||||
res = r;
|
||||
if ((r = spa_pod_builder_pad(builder, builder->state.offset)) < 0)
|
||||
res = r;
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
static inline int
|
||||
spa_pod_builder_string_len(struct spa_pod_builder *builder, const char *str, uint32_t len)
|
||||
{
|
||||
const struct spa_pod_string p = SPA_POD_INIT_String(len+1);
|
||||
uint32_t ref = spa_pod_builder_raw(builder, &p, sizeof(p));
|
||||
if (spa_pod_builder_write_string(builder, str, len) == SPA_ID_INVALID)
|
||||
ref = SPA_ID_INVALID;
|
||||
return ref;
|
||||
int r, res = spa_pod_builder_raw(builder, &p, sizeof(p));
|
||||
if ((r = spa_pod_builder_write_string(builder, str, len)) < 0)
|
||||
res = r;
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline uint32_t spa_pod_builder_string(struct spa_pod_builder *builder, const char *str)
|
||||
static inline int spa_pod_builder_string(struct spa_pod_builder *builder, const char *str)
|
||||
{
|
||||
uint32_t len = str ? strlen(str) : 0;
|
||||
return spa_pod_builder_string_len(builder, str ? str : "", len);
|
||||
|
|
@ -314,19 +274,19 @@ static inline uint32_t spa_pod_builder_string(struct spa_pod_builder *builder, c
|
|||
|
||||
#define SPA_POD_INIT_Bytes(len) (struct spa_pod_bytes){ { len, SPA_TYPE_Bytes } }
|
||||
|
||||
static inline uint32_t
|
||||
static inline int
|
||||
spa_pod_builder_bytes(struct spa_pod_builder *builder, const void *bytes, uint32_t len)
|
||||
{
|
||||
const struct spa_pod_bytes p = SPA_POD_INIT_Bytes(len);
|
||||
uint32_t ref = spa_pod_builder_raw(builder, &p, sizeof(p));
|
||||
if (spa_pod_builder_raw_padded(builder, bytes, len) == SPA_ID_INVALID)
|
||||
ref = SPA_ID_INVALID;
|
||||
return ref;
|
||||
int r, res = spa_pod_builder_raw(builder, &p, sizeof(p));
|
||||
if ((r = spa_pod_builder_raw_padded(builder, bytes, len)) < 0)
|
||||
res = r;
|
||||
return res;
|
||||
}
|
||||
|
||||
#define SPA_POD_INIT_Pointer(type,value) (struct spa_pod_pointer){ { sizeof(struct spa_pod_pointer_body), SPA_TYPE_Pointer }, { type, 0, value } }
|
||||
|
||||
static inline uint32_t
|
||||
static inline int
|
||||
spa_pod_builder_pointer(struct spa_pod_builder *builder, uint32_t type, const void *val)
|
||||
{
|
||||
const struct spa_pod_pointer p = SPA_POD_INIT_Pointer(type, val);
|
||||
|
|
@ -335,7 +295,7 @@ spa_pod_builder_pointer(struct spa_pod_builder *builder, uint32_t type, const vo
|
|||
|
||||
#define SPA_POD_INIT_Fd(fd) (struct spa_pod_fd){ { sizeof(int64_t), SPA_TYPE_Fd }, fd }
|
||||
|
||||
static inline uint32_t spa_pod_builder_fd(struct spa_pod_builder *builder, int64_t fd)
|
||||
static inline int spa_pod_builder_fd(struct spa_pod_builder *builder, int64_t fd)
|
||||
{
|
||||
const struct spa_pod_fd p = SPA_POD_INIT_Fd(fd);
|
||||
return spa_pod_builder_primitive(builder, &p.pod);
|
||||
|
|
@ -343,7 +303,7 @@ static inline uint32_t spa_pod_builder_fd(struct spa_pod_builder *builder, int64
|
|||
|
||||
#define SPA_POD_INIT_Rectangle(val) (struct spa_pod_rectangle){ { sizeof(struct spa_rectangle), SPA_TYPE_Rectangle }, val }
|
||||
|
||||
static inline uint32_t
|
||||
static inline int
|
||||
spa_pod_builder_rectangle(struct spa_pod_builder *builder, uint32_t width, uint32_t height)
|
||||
{
|
||||
const struct spa_pod_rectangle p = SPA_POD_INIT_Rectangle(SPA_RECTANGLE(width, height));
|
||||
|
|
@ -352,25 +312,26 @@ spa_pod_builder_rectangle(struct spa_pod_builder *builder, uint32_t width, uint3
|
|||
|
||||
#define SPA_POD_INIT_Fraction(val) (struct spa_pod_fraction){ { sizeof(struct spa_fraction), SPA_TYPE_Fraction }, val }
|
||||
|
||||
static inline uint32_t
|
||||
static inline int
|
||||
spa_pod_builder_fraction(struct spa_pod_builder *builder, uint32_t num, uint32_t denom)
|
||||
{
|
||||
const struct spa_pod_fraction p = SPA_POD_INIT_Fraction(SPA_FRACTION(num, denom));
|
||||
return spa_pod_builder_primitive(builder, &p.pod);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
spa_pod_builder_push_array(struct spa_pod_builder *builder)
|
||||
static inline int
|
||||
spa_pod_builder_push_array(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
|
||||
{
|
||||
const struct spa_pod_array p =
|
||||
{ {sizeof(struct spa_pod_array_body) - sizeof(struct spa_pod), SPA_TYPE_Array},
|
||||
{{0, 0}} };
|
||||
return spa_pod_builder_push(builder, &p.pod,
|
||||
spa_pod_builder_raw(builder, &p,
|
||||
sizeof(p) - sizeof(struct spa_pod)));
|
||||
uint32_t offset = builder->state.offset;
|
||||
int res = spa_pod_builder_raw(builder, &p, sizeof(p) - sizeof(struct spa_pod));
|
||||
spa_pod_builder_push(builder, frame, &p.pod, offset);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
static inline int
|
||||
spa_pod_builder_array(struct spa_pod_builder *builder,
|
||||
uint32_t child_size, uint32_t child_type, uint32_t n_elems, const void *elems)
|
||||
{
|
||||
|
|
@ -378,10 +339,10 @@ spa_pod_builder_array(struct spa_pod_builder *builder,
|
|||
{(uint32_t)(sizeof(struct spa_pod_array_body) + n_elems * child_size), SPA_TYPE_Array},
|
||||
{{child_size, child_type}}
|
||||
};
|
||||
uint32_t ref = spa_pod_builder_raw(builder, &p, sizeof(p));
|
||||
if (spa_pod_builder_raw_padded(builder, elems, child_size * n_elems) == SPA_ID_INVALID)
|
||||
ref = SPA_ID_INVALID;
|
||||
return ref;
|
||||
int r, res = spa_pod_builder_raw(builder, &p, sizeof(p));
|
||||
if ((r = spa_pod_builder_raw_padded(builder, elems, child_size * n_elems)) < 0)
|
||||
res = r;
|
||||
return res;
|
||||
}
|
||||
|
||||
#define SPA_POD_INIT_CHOICE_BODY(type, flags, child_size, child_type) \
|
||||
|
|
@ -392,69 +353,74 @@ spa_pod_builder_array(struct spa_pod_builder *builder,
|
|||
{ { { n_vals * sizeof(ctype) + sizeof(struct spa_pod_choice_body), SPA_TYPE_Choice }, \
|
||||
{ type, 0, { sizeof(ctype), child_type } } }, { __VA_ARGS__ } }
|
||||
|
||||
static inline uint32_t
|
||||
spa_pod_builder_push_choice(struct spa_pod_builder *builder, uint32_t type, uint32_t flags)
|
||||
static inline int
|
||||
spa_pod_builder_push_choice(struct spa_pod_builder *builder, struct spa_pod_frame *frame,
|
||||
uint32_t type, uint32_t flags)
|
||||
{
|
||||
const struct spa_pod_choice p =
|
||||
{ {sizeof(struct spa_pod_choice_body) - sizeof(struct spa_pod), SPA_TYPE_Choice},
|
||||
{ type, flags, {0, 0}} };
|
||||
return spa_pod_builder_push(builder, &p.pod,
|
||||
spa_pod_builder_raw(builder, &p,
|
||||
sizeof(p) - sizeof(struct spa_pod)));
|
||||
uint32_t offset = builder->state.offset;
|
||||
int res = spa_pod_builder_raw(builder, &p, sizeof(p) - sizeof(struct spa_pod));
|
||||
spa_pod_builder_push(builder, frame, &p.pod, offset);
|
||||
return res;
|
||||
}
|
||||
|
||||
#define SPA_POD_INIT_Struct(size) (struct spa_pod_struct){ { size, SPA_TYPE_Struct } }
|
||||
|
||||
static inline uint32_t
|
||||
spa_pod_builder_push_struct(struct spa_pod_builder *builder)
|
||||
static inline int
|
||||
spa_pod_builder_push_struct(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
|
||||
{
|
||||
const struct spa_pod_struct p = SPA_POD_INIT_Struct(0);
|
||||
return spa_pod_builder_push(builder, &p.pod,
|
||||
spa_pod_builder_raw(builder, &p, sizeof(p)));
|
||||
uint32_t offset = builder->state.offset;
|
||||
int res = spa_pod_builder_raw(builder, &p, sizeof(p));
|
||||
spa_pod_builder_push(builder, frame, &p.pod, offset);
|
||||
return res;
|
||||
}
|
||||
|
||||
#define SPA_POD_INIT_Object(size,type,id,...) (struct spa_pod_object){ { size, SPA_TYPE_Object }, { type, id }, ##__VA_ARGS__ }
|
||||
|
||||
static inline uint32_t
|
||||
spa_pod_builder_push_object(struct spa_pod_builder *builder, uint32_t type, uint32_t id)
|
||||
static inline int
|
||||
spa_pod_builder_push_object(struct spa_pod_builder *builder, struct spa_pod_frame *frame,
|
||||
uint32_t type, uint32_t id)
|
||||
{
|
||||
const struct spa_pod_object p =
|
||||
SPA_POD_INIT_Object(sizeof(struct spa_pod_object_body), type, id);
|
||||
return spa_pod_builder_push(builder, &p.pod,
|
||||
spa_pod_builder_raw(builder, &p, sizeof(p)));
|
||||
uint32_t offset = builder->state.offset;
|
||||
int res = spa_pod_builder_raw(builder, &p, sizeof(p));
|
||||
spa_pod_builder_push(builder, frame, &p.pod, offset);
|
||||
return res;
|
||||
}
|
||||
|
||||
#define SPA_POD_INIT_Prop(key,flags,size,type) \
|
||||
(struct spa_pod_prop){ key, flags, { size, type } }
|
||||
|
||||
static inline uint32_t
|
||||
static inline int
|
||||
spa_pod_builder_prop(struct spa_pod_builder *builder, uint32_t key, uint32_t flags)
|
||||
{
|
||||
const struct { uint32_t key; uint32_t flags; } p = { key, flags };
|
||||
uint32_t ref = spa_pod_builder_raw(builder, &p, sizeof(p));
|
||||
SPA_FLAG_SET(builder->state.flags, SPA_POD_BUILDER_FLAG_HEADER);
|
||||
return ref;
|
||||
return spa_pod_builder_raw(builder, &p, sizeof(p));
|
||||
}
|
||||
|
||||
#define SPA_POD_INIT_Sequence(size,unit) \
|
||||
(struct spa_pod_sequence){ { size, SPA_TYPE_Sequence}, {unit, 0 } }
|
||||
|
||||
static inline uint32_t
|
||||
spa_pod_builder_push_sequence(struct spa_pod_builder *builder, uint32_t unit)
|
||||
static inline int
|
||||
spa_pod_builder_push_sequence(struct spa_pod_builder *builder, struct spa_pod_frame *frame, uint32_t unit)
|
||||
{
|
||||
const struct spa_pod_sequence p =
|
||||
SPA_POD_INIT_Sequence(sizeof(struct spa_pod_sequence_body), unit);
|
||||
return spa_pod_builder_push(builder, &p.pod,
|
||||
spa_pod_builder_raw(builder, &p, sizeof(p)));
|
||||
uint32_t offset = builder->state.offset;
|
||||
int res = spa_pod_builder_raw(builder, &p, sizeof(p));
|
||||
spa_pod_builder_push(builder, frame, &p.pod, offset);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
spa_pod_builder_control(struct spa_pod_builder *builder, uint32_t offset, uint32_t type)
|
||||
{
|
||||
const struct { uint32_t offset; uint32_t type; } p = { offset, type };
|
||||
uint32_t ref = spa_pod_builder_raw(builder, &p, sizeof(p));
|
||||
SPA_FLAG_SET(builder->state.flags, SPA_POD_BUILDER_FLAG_HEADER);
|
||||
return ref;
|
||||
return spa_pod_builder_raw(builder, &p, sizeof(p));
|
||||
}
|
||||
|
||||
static inline uint32_t spa_choice_from_id(char id)
|
||||
|
|
@ -513,7 +479,7 @@ do { \
|
|||
spa_pod_builder_string_len(builder, strval, len); \
|
||||
break; \
|
||||
} \
|
||||
case 'z': \
|
||||
case 'y': \
|
||||
{ \
|
||||
void *ptr = va_arg(args, void *); \
|
||||
int len = va_arg(args, int); \
|
||||
|
|
@ -569,94 +535,66 @@ do { \
|
|||
} \
|
||||
} while(false)
|
||||
|
||||
static inline void *
|
||||
static inline int
|
||||
spa_pod_builder_addv(struct spa_pod_builder *builder, va_list args)
|
||||
{
|
||||
const char *format = "";
|
||||
void *top = NULL;
|
||||
do {
|
||||
int n_values = 1;
|
||||
bool do_pop = false;
|
||||
int res = 0;
|
||||
struct spa_pod_frame *f = builder->state.frame;
|
||||
uint32_t ftype = f ? f->pod.type : SPA_TYPE_None;
|
||||
|
||||
if (builder->state.flags == SPA_POD_BUILDER_FLAG_OBJECT) {
|
||||
do {
|
||||
const char *format;
|
||||
int n_values = 1;
|
||||
struct spa_pod_frame f;
|
||||
bool choice;
|
||||
|
||||
switch (ftype) {
|
||||
case SPA_TYPE_Object:
|
||||
{
|
||||
uint32_t key = va_arg(args, uint32_t);
|
||||
if (key == 0)
|
||||
break;
|
||||
if (key != SPA_ID_INVALID)
|
||||
spa_pod_builder_prop(builder, key, 0);
|
||||
goto exit;
|
||||
spa_pod_builder_prop(builder, key, 0);
|
||||
break;
|
||||
}
|
||||
else if (builder->state.flags == SPA_POD_BUILDER_FLAG_SEQUENCE) {
|
||||
case SPA_TYPE_Sequence:
|
||||
{
|
||||
uint32_t offset = va_arg(args, uint32_t);
|
||||
uint32_t type = va_arg(args, uint32_t);
|
||||
if (type == 0)
|
||||
break;
|
||||
if (type != SPA_ID_INVALID)
|
||||
spa_pod_builder_control(builder, offset, type);
|
||||
goto exit;
|
||||
spa_pod_builder_control(builder, offset, type);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if ((format = va_arg(args, const char *)) == NULL)
|
||||
break;
|
||||
|
||||
again:
|
||||
switch (*format) {
|
||||
case '{':
|
||||
{
|
||||
uint32_t type = va_arg(args, uint32_t);
|
||||
uint32_t id = va_arg(args, uint32_t);
|
||||
spa_pod_builder_push_object(builder, type, id);
|
||||
break;
|
||||
}
|
||||
case '[':
|
||||
spa_pod_builder_push_struct(builder);
|
||||
break;
|
||||
case '(':
|
||||
spa_pod_builder_push_array(builder);
|
||||
break;
|
||||
case '<':
|
||||
{
|
||||
uint32_t unit = va_arg(args, uint32_t);
|
||||
spa_pod_builder_push_sequence(builder, unit);
|
||||
break;
|
||||
}
|
||||
case '?':
|
||||
{
|
||||
uint32_t choice, flags = 0;
|
||||
|
||||
format++;
|
||||
choice = spa_choice_from_id(*format);
|
||||
choice = *format == '?';
|
||||
if (choice) {
|
||||
uint32_t type = spa_choice_from_id(*++format);
|
||||
if (*format != '\0')
|
||||
format++;
|
||||
|
||||
spa_pod_builder_push_choice(builder, choice, flags);
|
||||
spa_pod_builder_push_choice(builder, &f, type, 0);
|
||||
|
||||
n_values = va_arg(args, int);
|
||||
do_pop = true;
|
||||
goto do_collect;
|
||||
}
|
||||
case ']': case ')': case '>': case '}':
|
||||
top = spa_pod_builder_pop(builder);
|
||||
break;
|
||||
case ' ': case '\n': case '\t': case '\r':
|
||||
break;
|
||||
case '\0':
|
||||
if ((format = va_arg(args, const char *)) != NULL)
|
||||
goto again;
|
||||
continue;
|
||||
default:
|
||||
do_collect:
|
||||
while (n_values-- > 0)
|
||||
SPA_POD_BUILDER_COLLECT(builder, *format, args);
|
||||
if (do_pop)
|
||||
top = spa_pod_builder_pop(builder);
|
||||
break;
|
||||
}
|
||||
if (*format != '\0')
|
||||
format++;
|
||||
} while (format != NULL);
|
||||
while (n_values-- > 0)
|
||||
SPA_POD_BUILDER_COLLECT(builder, *format, args);
|
||||
|
||||
return top;
|
||||
if (choice)
|
||||
spa_pod_builder_pop(builder, &f);
|
||||
} while (true);
|
||||
|
||||
exit:
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline void *spa_pod_builder_add(struct spa_pod_builder *builder, ...)
|
||||
static inline int spa_pod_builder_add(struct spa_pod_builder *builder, ...)
|
||||
{
|
||||
void *res;
|
||||
int res;
|
||||
va_list args;
|
||||
|
||||
va_start(args, builder);
|
||||
|
|
@ -666,29 +604,35 @@ static inline void *spa_pod_builder_add(struct spa_pod_builder *builder, ...)
|
|||
return res;
|
||||
}
|
||||
|
||||
#define SPA_POD_Object(type,id,...) \
|
||||
"{", type, id, ##__VA_ARGS__, SPA_ID_INVALID, "}"
|
||||
|
||||
#define SPA_POD_Prop(key,...) \
|
||||
key, ##__VA_ARGS__
|
||||
|
||||
#define SPA_POD_Struct(...) \
|
||||
"[", ##__VA_ARGS__, "]"
|
||||
|
||||
#define SPA_POD_Sequence(unit,...) \
|
||||
"<", unit, ##__VA_ARGS__, 0, SPA_ID_INVALID, ">"
|
||||
|
||||
#define SPA_POD_Control(offset,type,...) \
|
||||
offset, type, ##__VA_ARGS__
|
||||
|
||||
#define spa_pod_builder_add_object(b,type,id,...) \
|
||||
spa_pod_builder_add(b, SPA_POD_Object(type,id,##__VA_ARGS__), NULL, NULL, NULL)
|
||||
({ \
|
||||
struct spa_pod_frame f; \
|
||||
spa_pod_builder_push_object(b, &f, type, id); \
|
||||
spa_pod_builder_add(b, ##__VA_ARGS__, 0); \
|
||||
spa_pod_builder_pop(b, &f); \
|
||||
})
|
||||
|
||||
#define spa_pod_builder_add_struct(b,...) \
|
||||
spa_pod_builder_add(b, SPA_POD_Struct(__VA_ARGS__), NULL, NULL, NULL)
|
||||
({ \
|
||||
struct spa_pod_frame f; \
|
||||
spa_pod_builder_push_struct(b, &f); \
|
||||
spa_pod_builder_add(b, ##__VA_ARGS__, NULL); \
|
||||
spa_pod_builder_pop(b, &f); \
|
||||
})
|
||||
|
||||
#define spa_pod_builder_add_sequence(b,unit,...) \
|
||||
spa_pod_builder_add(b, SPA_POD_Sequence(unit,__VA_ARGS__), NULL, NULL, NULL)
|
||||
({ \
|
||||
struct spa_pod_frame f; \
|
||||
spa_pod_builder_push_sequence(b, &f, unit); \
|
||||
spa_pod_builder_add(b, ##__VA_ARGS__, 0, 0); \
|
||||
spa_pod_builder_pop(b, &f); \
|
||||
})
|
||||
|
||||
#define SPA_CHOICE_RANGE(def,min,max) 3,(def),(min),(max)
|
||||
#define SPA_CHOICE_STEP(def,min,max,step) 4,(def),(min),(max),(step)
|
||||
|
|
@ -724,7 +668,7 @@ static inline void *spa_pod_builder_add(struct spa_pod_builder *builder, ...)
|
|||
#define SPA_POD_String(val) "s",val
|
||||
#define SPA_POD_Stringn(val,len) "S",val,len
|
||||
|
||||
#define SPA_POD_Bytes(val,len) "z",val,len
|
||||
#define SPA_POD_Bytes(val,len) "y",val,len
|
||||
|
||||
#define SPA_POD_Rectangle(val) "R", val
|
||||
#define SPA_POD_CHOICE_ENUM_Rectangle(n_vals,...) "?eR", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue