pod-builder: make more generic builder

Make a vararg based builder that produces much smaller code.
Catch demarshal errors.
Simplify array handling
This commit is contained in:
Wim Taymans 2017-03-07 17:23:35 +01:00
parent f92b68c3c3
commit 78a3cd61b8
9 changed files with 862 additions and 637 deletions

View file

@ -39,6 +39,8 @@ typedef struct _SpaPODBuilder {
uint32_t offset;
SpaPODFrame *stack;
uint32_t (*write) (struct _SpaPODBuilder *builder, uint32_t ref, const void *data, uint32_t size);
bool in_array;
bool first;
} SpaPODBuilder;
#define SPA_POD_BUILDER_DEREF(b,ref,type) SPA_MEMBER ((b)->data, (ref), type)
@ -54,23 +56,6 @@ spa_pod_builder_init (SpaPODBuilder *builder,
builder->stack = NULL;
}
static inline bool
spa_pod_builder_in_array (SpaPODBuilder *builder, bool *first)
{
SpaPODFrame *f;
if ((f = builder->stack)) {
if (f->pod.type == SPA_POD_TYPE_ARRAY) {
*first = f->pod.size == 0;
return true;
}
if (f->pod.type == SPA_POD_TYPE_PROP) {
*first = f->pod.size == (sizeof (SpaPODPropBody) - sizeof(SpaPOD));
return true;
}
}
return false;
}
static inline uint32_t
spa_pod_builder_push (SpaPODBuilder *builder,
SpaPODFrame *frame,
@ -81,6 +66,8 @@ spa_pod_builder_push (SpaPODBuilder *builder,
frame->pod = *pod;
frame->ref = ref;
builder->stack = frame;
builder->in_array = builder->first = (pod->type == SPA_POD_TYPE_ARRAY ||
pod->type == SPA_POD_TYPE_PROP);
return ref;
}
@ -110,6 +97,8 @@ spa_pod_builder_pop (SpaPODBuilder *builder,
memcpy (builder->data + frame->ref, &frame->pod, sizeof(SpaPOD));
}
builder->stack = frame->parent;
builder->in_array = (builder->stack && (builder->stack->pod.type == SPA_POD_TYPE_ARRAY ||
builder->stack->pod.type == SPA_POD_TYPE_PROP));
spa_pod_builder_advance (builder, SPA_ROUND_UP_N(builder->offset, 8) - builder->offset, false);
}
@ -143,29 +132,21 @@ spa_pod_builder_string_body (SpaPODBuilder *builder,
return out;
}
static inline uint32_t
spa_pod_builder_pod (SpaPODBuilder *builder, uint32_t size, uint32_t type)
{
const SpaPOD p = { size, type };
return spa_pod_builder_raw (builder, &p, sizeof (p), false);
}
static inline uint32_t
spa_pod_builder_primitive (SpaPODBuilder *builder, const SpaPOD *p)
{
const void *data;
uint32_t size;
bool in_array, first = false;
in_array = spa_pod_builder_in_array (builder, &first);
if (in_array && !first) {
if (builder->in_array && !builder->first) {
data = SPA_POD_BODY_CONST (p);
size = SPA_POD_BODY_SIZE (p);
} else {
data = p;
size = SPA_POD_SIZE (p);
builder->first = false;
}
return spa_pod_builder_raw (builder, data, size, !in_array);
return spa_pod_builder_raw (builder, data, size, !builder->in_array);
}
static inline uint32_t
@ -348,12 +329,8 @@ spa_pod_builder_propv (SpaPODBuilder *builder,
spa_pod_builder_double (builder, va_arg (args, double));
break;
case SPA_POD_TYPE_STRING:
{
const char *str = va_arg (args, char *);
uint32_t len = va_arg (args, uint32_t);
spa_pod_builder_string_len (builder, str, len);
spa_pod_builder_string (builder, va_arg (args, char *));
break;
}
case SPA_POD_TYPE_RECTANGLE:
{
uint32_t width = va_arg (args, uint32_t), height = va_arg (args, uint32_t);
@ -414,6 +391,122 @@ spa_pod_builder_prop (SpaPODBuilder *builder,
va_end (args);
}
static inline void
spa_pod_builder_addv (SpaPODBuilder *builder,
uint32_t type,
va_list args)
{
uint32_t n_values = 0;
while (type != 0) {
switch (type) {
case SPA_POD_TYPE_INVALID:
break;
case SPA_POD_TYPE_BOOL:
spa_pod_builder_bool (builder, va_arg (args, int));
break;
case SPA_POD_TYPE_URI:
spa_pod_builder_uri (builder, va_arg (args, int32_t));
break;
case SPA_POD_TYPE_INT:
spa_pod_builder_int (builder, va_arg (args, int32_t));
break;
case SPA_POD_TYPE_LONG:
spa_pod_builder_long (builder, va_arg (args, int64_t));
break;
case SPA_POD_TYPE_FLOAT:
spa_pod_builder_float (builder, va_arg (args, double));
break;
case SPA_POD_TYPE_DOUBLE:
spa_pod_builder_double (builder, va_arg (args, double));
break;
case SPA_POD_TYPE_STRING:
spa_pod_builder_string (builder, va_arg (args, char *));
break;
case SPA_POD_TYPE_RECTANGLE:
{
uint32_t width = va_arg (args, uint32_t), height = va_arg (args, uint32_t);
spa_pod_builder_rectangle (builder, width, height);
break;
}
case SPA_POD_TYPE_FRACTION:
{
uint32_t num = va_arg (args, uint32_t), denom = va_arg (args, uint32_t);
spa_pod_builder_fraction (builder, num, denom);
break;
}
case SPA_POD_TYPE_BITMASK:
break;
case SPA_POD_TYPE_ARRAY:
{
SpaPODFrame *f = va_arg (args, SpaPODFrame *);
spa_pod_builder_push_array (builder, f);
break;
}
case SPA_POD_TYPE_STRUCT:
{
SpaPODFrame *f = va_arg (args, SpaPODFrame *);
spa_pod_builder_push_struct (builder, f);
break;
}
case SPA_POD_TYPE_OBJECT:
{
SpaPODFrame *f = va_arg (args, SpaPODFrame *);
uint32_t id = va_arg (args, uint32_t);
uint32_t type = va_arg (args, uint32_t);
spa_pod_builder_push_object (builder, f, id, type);
break;
}
case SPA_POD_TYPE_PROP:
{
SpaPODFrame *f = va_arg (args, SpaPODFrame *);
uint32_t key = va_arg (args, uint32_t);
uint32_t flags = va_arg (args, uint32_t);
type = va_arg (args, uint32_t);
n_values = va_arg (args, uint32_t);
spa_pod_builder_push_prop (builder, f, key, flags);
break;
}
case -SPA_POD_TYPE_ARRAY:
case -SPA_POD_TYPE_STRUCT:
case -SPA_POD_TYPE_OBJECT:
case -SPA_POD_TYPE_PROP:
{
SpaPODFrame *f = va_arg (args, SpaPODFrame *);
spa_pod_builder_pop (builder, f);
break;
}
case SPA_POD_TYPE_BYTES:
{
void *value = va_arg (args, void *);
uint32_t size = va_arg (args, uint32_t);
spa_pod_builder_bytes (builder, value, size);
break;
}
case SPA_POD_TYPE_POD:
{
SpaPOD *value = va_arg (args, SpaPOD *);
spa_pod_builder_raw (builder, value, SPA_POD_SIZE (value), true);
break;
}
}
if (n_values > 0)
n_values--;
else
type = va_arg (args, uint32_t);
}
}
static inline void
spa_pod_builder_add (SpaPODBuilder *builder,
uint32_t type, ...)
{
va_list args;
va_start (args, type);
spa_pod_builder_addv (builder, type, args);
va_end (args);
}
#ifdef __cplusplus
} /* extern "C" */
#endif

View file

@ -48,7 +48,8 @@ typedef enum {
SPA_POD_TYPE_STRUCT,
SPA_POD_TYPE_OBJECT,
SPA_POD_TYPE_PROP,
SPA_POD_TYPE_BYTES
SPA_POD_TYPE_BYTES,
SPA_POD_TYPE_POD
} SpaPODType;
typedef struct {
@ -71,16 +72,6 @@ typedef struct {
int32_t value;
} SpaPODInt;
static inline bool
spa_pod_get_int (SpaPOD **pod, int32_t *val)
{
if (*pod == NULL || (*pod)->type != SPA_POD_TYPE_INT)
return false;
*val = ((SpaPODInt *)(*pod))->value;
*pod = SPA_MEMBER (*pod, SPA_ROUND_UP_N (SPA_POD_SIZE (*pod), 8), SpaPOD);
return true;
}
typedef SpaPODInt SpaPODBool;
typedef SpaPODInt SpaPODURI;
@ -89,16 +80,6 @@ typedef struct {
int64_t value;
} SpaPODLong;
static inline bool
spa_pod_get_long (SpaPOD **pod, int64_t *val)
{
if (*pod == NULL || (*pod)->type != SPA_POD_TYPE_LONG)
return false;
*val = ((SpaPODLong *)*pod)->value;
*pod = SPA_MEMBER (*pod, SPA_ROUND_UP_N (SPA_POD_SIZE (*pod), 8), SpaPOD);
return true;
}
typedef struct {
SpaPOD pod;
float value;
@ -114,16 +95,6 @@ typedef struct {
/* value here */
} SpaPODString;
static inline bool
spa_pod_get_string (SpaPOD **pod, const char **val)
{
if (*pod == NULL || (*pod)->type != SPA_POD_TYPE_STRING)
return false;
*val = SPA_POD_CONTENTS (SpaPODString, *pod);
*pod = SPA_MEMBER (*pod, SPA_ROUND_UP_N (SPA_POD_SIZE (*pod), 8), SpaPOD);
return true;
}
typedef struct {
SpaPOD pod;
/* value here */
@ -159,16 +130,6 @@ typedef struct {
/* one or more SpaPOD follow */
} SpaPODStruct;
static inline bool
spa_pod_get_struct (SpaPOD **pod, SpaPOD **val)
{
if (*pod == NULL || (*pod)->type != SPA_POD_TYPE_STRUCT)
return false;
*val = *pod;
*pod = SPA_MEMBER (*pod, SPA_ROUND_UP_N (SPA_POD_SIZE (*pod), 8), SpaPOD);
return true;
}
typedef struct {
uint32_t key;
#define SPA_POD_PROP_RANGE_NONE 0
@ -207,28 +168,6 @@ typedef struct {
SpaPODObjectBody body;
} SpaPODObject;
static inline bool
spa_pod_get_object (SpaPOD **pod, const SpaPOD **val)
{
if (*pod == NULL || (*pod)->type != SPA_POD_TYPE_OBJECT)
return false;
*val = *pod;
*pod = SPA_MEMBER (*pod, SPA_ROUND_UP_N (SPA_POD_SIZE (*pod), 8), SpaPOD);
return true;
}
static inline bool
spa_pod_get_bytes (SpaPOD **pod, const void **val, uint32_t *size)
{
if (*pod == NULL || (*pod)->type != SPA_POD_TYPE_BYTES)
return false;
*val = SPA_POD_CONTENTS (SpaPODBytes, *pod);
*size = SPA_POD_SIZE (*pod);
*pod = SPA_MEMBER (*pod, SPA_ROUND_UP_N (SPA_POD_SIZE (*pod), 8), SpaPOD);
return true;
}
#define SPA_POD_ARRAY_BODY_FOREACH(body, _size, iter) \
for ((iter) = SPA_MEMBER ((body), sizeof(SpaPODArrayBody), __typeof__(*(iter))); \
(iter) < SPA_MEMBER ((body), (_size), __typeof__(*(iter))); \

View file

@ -102,7 +102,7 @@ static const struct _test_format {
SPA_POD_TYPE_PROP } ,
{ SPA_PROP_ID_VIDEO_SIZE, SPA_POD_PROP_RANGE_MIN_MAX | SPA_POD_PROP_FLAG_UNSET,
{ sizeof (SpaRectangle), SPA_POD_TYPE_RECTANGLE } }, },
{ { 320, 240 },
{ { 320, 243 },
{ 1, 1 },
{ INT32_MAX, INT32_MAX } },
@ -125,8 +125,7 @@ main (int argc, char *argv[])
SpaFormat *fmt;
off_t o;
b.data = buffer;
b.size = 1024;
spa_pod_builder_init (&b, buffer, sizeof (buffer));
fmt = SPA_MEMBER (buffer, spa_pod_builder_push_format (&b, &frame[0],
SPA_MEDIA_TYPE_VIDEO,
@ -159,9 +158,7 @@ main (int argc, char *argv[])
spa_debug_pod (&fmt->pod);
memset (&b, 0, sizeof(b));
b.data = buffer;
b.size = 1024;
spa_pod_builder_init (&b, buffer, sizeof (buffer));
o = spa_pod_builder_format (&b, SPA_MEDIA_TYPE_VIDEO, SPA_MEDIA_SUBTYPE_RAW,
SPA_PROP_ID_VIDEO_FORMAT, SPA_POD_TYPE_INT,
@ -171,7 +168,7 @@ main (int argc, char *argv[])
SPA_VIDEO_FORMAT_I420,
SPA_VIDEO_FORMAT_YUY2,
SPA_PROP_ID_VIDEO_SIZE , SPA_POD_TYPE_RECTANGLE,
320, 240,
320, 241,
SPA_POD_PROP_FLAG_UNSET |
SPA_POD_PROP_RANGE_MIN_MAX,
1, 1,
@ -187,6 +184,44 @@ main (int argc, char *argv[])
spa_debug_pod (&fmt->pod);
spa_debug_format (fmt);
spa_pod_builder_init (&b, buffer, sizeof (buffer));
spa_pod_builder_add (&b,
SPA_POD_TYPE_OBJECT, &frame[0], 0, 0,
SPA_POD_TYPE_INT, SPA_MEDIA_TYPE_VIDEO,
SPA_POD_TYPE_INT, SPA_MEDIA_SUBTYPE_RAW,
SPA_POD_TYPE_PROP, &frame[1],
SPA_PROP_ID_VIDEO_FORMAT, SPA_POD_PROP_FLAG_UNSET |
SPA_POD_PROP_RANGE_ENUM,
SPA_POD_TYPE_INT, 3,
SPA_VIDEO_FORMAT_I420,
SPA_VIDEO_FORMAT_I420,
SPA_VIDEO_FORMAT_YUY2,
-SPA_POD_TYPE_PROP, &frame[1],
SPA_POD_TYPE_PROP, &frame[1],
SPA_PROP_ID_VIDEO_SIZE, SPA_POD_PROP_FLAG_UNSET |
SPA_POD_PROP_RANGE_MIN_MAX,
SPA_POD_TYPE_RECTANGLE, 3,
320, 242,
1, 1,
INT32_MAX, INT32_MAX,
-SPA_POD_TYPE_PROP, &frame[1],
SPA_POD_TYPE_PROP, &frame[1],
SPA_PROP_ID_VIDEO_FRAMERATE, SPA_POD_PROP_FLAG_UNSET |
SPA_POD_PROP_RANGE_MIN_MAX,
SPA_POD_TYPE_FRACTION, 3,
25, 1,
0, 1,
INT32_MAX, 1,
-SPA_POD_TYPE_PROP, &frame[1],
-SPA_POD_TYPE_OBJECT, &frame[0],
0);
spa_pod_builder_pop (&b, &frame[0]);
fmt = SPA_MEMBER (buffer, o, SpaFormat);
spa_debug_pod (&fmt->pod);
spa_debug_format (fmt);
spa_debug_pod (&test_format.fmt.pod);
spa_debug_format (&test_format.fmt);