Add new pod parser and builder

Add a new pod builder and parser that is less verbose and
a little more powerful.
This commit is contained in:
Wim Taymans 2017-09-21 18:57:41 +02:00
parent 3e49aec61b
commit 24d80e5c00
54 changed files with 3616 additions and 2817 deletions

View file

@ -50,18 +50,19 @@ spa_type_format_audio_map(struct spa_type_map *map, struct spa_type_format_audio
}
}
static inline bool
static inline int
spa_format_audio_raw_parse(const struct spa_format *format,
struct spa_audio_info_raw *info, struct spa_type_format_audio *type)
{
spa_format_query(format,
type->format, SPA_POD_TYPE_ID, &info->format,
type->flags, SPA_POD_TYPE_INT, &info->flags,
type->layout, SPA_POD_TYPE_INT, &info->layout,
type->rate, SPA_POD_TYPE_INT, &info->rate,
type->channels, SPA_POD_TYPE_INT, &info->channels,
type->channel_mask, SPA_POD_TYPE_INT, &info->channel_mask, 0);
return true;
struct spa_pod_parser prs;
spa_pod_parser_pod(&prs, &format->pod);
return spa_pod_parser_get(&prs,
":",type->format, "I", &info->format,
":",type->rate, "i", &info->rate,
":",type->channels, "i", &info->channels,
":",type->flags, "?i", &info->flags,
":",type->layout, "?i", &info->layout,
":",type->channel_mask, "?i", &info->channel_mask, NULL);
}
#ifdef __cplusplus

View file

@ -71,6 +71,7 @@ enum spa_result {
SPA_RESULT_OUT_OF_BUFFERS = -35,
SPA_RESULT_INCOMPATIBLE_PROPS = -36,
SPA_RESULT_INCOMPATIBLE_VERSION = -37,
SPA_RESULT_NOT_FOUND = -38,
};
#define SPA_ASYNC_BIT (1 << 30)
@ -89,11 +90,14 @@ enum spa_direction {
SPA_DIRECTION_OUTPUT = 1,
};
#define SPA_RECTANGLE(width,height) (struct spa_rectangle){ width, height }
struct spa_rectangle {
uint32_t width;
uint32_t height;
};
#define SPA_FRACTION(num,denom) (struct spa_fraction){ num, denom }
struct spa_fraction {
uint32_t num;
uint32_t denom;

View file

@ -48,11 +48,11 @@ spa_pod_builder_push_format(struct spa_pod_builder *builder,
spa_pod_builder_raw(builder, &p, sizeof(p)));
}
#define spa_pod_builder_format(b,f,format_type,media_type,media_subtype,...) \
spa_pod_builder_object(b, f, 0, format_type, \
SPA_POD_TYPE_ID,media_type, \
SPA_POD_TYPE_ID,media_subtype, \
## __VA_ARGS__)
#define spa_pod_builder_format(b,format_type,media_type,media_subtype,...) \
spa_pod_builder_object(b, 0, format_type, \
"I",media_type, \
"I",media_subtype, \
##__VA_ARGS__)
#ifdef __cplusplus
} /* extern "C" */

View file

@ -27,7 +27,7 @@ extern "C" {
#include <stdarg.h>
#include <spa/format.h>
#include <spa/pod-utils.h>
#include <spa/pod-parser.h>
#include <spa/type-map.h>
struct spa_type_media_type {
@ -149,22 +149,17 @@ spa_type_media_subtype_audio_map(struct spa_type_map *map,
#define SPA_FORMAT_MEDIA_TYPE(f) SPA_POD_VALUE(struct spa_pod_id, &f->body.media_type)
#define SPA_FORMAT_MEDIA_SUBTYPE(f) SPA_POD_VALUE(struct spa_pod_id, &f->body.media_subtype)
static inline struct spa_pod_prop *spa_format_find_prop(const struct spa_format *format,
uint32_t key)
#define spa_format_parse(format,...) \
({ \
struct spa_pod_parser __p; \
const struct spa_format *__format = format; \
spa_pod_parser_pod(&__p, &__format->pod); \
spa_pod_parser_get(&__p, "<", ##__VA_ARGS__, NULL); \
})
static inline struct spa_pod_prop *spa_format_find_prop(const struct spa_format *format, uint32_t key)
{
return spa_pod_contents_find_prop(&format->pod, sizeof(struct spa_format), key);
}
static inline uint32_t spa_format_query(const struct spa_format *format, uint32_t key, ...)
{
uint32_t count;
va_list args;
va_start(args, key);
count = spa_pod_contents_queryv(&format->pod, sizeof(struct spa_format), key, args);
va_end(args);
return count;
return spa_pod_contents_find_prop(&format->pod, sizeof(struct spa_format), key);
}
static inline int spa_format_fixate(struct spa_format *format)

View file

@ -91,7 +91,7 @@ static inline void spa_hook_remove(struct spa_hook *hook)
break; \
} \
} \
});
})
#define spa_hook_list_call(l,t,m,...) spa_hook_list_do_call(l,NULL,t,m,false,##__VA_ARGS__)
#define spa_hook_list_call_once(l,t,m,...) spa_hook_list_do_call(l,NULL,t,m,true,##__VA_ARGS__)

View file

@ -0,0 +1,67 @@
/* Spa
* Copyright (C) 2017 Wim Taymans <wim.taymans@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __SPA_JSON_BUILDER_H__
#define __SPA_JSON_BUILDER_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdarg.h>
#include <spa/defs.h>
struct spa_json_builder {
char *data;
int size;
int offset;
int (*printf) (void *user_data, const char *format, va_list args);
void *user_data;
};
static inline int spa_json_builder_printf(struct spa_json_builder *builder,
const char *format, ...)
{
va_list args;
int res;
va_start(args, format);
if (builder->printf)
res = builder->printf(builder->user_data, format, args);
else {
int size = builder->size;
int offset = builder->offset;
int remain = SPA_MAX(0, size - offset);
res = vsnprintf(&builder->data[offset], remain, format, args);
builder->offset += res;
if (builder->offset > size)
res = -1;
}
va_end(args);
return res;
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __SPA_JSON_BUILDER_H__ */

510
spa/include/spa/json.h Normal file
View file

@ -0,0 +1,510 @@
/* Spa
* Copyright (C) 2017 Wim Taymans <wim.taymans@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __SPA_JSON_H__
#define __SPA_JSON_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdarg.h>
#include <spa/defs.h>
struct spa_json_iter {
const char *start;
const char *cur;
const char *end;
int state;
int depth;
};
struct spa_json_chunk {
const char *value;
int len;
};
static inline int
spa_json_chunk_extract(struct spa_json_chunk *chunk, const char *template, ...);
enum spa_json_type {
SPA_JSON_TYPE_ANY = '-',
SPA_JSON_TYPE_CHUNK = 'c',
SPA_JSON_TYPE_INT = 'i',
SPA_JSON_TYPE_LONG = 'l',
SPA_JSON_TYPE_FLOAT = 'f',
SPA_JSON_TYPE_DOUBLE = 'd',
SPA_JSON_TYPE_STRING = 's',
SPA_JSON_TYPE_BOOL = 'b',
SPA_JSON_TYPE_RECTANGLE = 'R',
SPA_JSON_TYPE_FRACTION = 'F',
SPA_JSON_TYPE_OBJECT = 'o',
SPA_JSON_TYPE_ARRAY = 'a'
};
static inline bool spa_json_chunk_is_type(struct spa_json_chunk *chunk,
enum spa_json_type type)
{
switch (type) {
case SPA_JSON_TYPE_ANY:
case SPA_JSON_TYPE_CHUNK:
return true;
case SPA_JSON_TYPE_INT:
case SPA_JSON_TYPE_LONG:
case SPA_JSON_TYPE_FLOAT:
case SPA_JSON_TYPE_DOUBLE:
return (chunk->value[0] >= '0' && chunk->value[0] <= '9') ||
chunk->value[0] == '-' ;
case SPA_JSON_TYPE_STRING:
return chunk->value[0] == '\"';
case SPA_JSON_TYPE_BOOL:
return chunk->value[0] == 't' || chunk->value[0] == 'f';
case SPA_JSON_TYPE_RECTANGLE:
case SPA_JSON_TYPE_FRACTION:
case SPA_JSON_TYPE_ARRAY:
return chunk->value[0] == '[';
case SPA_JSON_TYPE_OBJECT:
return chunk->value[0] == '{';
}
return false;
}
static inline int spa_json_chunk_to_int(struct spa_json_chunk *chunk) {
return atoi(chunk->value);
}
static inline int64_t spa_json_chunk_to_long(struct spa_json_chunk *chunk) {
return atol(chunk->value);
}
static inline int64_t spa_json_chunk_to_float(struct spa_json_chunk *chunk) {
return strtof(chunk->value, NULL);
}
static inline int64_t spa_json_chunk_to_double(struct spa_json_chunk *chunk) {
return strtod(chunk->value, NULL);
}
static inline bool spa_json_chunk_to_bool(struct spa_json_chunk *chunk) {
return chunk->value[0] == 't';
}
static inline int spa_json_chunk_to_rectangle(struct spa_json_chunk *chunk,
struct spa_rectangle *rect) {
return spa_json_chunk_extract(chunk, "[ #pi, #pi ]", &rect->width, &rect->height);
}
static inline int spa_json_chunk_to_fraction(struct spa_json_chunk *chunk,
struct spa_fraction *frac) {
return spa_json_chunk_extract(chunk, "[ #pi, #pi ]", &frac->num, &frac->denom);
}
static inline void
spa_json_iter_init (struct spa_json_iter *iter, const char *data, size_t size)
{
iter->start = iter->cur = data;
iter->end = size == -1 ? NULL : data + size;
iter->state = 0;
iter->depth = 0;
}
static inline bool
spa_json_iter_chunk(struct spa_json_iter *iter, struct spa_json_chunk *chunk)
{
if (!spa_json_chunk_is_type(chunk, SPA_JSON_TYPE_OBJECT) &&
!spa_json_chunk_is_type(chunk, SPA_JSON_TYPE_ARRAY))
return false;
spa_json_iter_init (iter, chunk->value, -1);
iter->cur++;
return true;
}
static inline int
spa_json_iter_next_chunk(struct spa_json_iter *iter, struct spa_json_chunk *chunk)
{
int utf8_remain = 0;
for (;iter->end == NULL || iter->cur < iter->end; iter->cur++) {
unsigned char cur = (unsigned char) *iter->cur;
again:
switch (iter->state) {
case 0: /* scanning for objects */
switch (cur) {
case '\t': case ' ': case '\r': case '\n': case ':': case ',':
continue;
case '"':
chunk->value = iter->cur;
iter->state = 2;
continue;
case '[': case '{':
chunk->value = iter->cur;
if (++iter->depth > 1)
continue;
iter->cur++;
return chunk->len = 1;
case '}': case ']':
if (iter->depth == 0)
return 0;
--iter->depth;
continue;
case '-': case 'a' ... 'z': case 'A' ... 'Z': case '0' ... '9': case '#':
chunk->value = iter->cur;
iter->state = 1;
continue;
case '\0':
return 0;
}
return -1;
case 1: /* token */
switch (cur) {
case '\t': case ' ': case '\r': case '\n': case ':': case ',':
case ']': case '}':
iter->state = 0;
if (iter->depth > 0)
goto again;
return chunk->len = iter->cur - chunk->value;
default:
if (cur >= 32 && cur <= 126)
continue;
}
return -1;
case 2: /* string */
switch (cur) {
case '\\':
iter->state = 4;
continue;
case '"':
iter->state = 0;
if (iter->depth > 0)
continue;
iter->cur++;
return chunk->len = iter->cur - chunk->value;
case 240 ... 247:
utf8_remain++;
case 224 ... 239:
utf8_remain++;
case 192 ... 223:
utf8_remain++;
iter->state = 3;
continue;
default:
if (cur >= 32 && cur <= 126)
continue;
}
return -1;
case 3: /* utf chars */
switch (cur) {
case 128 ... 191:
if (--utf8_remain == 0)
iter->state = 2;
continue;
}
return -1;
case 4: /* inside escape chars */
switch (cur) {
case '"': case '\\': case '/': case 'b': case 'f': case 'n': case 'r':
case 't': case 'u':
iter->state = 2;
continue;
}
return -1;
}
}
return iter->depth == 0 ? 0 : -1;
}
static inline void
spa_json_chunk_print(struct spa_json_chunk *chunk, int prefix)
{
struct spa_json_iter iter;
if (spa_json_iter_chunk(&iter, chunk)) {
struct spa_json_chunk chunk2 = { NULL, };
printf ("%-*s%c\n", prefix, "", chunk->value[0]);
while (spa_json_iter_next_chunk(&iter, &chunk2) > 0)
spa_json_chunk_print(&chunk2, prefix + 2);
printf ("%-*s%c\n", prefix, "", iter.cur[0]);
} else {
printf ("%-*s%.*s\n", prefix, "", chunk->len, chunk->value);
}
}
static inline int spa_json_iter_find_key(struct spa_json_iter *iter, const char *key)
{
struct spa_json_chunk ch = { NULL, };
int res;
iter->cur = iter->start + 1;
iter->depth = 0;
iter->state = 0;
while (true) {
/* read key */
if ((res = spa_json_iter_next_chunk(iter, &ch)) <= 0)
return res;
if (spa_json_chunk_is_type(&ch, SPA_JSON_TYPE_STRING) &&
strncmp(key, ch.value, ch.len) == 0)
return 1;
}
return 0;
}
enum spa_json_prop_range {
SPA_JSON_PROP_RANGE_NONE = '-',
SPA_JSON_PROP_RANGE_MIN_MAX = 'r',
SPA_JSON_PROP_RANGE_STEP = 's',
SPA_JSON_PROP_RANGE_ENUM = 'e',
SPA_JSON_PROP_RANGE_FLAGS = 'f'
};
enum spa_json_prop_flags {
SPA_JSON_PROP_FLAG_UNSET = (1 << 0),
SPA_JSON_PROP_FLAG_OPTIONAL = (1 << 1),
SPA_JSON_PROP_FLAG_READONLY = (1 << 2),
SPA_JSON_PROP_FLAG_DEPRECATED = (1 << 3),
};
struct spa_json_prop {
enum spa_json_type type;
enum spa_json_prop_range range;
enum spa_json_prop_flags flags;
struct spa_json_chunk value;
struct spa_json_chunk alternatives;
};
static inline int
spa_json_chunk_parse_prop(struct spa_json_chunk *chunk, char type,
struct spa_json_prop *prop)
{
if (spa_json_chunk_is_type(chunk, SPA_JSON_TYPE_ARRAY)) {
struct spa_json_chunk flags;
int res;
char ch;
/* [<flags>, <default>, [<alternatives>,...]] */
if ((res = spa_json_chunk_extract(chunk,
"[ #&cs, #&c-, #&ca ]",
&flags, &prop->value, &prop->alternatives)) < 3) {
printf("can't parse prop chunk %d\n", res);
return -1;
}
/* skip \" */
flags.value++;
prop->type = *flags.value++;
if (type != SPA_JSON_TYPE_ANY && type != SPA_JSON_TYPE_CHUNK && prop->type != type) {
printf("prop chunk of wrong type %d %d\n", prop->type, type);
return -1;
}
prop->range = *flags.value++;
/* flags */
prop->flags = 0;
while ((ch = *flags.value++) != '\"') {
switch (ch) {
case 'u':
prop->flags |= SPA_JSON_PROP_FLAG_UNSET;
break;
case 'o':
prop->flags |= SPA_JSON_PROP_FLAG_OPTIONAL;
break;
case 'r':
prop->flags |= SPA_JSON_PROP_FLAG_READONLY;
break;
case 'd':
prop->flags |= SPA_JSON_PROP_FLAG_DEPRECATED;
break;
}
}
}
else {
/* <value> */
prop->type = type;
prop->range = SPA_JSON_PROP_RANGE_NONE;
prop->flags = 0;
prop->value = *chunk;
prop->alternatives = *chunk;
}
return 0;
}
/**
* #[*]<asign>
*
* * = skip assignment
* <asign> is:
* &<type> -> pointer to type
* p<type> -> property, fixed value store in pointer to type
* P<type> -> property, stored in pointer to struct spa_json_prop
*
* <type>
* - -> any
* c<type> -> store as chunk if of type
* s -> string
* i -> int
* l -> long
* f -> float
* d -> double
* b -> bool
* R -> rectangle
* F -> fraction
* a -> array
* o -> object
*/
static inline int
spa_json_chunk_extract(struct spa_json_chunk *chunk,
const char *template, ...)
{
struct spa_json_iter templ[16], it[16];
struct spa_json_chunk tch = { NULL, }, ch = { NULL, };
struct spa_json_prop prop;
const char *match;
int collected = 0, res, level = 0;
va_list args;
bool store;
va_start(args, template);
spa_json_iter_init(&it[0], chunk->value, chunk->len);
spa_json_iter_init (&templ[0], template, -1);
while (true) {
res = spa_json_iter_next_chunk(&templ[level], &tch);
if (res == 0) {
if (--level == 0)
break;
continue;
} else if (res < 0) {
return res;
}
switch (tch.value[0]) {
case '[': case '{':
if (spa_json_iter_next_chunk(&it[level], &ch) <= 0 ||
ch.value[0] != tch.value[0])
return -1;
if (++level == 16)
return -2;
spa_json_iter_chunk(&it[level], &ch);
spa_json_iter_chunk(&templ[level], &tch);
break;
case '"':
case '-': case '0' ... '9':
case 't': case 'f':
case 'n':
if (templ[level].start[0] == '{') {
if (spa_json_iter_find_key(&it[level], tch.value) <= 0)
continue;
} else if (spa_json_iter_next_chunk(&it[level], &ch) <= 0 ||
ch.len != tch.len ||
strncmp(ch.value, tch.value, ch.len) != 0)
return -1;
break;
case '#':
match = tch.value + 1;
if (spa_json_iter_next_chunk(&it[level], &ch) <= 0)
return -1;
store = (match[0] != '*');
if (!store)
match++;
switch (match[0]) {
case 'p':
case 'P':
if (spa_json_chunk_parse_prop(&ch, match[1], &prop) < 0)
goto skip;
if (match[0] == 'P') {
if (store)
*va_arg(args, struct spa_json_prop *) = prop;
collected++;
break;
}
else {
if (prop.flags & SPA_JSON_PROP_FLAG_UNSET)
goto skip;
ch = prop.value;
}
/* fallthrough */
case '&':
if (!spa_json_chunk_is_type(&ch, match[1] == SPA_JSON_TYPE_CHUNK ?
match[2] : match[1])) {
skip:
if (store)
va_arg(args, void *);
break;
}
if (!store)
break;
collected++;
switch (match[1]) {
case SPA_JSON_TYPE_CHUNK:
*va_arg(args, struct spa_json_chunk *) = ch;
break;
case SPA_JSON_TYPE_INT:
*va_arg(args, int *) = spa_json_chunk_to_int(&ch);
break;
case SPA_JSON_TYPE_LONG:
*va_arg(args, int64_t *) = spa_json_chunk_to_long(&ch);
break;
case SPA_JSON_TYPE_FLOAT:
*va_arg(args, float *) = spa_json_chunk_to_float(&ch);
break;
case SPA_JSON_TYPE_DOUBLE:
*va_arg(args, double *) = spa_json_chunk_to_double(&ch);
break;
case SPA_JSON_TYPE_BOOL:
*va_arg(args, bool *) = spa_json_chunk_to_bool(&ch);
break;
case SPA_JSON_TYPE_RECTANGLE:
spa_json_chunk_to_rectangle(&ch,
va_arg(args, struct spa_rectangle *));
break;
case SPA_JSON_TYPE_FRACTION:
spa_json_chunk_to_fraction(&ch,
va_arg(args, struct spa_fraction *));
break;
default:
printf("ignoring invalid #p type %c\n", match[1]);
va_arg(args, void *);
collected--;
continue;
}
break;
default:
printf("ignoring unknown match type %c\n", *match);
break;
}
break;
default:
printf("invalid char %c\n", tch.value[0]);
return -2;
}
}
va_end(args);
return collected;
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __SPA_JSON_H__ */

View file

@ -35,18 +35,27 @@ struct spa_param {
struct spa_pod_object object;
};
static inline uint32_t spa_param_query(const struct spa_param *param, uint32_t key, ...)
static inline uint32_t
spa_pod_builder_push_param(struct spa_pod_builder *builder,
struct spa_pod_frame *frame,
uint32_t param_type)
{
uint32_t count;
va_list args;
va_start(args, key);
count = spa_pod_contents_queryv(&param->object.pod, sizeof(struct spa_param), key, args);
va_end(args);
return count;
return spa_pod_builder_push_object(builder, frame, 0, param_type);
}
#define spa_pod_builder_param(b,param_type,...) \
spa_pod_builder_object(b, 0, param_type, \
##__VA_ARGS__)
#define spa_param_parse(param,...) \
({ \
struct spa_pod_parser __p; \
const struct spa_param *__param = param; \
spa_pod_parser_pod(&__p, &__param->object.pod); \
spa_pod_parser_get(&__p, "<", ##__VA_ARGS__, NULL); \
})
#define SPA_PARAM_BODY_FOREACH(body, size, iter) \
for ((iter) = SPA_MEMBER((body), sizeof(struct spa_pod_object_body), struct spa_pod_prop); \
(iter) < SPA_MEMBER((body), (size), struct spa_pod_prop); \

View file

@ -27,6 +27,10 @@ extern "C" {
#include <stdarg.h>
#include <spa/pod-utils.h>
#ifndef SPA_POD_MAX_LEVEL
#define SPA_POD_MAX_LEVEL 16
#endif
struct spa_pod_frame {
struct spa_pod_frame *parent;
struct spa_pod pod;
@ -42,6 +46,8 @@ struct spa_pod_builder {
uint32_t size);
bool in_array;
bool first;
struct spa_pod_frame frame[SPA_POD_MAX_LEVEL];
int depth;
};
#define SPA_POD_BUILDER_INIT(buffer,size) { buffer, size, }
@ -54,6 +60,7 @@ static inline void spa_pod_builder_init(struct spa_pod_builder *builder, void *d
builder->size = size;
builder->offset = 0;
builder->stack = NULL;
builder->depth = 0;
}
static inline uint32_t
@ -144,6 +151,14 @@ spa_pod_builder_primitive(struct spa_pod_builder *builder, const struct spa_pod
return ref;
}
#define SPA_POD_NONE_INIT() { 0, SPA_POD_TYPE_NONE }
static inline uint32_t spa_pod_builder_none(struct spa_pod_builder *builder)
{
const struct spa_pod p = SPA_POD_NONE_INIT();
return spa_pod_builder_primitive(builder, &p);
}
#define SPA_POD_BOOL_INIT(val) { { sizeof(uint32_t), SPA_POD_TYPE_BOOL }, val ? 1 : 0 }
static inline uint32_t spa_pod_builder_bool(struct spa_pod_builder *builder, bool val)
@ -194,12 +209,24 @@ static inline uint32_t spa_pod_builder_double(struct spa_pod_builder *builder, d
#define SPA_POD_STRING_INIT(len) { { len, SPA_POD_TYPE_STRING } }
static inline uint32_t
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) == -1)
ref = -1;
if (spa_pod_builder_raw(builder, "", 1) == -1)
ref = -1;
spa_pod_builder_pad(builder, builder->offset);
return ref;
}
static inline uint32_t
spa_pod_builder_string_len(struct spa_pod_builder *builder, const char *str, uint32_t len)
{
const struct spa_pod_string p = SPA_POD_STRING_INIT(len);
const struct spa_pod_string p = SPA_POD_STRING_INIT(len+1);
uint32_t ref = spa_pod_builder_raw(builder, &p, sizeof(p));
if (spa_pod_builder_raw_padded(builder, str, len) == -1)
if (spa_pod_builder_write_string(builder, str, len) == -1)
ref = -1;
return ref;
}
@ -207,7 +234,7 @@ spa_pod_builder_string_len(struct spa_pod_builder *builder, const char *str, uin
static inline uint32_t 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 + 1);
return spa_pod_builder_string_len(builder, str ? str : "", len);
}
#define SPA_POD_BYTES_INIT(len) { { len, SPA_POD_TYPE_BYTES } }
@ -231,6 +258,14 @@ spa_pod_builder_pointer(struct spa_pod_builder *builder, uint32_t type, void *va
return spa_pod_builder_primitive(builder, &p.pod);
}
#define SPA_POD_FD_INIT(fd) { { sizeof(int), SPA_POD_TYPE_FD }, fd }
static inline uint32_t spa_pod_builder_fd(struct spa_pod_builder *builder, int fd)
{
const struct spa_pod_fd p = SPA_POD_FD_INIT(fd);
return spa_pod_builder_primitive(builder, &p.pod);
}
#define SPA_POD_RECTANGLE_INIT(width,height) { { sizeof(struct spa_rectangle), SPA_POD_TYPE_RECTANGLE }, { width, height } }
static inline uint32_t
@ -311,238 +346,227 @@ spa_pod_builder_push_prop(struct spa_pod_builder *builder,
sizeof(p) - sizeof(struct spa_pod)));
}
static inline void
spa_pod_builder_addv(struct spa_pod_builder *builder, uint32_t type, va_list args)
static inline uint32_t spa_pod_range_from_id(char id)
{
uint32_t n_values = 0;
union {
struct spa_pod pod;
struct spa_pod_bool bool_pod;
struct spa_pod_id id_pod;
struct spa_pod_int int_pod;
struct spa_pod_long long_pod;
struct spa_pod_float float_pod;
struct spa_pod_double double_pod;
struct spa_pod_string string_pod;
struct spa_pod_bytes bytes_pod;
struct spa_pod_pointer pointer_pod;
struct spa_pod_rectangle rectangle_pod;
struct spa_pod_fraction fraction_pod;
struct spa_pod_array array_pod;
struct spa_pod_struct struct_pod;
struct spa_pod_object object_pod;
struct spa_pod_prop prop_pod;
} head;
uint32_t head_size;
const void *body;
uint32_t body_size;
static const uint64_t zeroes = 0;
while (type != SPA_POD_TYPE_INVALID) {
struct spa_pod_frame *f = NULL;
const void *data[3];
uint32_t size[3], ref, i, n_sizes = 0;
switch (type) {
case SPA_POD_TYPE_NONE:
break;
case SPA_POD_TYPE_BOOL:
case SPA_POD_TYPE_ID:
case SPA_POD_TYPE_INT:
head.int_pod.pod.type = type;
head.int_pod.pod.size = body_size = sizeof(uint32_t);
head.int_pod.value = va_arg(args, int);
head_size = sizeof(struct spa_pod);
body = &head.int_pod.value;
goto primitive;
case SPA_POD_TYPE_LONG:
head.long_pod.pod.type = SPA_POD_TYPE_LONG;
head.long_pod.pod.size = body_size = sizeof(uint32_t);
head.long_pod.value = va_arg(args, int64_t);
head_size = sizeof(struct spa_pod);
body = &head.long_pod.value;
goto primitive;
case SPA_POD_TYPE_FLOAT:
head.float_pod.pod.type = SPA_POD_TYPE_FLOAT;
head.float_pod.pod.size = body_size = sizeof(float);
head.float_pod.value = va_arg(args, double);
head_size = sizeof(struct spa_pod);
body = &head.float_pod.value;
goto primitive;
case SPA_POD_TYPE_DOUBLE:
head.double_pod.pod.type = SPA_POD_TYPE_DOUBLE;
head.double_pod.pod.size = body_size = sizeof(double);
head.double_pod.value = va_arg(args, double);
head_size = sizeof(struct spa_pod);
body = &head.double_pod.value;
goto primitive;
case SPA_POD_TYPE_STRING:
body = va_arg(args, const char *);
body_size = body ? strlen(body) + 1 : (body = "", 1);
head.string_pod.pod.type = SPA_POD_TYPE_STRING;
head.string_pod.pod.size = body_size;
head_size = sizeof(struct spa_pod);
goto primitive;
case -SPA_POD_TYPE_STRING:
body = va_arg(args, const char *);
body_size = va_arg(args, uint32_t);
head.string_pod.pod.type = SPA_POD_TYPE_STRING;
head.string_pod.pod.size = body_size;
head_size = sizeof(struct spa_pod);
goto primitive;
case SPA_POD_TYPE_BYTES:
body = va_arg(args, void *);
body_size = va_arg(args, uint32_t);
head.bytes_pod.pod.type = SPA_POD_TYPE_BYTES;
head.bytes_pod.pod.size = body_size;
head_size = sizeof(struct spa_pod);
goto primitive;
case SPA_POD_TYPE_POINTER:
head.pointer_pod.pod.type = SPA_POD_TYPE_POINTER;
head.pointer_pod.pod.size = body_size = sizeof(struct spa_pod_pointer_body);
head.pointer_pod.body.type = va_arg(args, uint32_t);
head.pointer_pod.body.value = va_arg(args, void *);
head_size = sizeof(struct spa_pod);
body = &head.pointer_pod.body;
goto primitive;
case SPA_POD_TYPE_RECTANGLE:
head.rectangle_pod.pod.type = SPA_POD_TYPE_RECTANGLE;
head.rectangle_pod.pod.size = body_size = sizeof(struct spa_rectangle);
head.rectangle_pod.value.width = va_arg(args, uint32_t);
head.rectangle_pod.value.height = va_arg(args, uint32_t);
head_size = sizeof(struct spa_pod);
body = &head.rectangle_pod.value;
goto primitive;
case -SPA_POD_TYPE_RECTANGLE:
head.rectangle_pod.pod.type = SPA_POD_TYPE_RECTANGLE;
head.rectangle_pod.pod.size = body_size = sizeof(struct spa_rectangle);
head.rectangle_pod.value = *va_arg(args, struct spa_rectangle *);
head_size = sizeof(struct spa_pod);
body = &head.rectangle_pod.value;
goto primitive;
case SPA_POD_TYPE_FRACTION:
head.fraction_pod.pod.type = SPA_POD_TYPE_FRACTION;
head.fraction_pod.pod.size = body_size = sizeof(struct spa_fraction);
head.fraction_pod.value.num = va_arg(args, uint32_t);
head.fraction_pod.value.denom = va_arg(args, uint32_t);
head_size = sizeof(struct spa_pod);
body = &head.fraction_pod.value;
goto primitive;
case -SPA_POD_TYPE_FRACTION:
head.fraction_pod.pod.type = SPA_POD_TYPE_FRACTION;
head.fraction_pod.pod.size = body_size = sizeof(struct spa_fraction);
head.fraction_pod.value = *va_arg(args, struct spa_fraction *);
head_size = sizeof(struct spa_pod);
body = &head.fraction_pod.value;
goto primitive;
case SPA_POD_TYPE_BITMASK:
break;
case SPA_POD_TYPE_ARRAY:
f = va_arg(args, struct spa_pod_frame *);
type = va_arg(args, uint32_t);
n_values = va_arg(args, uint32_t);
head.array_pod.pod.type = SPA_POD_TYPE_ARRAY;
head.array_pod.pod.size = 0;
head_size = sizeof(struct spa_pod);
body = NULL;
goto primitive;
case SPA_POD_TYPE_STRUCT:
f = va_arg(args, struct spa_pod_frame *);
head.struct_pod.pod.type = SPA_POD_TYPE_STRUCT;
head.struct_pod.pod.size = 0;
head_size = sizeof(struct spa_pod);
body = NULL;
goto primitive;
case SPA_POD_TYPE_OBJECT:
f = va_arg(args, struct spa_pod_frame *);
head.object_pod.pod.type = SPA_POD_TYPE_OBJECT;
head.object_pod.pod.size = sizeof(struct spa_pod_object_body);
head.object_pod.body.id = va_arg(args, uint32_t);
head.object_pod.body.type = va_arg(args, uint32_t);
head_size = sizeof(struct spa_pod_object);
body = NULL;
goto primitive;
case SPA_POD_TYPE_PROP:
f = va_arg(args, struct spa_pod_frame *);
head.prop_pod.pod.type = SPA_POD_TYPE_PROP;
head.prop_pod.pod.size =
sizeof(struct spa_pod_prop_body) - sizeof(struct spa_pod);
head.prop_pod.body.key = va_arg(args, uint32_t);
head.prop_pod.body.flags = va_arg(args, uint32_t);
head_size = sizeof(struct spa_pod_prop) - sizeof(struct spa_pod);
body = NULL;
type = va_arg(args, uint32_t);
n_values = va_arg(args, uint32_t);
goto primitive;
case -SPA_POD_TYPE_ARRAY:
case -SPA_POD_TYPE_STRUCT:
case -SPA_POD_TYPE_OBJECT:
case -SPA_POD_TYPE_PROP:
f = va_arg(args, struct spa_pod_frame *);
spa_pod_builder_pop(builder, f);
break;
case SPA_POD_TYPE_POD:
if ((body = va_arg(args, void *)) == NULL) {
head.pod.type = SPA_POD_TYPE_NONE;
head.pod.size = 0;
body = &head;
}
body_size = SPA_POD_SIZE(body);
goto extra;
}
if (0) {
primitive:
if (!builder->in_array || builder->first) {
data[n_sizes] = &head;
size[n_sizes++] = head_size;
builder->first = false;
}
if (body) {
extra:
data[n_sizes] = body;
size[n_sizes++] = body_size;
if (!builder->in_array) {
data[n_sizes] = &zeroes;
size[n_sizes++] = SPA_ROUND_UP_N(body_size, 8) - body_size;
}
}
for (i = 0; i < n_sizes; i++) {
ref = spa_pod_builder_raw(builder, data[i], size[i]);
if (f && i == 0)
spa_pod_builder_push(builder, f, data[i], ref);
}
}
if (n_values > 0)
n_values--;
else
type = va_arg(args, uint32_t);
switch (id) {
case 'r':
return SPA_POD_PROP_RANGE_MIN_MAX;
case 's':
return SPA_POD_PROP_RANGE_STEP;
case 'e':
return SPA_POD_PROP_RANGE_ENUM;
case 'f':
return SPA_POD_PROP_RANGE_FLAGS;
default:
return SPA_POD_PROP_RANGE_NONE;
}
}
static inline void spa_pod_builder_add(struct spa_pod_builder *builder, uint32_t type, ...)
static inline uint32_t spa_pod_flag_from_id(char id)
{
va_list args;
va_start(args, type);
spa_pod_builder_addv(builder, type, args);
va_end(args);
switch (id) {
case 'u':
return SPA_POD_PROP_FLAG_UNSET;
case 'o':
return SPA_POD_PROP_FLAG_OPTIONAL;
case 'r':
return SPA_POD_PROP_FLAG_READONLY;
case 'd':
return SPA_POD_PROP_FLAG_DEPRECATED;
default:
return 0;
}
}
#define SPA_POD_OBJECT(f,id,type,...) \
SPA_POD_TYPE_OBJECT, f, id, type, __VA_ARGS__, -SPA_POD_TYPE_OBJECT, f
#define SPA_POD_BUILDER_COLLECT(builder,type,args) \
do { \
switch (type) { \
case 'b': \
spa_pod_builder_bool(builder, va_arg(args, int)); \
break; \
case 'I': \
spa_pod_builder_id(builder, va_arg(args, uint32_t)); \
break; \
case 'i': \
spa_pod_builder_int(builder, va_arg(args, int)); \
break; \
case 'l': \
spa_pod_builder_long(builder, va_arg(args, int64_t)); \
break; \
case 'f': \
spa_pod_builder_float(builder, va_arg(args, double)); \
break; \
case 'd': \
spa_pod_builder_double(builder, va_arg(args, double)); \
break; \
case 's': \
{ \
char *strval = va_arg(args, char *) ? : ""; \
size_t len = strlen(strval); \
spa_pod_builder_string_len(builder, strval, len); \
break; \
} \
case 'S': \
{ \
char *strval = va_arg(args, char *); \
size_t len = va_arg(args, int); \
spa_pod_builder_string_len(builder, strval, len); \
break; \
} \
case 'z': \
{ \
void *ptr = va_arg(args, void *); \
int len = va_arg(args, int); \
spa_pod_builder_bytes(builder, ptr, len); \
break; \
} \
case 'R': \
{ \
struct spa_rectangle *rectval = \
va_arg(args, struct spa_rectangle *); \
spa_pod_builder_rectangle(builder, \
rectval->width, rectval->height); \
break; \
} \
case 'F': \
{ \
struct spa_fraction *fracval = \
va_arg(args, struct spa_fraction *); \
spa_pod_builder_fraction(builder, fracval->num, fracval->denom);\
break; \
} \
case 'a': \
{ \
int child_size = va_arg(args, int); \
int child_type = va_arg(args, int); \
int n_elems = va_arg(args, int); \
void *elems = va_arg(args, void *); \
spa_pod_builder_array(builder, child_size, \
child_type, n_elems, elems); \
break; \
} \
case 'p': \
{ \
int t = va_arg(args, uint32_t); \
spa_pod_builder_pointer(builder, t, va_arg(args, void *)); \
break; \
} \
case 'h': \
spa_pod_builder_fd(builder, va_arg(args, int)); \
break; \
case 'P': \
{ \
struct spa_pod *pod = va_arg(args, struct spa_pod *); \
if (pod == NULL) \
spa_pod_builder_none(builder); \
else \
spa_pod_builder_primitive(builder, pod); \
break; \
} \
} \
} while(false)
#define SPA_POD_STRUCT(f,...) \
SPA_POD_TYPE_STRUCT, f, __VA_ARGS__, -SPA_POD_TYPE_STRUCT, f
static inline void *
spa_pod_builder_addv(struct spa_pod_builder *builder,
const char *format, va_list args)
{
while (format) {
switch (*format) {
case '<':
{
uint32_t id = va_arg(args, uint32_t);
uint32_t type = va_arg(args, uint32_t);
spa_pod_builder_push_object(builder, &builder->frame[builder->depth++], id, type);
break;
}
case '[':
spa_pod_builder_push_struct(builder, &builder->frame[builder->depth++]);
break;
case '(':
spa_pod_builder_push_array(builder, &builder->frame[builder->depth++]);
break;
case ':':
{
const char *spec;
char type;
int n_values;
uint32_t key, flags;
#define SPA_POD_PROP(f,key,flags,type,...) \
SPA_POD_TYPE_PROP, f, key, flags, type, __VA_ARGS__, -SPA_POD_TYPE_PROP, f
key = va_arg(args, uint32_t);
format = spec = va_arg(args, const char *);
type = *spec;
if (*spec != '\0')
spec++;
flags = spa_pod_range_from_id(*spec);
if (*spec != '\0')
spec++;
for (;*spec;spec++)
flags |= spa_pod_flag_from_id(*spec);
spa_pod_builder_push_prop(builder, &builder->frame[builder->depth++], key, flags);
#define spa_pod_builder_object(b,f,id,type,...) \
spa_pod_builder_add(b, SPA_POD_OBJECT(f,id,type,__VA_ARGS__), 0)
if (type == '{' || type == '[')
continue;
#define spa_pod_builder_struct(b,f,...) \
spa_pod_builder_add(b, SPA_POD_STRUCT(f,__VA_ARGS__), 0)
n_values = -1;
while (n_values-- != 0) {
SPA_POD_BUILDER_COLLECT(builder, type, args);
if ((flags & SPA_POD_PROP_RANGE_MASK) == 0)
break;
if (n_values == -2)
n_values = va_arg(args, int);
}
spa_pod_builder_pop(builder, &builder->frame[--builder->depth]);
break;
}
case ']': case ')': case '>':
spa_pod_builder_pop(builder, &builder->frame[--builder->depth]);
if (builder->depth > 0 &&
builder->frame[builder->depth-1].pod.type == SPA_POD_TYPE_PROP)
spa_pod_builder_pop(builder, &builder->frame[--builder->depth]);
break;
case ' ': case '\n': case '\t': case '\r':
break;
case '\0':
format = va_arg(args, const char *);
continue;
default:
SPA_POD_BUILDER_COLLECT(builder,*format,args);
break;;
}
format++;
}
return SPA_POD_BUILDER_DEREF(builder, builder->frame[builder->depth].ref, void);
}
static inline void *spa_pod_builder_add(struct spa_pod_builder *builder, const char *format, ...)
{
void *res;
va_list args;
va_start(args, format);
res = spa_pod_builder_addv(builder, format, args);
va_end(args);
return res;
}
#define SPA_POD_OBJECT(id,type,...) \
"<", id, type, ##__VA_ARGS__, ">"
#define SPA_POD_STRUCT(...) \
"[", ##__VA_ARGS__, "]"
#define SPA_POD_PROP(key,spec,type,value,...) \
":", key, spec, value, ##__VA_ARGS__
#define spa_pod_builder_object(b,id,type,...) \
spa_pod_builder_add(b, SPA_POD_OBJECT(id,type,##__VA_ARGS__), NULL)
#define spa_pod_builder_struct(b,...) \
spa_pod_builder_add(b, SPA_POD_STRUCT(__VA_ARGS__), NULL)
#ifdef __cplusplus
} /* extern "C" */

View file

@ -35,102 +35,27 @@ struct spa_pod_iter {
uint32_t offset;
};
static inline void spa_pod_iter_contents(struct spa_pod_iter *iter, const void *data, uint32_t size)
static inline void spa_pod_iter_init(struct spa_pod_iter *iter, const void *data, uint32_t size, uint32_t offset)
{
iter->data = data;
iter->size = size;
iter->offset = 0;
iter->offset = offset;
}
static inline bool spa_pod_iter_struct(struct spa_pod_iter *iter, const void *data, uint32_t size)
static inline struct spa_pod *spa_pod_iter_current(struct spa_pod_iter *iter)
{
if (data == NULL || size < 8 || SPA_POD_SIZE(data) > size
|| SPA_POD_TYPE(data) != SPA_POD_TYPE_STRUCT)
return false;
spa_pod_iter_contents(iter, SPA_POD_CONTENTS(struct spa_pod_struct, data),
SPA_POD_CONTENTS_SIZE(struct spa_pod_struct, data));
return true;
}
static inline bool spa_pod_iter_object(struct spa_pod_iter *iter, const void *data, uint32_t size)
{
if (data == NULL || SPA_POD_SIZE(data) > size || SPA_POD_TYPE(data) != SPA_POD_TYPE_OBJECT)
return false;
spa_pod_iter_contents(iter, SPA_POD_CONTENTS(struct spa_pod_object, data),
SPA_POD_CONTENTS_SIZE(struct spa_pod_object, data));
return true;
}
static inline bool spa_pod_iter_pod(struct spa_pod_iter *iter, struct spa_pod *pod)
{
void *data;
uint32_t size;
switch (SPA_POD_TYPE(pod)) {
case SPA_POD_TYPE_STRUCT:
data = SPA_POD_CONTENTS(struct spa_pod_struct, pod);
size = SPA_POD_CONTENTS_SIZE(struct spa_pod_struct, pod);
break;
case SPA_POD_TYPE_OBJECT:
data = SPA_POD_CONTENTS(struct spa_pod_object, pod);
size = SPA_POD_CONTENTS_SIZE(struct spa_pod_object, pod);
break;
default:
spa_pod_iter_contents(iter, NULL, 0);
return false;
if (iter->offset + 8 <= iter->size) {
struct spa_pod *pod = SPA_MEMBER(iter->data, iter->offset, struct spa_pod);
if (SPA_POD_SIZE(pod) <= iter->size)
return pod;
}
spa_pod_iter_contents(iter, data, size);
return true;
return NULL;
}
static inline bool spa_pod_iter_has_next(struct spa_pod_iter *iter)
static inline void spa_pod_iter_advance(struct spa_pod_iter *iter, struct spa_pod *current)
{
return (iter->offset + 8 <= iter->size &&
SPA_POD_SIZE(SPA_MEMBER(iter->data, iter->offset, struct spa_pod)) <= iter->size);
}
static inline struct spa_pod *spa_pod_iter_next(struct spa_pod_iter *iter)
{
struct spa_pod *res = SPA_MEMBER(iter->data, iter->offset, struct spa_pod);
iter->offset += SPA_ROUND_UP_N(SPA_POD_SIZE(res), 8);
return res;
}
static inline struct spa_pod *spa_pod_iter_first(struct spa_pod_iter *iter, struct spa_pod *pod)
{
if (!spa_pod_iter_pod(iter, pod) || !spa_pod_iter_has_next(iter))
return NULL;
return spa_pod_iter_next(iter);
}
static inline bool spa_pod_iter_getv(struct spa_pod_iter *iter, uint32_t type, va_list args)
{
bool res = true;
while (type && (res = spa_pod_iter_has_next(iter))) {
struct spa_pod *pod = spa_pod_iter_next(iter);
SPA_POD_COLLECT(pod, type, args, error);
type = va_arg(args, uint32_t);
}
return res;
error:
return false;
}
static inline bool spa_pod_iter_get(struct spa_pod_iter *iter, uint32_t type, ...)
{
va_list args;
bool res;
va_start(args, type);
res = spa_pod_iter_getv(iter, type, args);
va_end(args);
return res;
if (current)
iter->offset += SPA_ROUND_UP_N(SPA_POD_SIZE(current), 8);
}
#ifdef __cplusplus

View file

@ -0,0 +1,313 @@
/* Spa
* Copyright (C) 2017 Wim Taymans <wim.taymans@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __SPA_POD_PARSER_H__
#define __SPA_POD_PARSER_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdarg.h>
#include <stdio.h>
#include <spa/pod-iter.h>
#ifndef SPA_POD_MAX_LEVEL
#define SPA_POD_MAX_LEVEL 16
#endif
struct spa_pod_parser {
struct spa_pod_iter iter[SPA_POD_MAX_LEVEL];
int depth;
};
static inline void spa_pod_parser_init(struct spa_pod_parser *parser,
const void *data, uint32_t size, uint32_t offset)
{
parser->depth = 0;
spa_pod_iter_init(&parser->iter[0], data, size, offset);
}
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), 0);
}
static inline bool spa_pod_parser_can_collect(struct spa_pod *pod, char type)
{
if (type == 'P')
return true;
switch (SPA_POD_TYPE(pod)) {
case SPA_POD_TYPE_NONE:
return type == 'T' || type == 'O' || type == 'V';
case SPA_POD_TYPE_BOOL:
return type == 'b';
case SPA_POD_TYPE_ID:
return type == 'I';
case SPA_POD_TYPE_INT:
return type == 'i';
case SPA_POD_TYPE_LONG:
return type == 'l';
case SPA_POD_TYPE_FLOAT:
return type == 'f';
case SPA_POD_TYPE_DOUBLE:
return type == 'd';
case SPA_POD_TYPE_STRING:
return type == 's' || type == 'S';
case SPA_POD_TYPE_BYTES:
return type == 'z';
case SPA_POD_TYPE_RECTANGLE:
return type == 'R';
case SPA_POD_TYPE_FRACTION:
return type == 'F';
case SPA_POD_TYPE_BITMAP:
return type == 'B';
case SPA_POD_TYPE_ARRAY:
return type == 'a';
case SPA_POD_TYPE_STRUCT:
return type == 'T';
case SPA_POD_TYPE_OBJECT:
return type == 'O';
case SPA_POD_TYPE_POINTER:
return type == 'p';
case SPA_POD_TYPE_FD:
return type == 'h';
case SPA_POD_TYPE_PROP:
return type == 'V';
default:
return false;
}
}
#define SPA_POD_PARSER_COLLECT(pod,type,args) \
do { \
switch (type) { \
case 'b': \
*va_arg(args, int*) = 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**) = 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, SPA_POD_CONTENTS(struct spa_pod_string, pod), maxlen-1); \
break; \
} \
case 'z': \
*(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 **) = \
SPA_POD_CONTENTS(struct spa_pod_bitmap, pod); \
break; \
case 'p': \
{ \
struct spa_pod_pointer_body *b = SPA_POD_BODY(pod); \
*(va_arg(args, void **)) = b->value; \
break; \
} \
case 'h': \
*va_arg(args, int*) = SPA_POD_VALUE(struct spa_pod_fd, pod); \
break; \
case 'V': \
case 'P': \
case 'O': \
case 'T': \
*va_arg(args, struct spa_pod**) = \
(pod == NULL || (SPA_POD_TYPE(pod) == SPA_POD_TYPE_NONE) \
? NULL : pod); \
break; \
default: \
break; \
} \
} while(false)
#define SPA_POD_PARSER_SKIP(type,args) \
do { \
switch (type) { \
case 'S': \
va_arg(args, void*); \
va_arg(args, uint32_t); \
break; \
case 'z': \
va_arg(args, void**); \
case 'b': \
case 'I': \
case 'i': \
case 'l': \
case 'f': \
case 'd': \
case 's': \
case 'R': \
case 'F': \
case 'B': \
case 'p': \
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,
const char *format, va_list args)
{
struct spa_pod *pod = NULL, *current;
struct spa_pod_prop *prop = NULL;
bool required = true, suppress = false, skip = false;
struct spa_pod_iter *it = &parser->iter[parser->depth];
current = pod = spa_pod_iter_current(it);
while (format) {
switch (*format) {
case '<':
if (pod == NULL || SPA_POD_TYPE(pod) != SPA_POD_TYPE_OBJECT)
return SPA_RESULT_ERROR;
it = &parser->iter[++parser->depth];
spa_pod_iter_init(it, pod, SPA_POD_SIZE(pod), sizeof(struct spa_pod_object));
goto read_pod;
case '[':
if (pod == NULL || SPA_POD_TYPE(pod) != SPA_POD_TYPE_STRUCT)
return SPA_RESULT_ERROR;
it = &parser->iter[++parser->depth];
spa_pod_iter_init(it, pod, SPA_POD_SIZE(pod), sizeof(struct spa_pod_struct));
goto read_pod;
case ']': case '>':
if (current != NULL)
return SPA_RESULT_ERROR;
if (--parser->depth < 0)
return SPA_RESULT_INVALID_ARGUMENTS;
it = &parser->iter[parser->depth];
current = spa_pod_iter_current(it);
spa_pod_iter_advance(it, current);
goto read_pod;
case '\0':
format = va_arg(args, char *);
continue;
case ' ': case '\n': case '\t': case '\r':
break;
case '?':
required = false;
break;
case '*':
suppress = true;
break;
case ':':
{
uint32_t key = va_arg(args, uint32_t);
const struct spa_pod *obj = parser->iter[parser->depth].data;
if (SPA_POD_TYPE(obj) == SPA_POD_TYPE_OBJECT)
prop = spa_pod_object_find_prop((struct spa_pod_object*)obj, key);
else if (SPA_POD_TYPE(obj) == SPA_POD_TYPE_STRUCT)
prop = spa_pod_struct_find_prop((struct spa_pod_struct*)obj, key);
else
prop = NULL;
if (prop != NULL && (prop->body.flags & SPA_POD_PROP_FLAG_UNSET) == 0)
pod = &prop->body.value;
else
pod = NULL;
it->offset = it->size;
current = NULL;
required = true;
break;
}
case 'V':
pod = (struct spa_pod *) prop;
if (pod == NULL && required)
return SPA_RESULT_NOT_FOUND;
goto collect;
default:
if (pod == NULL || !spa_pod_parser_can_collect(pod, *format)) {
if (required)
return SPA_RESULT_NOT_FOUND;
skip = true;
}
collect:
if (suppress)
suppress = false;
else if (skip)
SPA_POD_PARSER_SKIP(*format, args);
else
SPA_POD_PARSER_COLLECT(pod, *format, args);
spa_pod_iter_advance(it, current);
required = true;
skip = false;
read_pod:
pod = current = spa_pod_iter_current(it);
break;
}
format++;
}
return 0;
}
static inline int spa_pod_parser_get(struct spa_pod_parser *parser,
const char *format, ...)
{
int res;
va_list args;
va_start(args, format);
res = spa_pod_parser_getv(parser, format, args);
va_end(args);
return res;
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __SPA_POD_PARSER_H__ */

View file

@ -92,154 +92,19 @@ static inline struct spa_pod_prop *spa_pod_object_find_prop(const struct spa_pod
return spa_pod_contents_find_prop(&obj->pod, sizeof(struct spa_pod_object), key);
}
#define SPA_POD_COLLECT(pod,type,args,error) \
do { \
if (type == SPA_POD_TYPE_POD) { \
*(va_arg(args, struct spa_pod **)) = pod; \
} else if ((pod)->type == SPA_POD_TYPE_NONE) { \
switch (type) { \
case -SPA_POD_TYPE_ARRAY: \
case -SPA_POD_TYPE_STRUCT: \
case -SPA_POD_TYPE_OBJECT: \
case -SPA_POD_TYPE_PROP: \
*(va_arg(args, struct spa_pod **)) = NULL; \
break; \
default: \
goto error; \
} \
} else if ((pod)->type == type || (pod)->type == -type) { \
switch (type) { \
case SPA_POD_TYPE_BOOL: \
case SPA_POD_TYPE_ID: \
case SPA_POD_TYPE_INT: \
*(va_arg(args, int32_t*)) = SPA_POD_VALUE(struct spa_pod_int, pod); \
break; \
case SPA_POD_TYPE_LONG: \
*(va_arg(args, int64_t*)) = SPA_POD_VALUE(struct spa_pod_long, pod); \
break; \
case SPA_POD_TYPE_FLOAT: \
*(va_arg(args, float*)) = SPA_POD_VALUE(struct spa_pod_float, pod); \
break; \
case SPA_POD_TYPE_DOUBLE: \
*(va_arg(args, double*)) = SPA_POD_VALUE(struct spa_pod_double, pod); \
break; \
case SPA_POD_TYPE_STRING: \
*(va_arg(args, char **)) = SPA_POD_CONTENTS(struct spa_pod_string, pod); \
break; \
case -SPA_POD_TYPE_STRING: \
{ \
char *dest = va_arg(args, char *); \
uint32_t maxlen = va_arg(args, uint32_t); \
strncpy(dest, SPA_POD_CONTENTS(struct spa_pod_string, pod), maxlen-1); \
break; \
} \
case SPA_POD_TYPE_BYTES: \
*(va_arg(args, void **)) = SPA_POD_CONTENTS(struct spa_pod_bytes, pod); \
*(va_arg(args, uint32_t *)) = SPA_POD_BODY_SIZE(pod); \
break; \
case SPA_POD_TYPE_POINTER: \
{ \
struct spa_pod_pointer_body *b = SPA_POD_BODY(pod); \
*(va_arg(args, void **)) = b->value; \
break; \
} \
case SPA_POD_TYPE_RECTANGLE: \
*(va_arg(args, struct spa_rectangle *)) = \
SPA_POD_VALUE(struct spa_pod_rectangle, pod); \
break; \
case SPA_POD_TYPE_FRACTION: \
*(va_arg(args, struct spa_fraction *)) = \
SPA_POD_VALUE(struct spa_pod_fraction, pod); \
break; \
case SPA_POD_TYPE_BITMASK: \
*(va_arg(args, uint32_t **)) = SPA_POD_CONTENTS(struct spa_pod, pod); \
break; \
case SPA_POD_TYPE_ARRAY: \
case SPA_POD_TYPE_STRUCT: \
case SPA_POD_TYPE_OBJECT: \
case SPA_POD_TYPE_PROP: \
case -SPA_POD_TYPE_ARRAY: \
case -SPA_POD_TYPE_STRUCT: \
case -SPA_POD_TYPE_OBJECT: \
case -SPA_POD_TYPE_PROP: \
*(va_arg(args, struct spa_pod **)) = pod; \
break; \
default: \
goto error; \
} \
} else \
goto error; \
} while (false);
#define SPA_POD_COLLECT_SKIP(type,args) \
switch (type) { \
case SPA_POD_TYPE_BYTES: \
case SPA_POD_TYPE_POINTER: \
va_arg (args, void*); \
/* fallthrough */ \
case SPA_POD_TYPE_BOOL: \
case SPA_POD_TYPE_ID: \
case SPA_POD_TYPE_INT: \
case SPA_POD_TYPE_LONG: \
case SPA_POD_TYPE_FLOAT: \
case SPA_POD_TYPE_DOUBLE: \
case SPA_POD_TYPE_STRING: \
case -SPA_POD_TYPE_STRING: \
case SPA_POD_TYPE_RECTANGLE: \
case SPA_POD_TYPE_FRACTION: \
case SPA_POD_TYPE_BITMASK: \
case SPA_POD_TYPE_ARRAY: \
case SPA_POD_TYPE_STRUCT: \
case SPA_POD_TYPE_OBJECT: \
case SPA_POD_TYPE_PROP: \
case SPA_POD_TYPE_POD: \
case -SPA_POD_TYPE_ARRAY: \
case -SPA_POD_TYPE_STRUCT: \
case -SPA_POD_TYPE_OBJECT: \
case -SPA_POD_TYPE_PROP: \
va_arg(args, void*); \
default: \
break; \
}
static inline uint32_t
spa_pod_contents_queryv(const struct spa_pod *pod, uint32_t offset, uint32_t key, va_list args)
static inline struct spa_pod_prop *spa_pod_struct_find_prop(const struct spa_pod_struct *obj,
uint32_t key)
{
uint32_t count = 0;
while (key) {
uint32_t type;
struct spa_pod_prop *prop = spa_pod_contents_find_prop(pod, offset, key);
type = va_arg(args, uint32_t);
if (prop && prop->body.key == key && !(prop->body.flags & SPA_POD_PROP_FLAG_UNSET)) {
SPA_POD_COLLECT(&prop->body.value, type, args, next);
count++;
} else {
SPA_POD_COLLECT_SKIP(type, args);
}
next:
key = va_arg(args, uint32_t);
}
return count;
return spa_pod_contents_find_prop(&obj->pod, sizeof(struct spa_pod_struct), key);
}
static inline uint32_t
spa_pod_contents_query(const struct spa_pod *pod, uint32_t offset, uint32_t key, ...)
{
va_list args;
uint32_t count;
va_start(args, key);
count = spa_pod_contents_queryv(pod, offset, key, args);
va_end(args);
return count;
}
#define spa_pod_object_query(object,key, ...) \
spa_pod_contents_query(&(object)->pod, sizeof(struct spa_pod_object), key, __VA_ARGS__)
#define spa_pod_object_parse(object,...) \
({ \
struct spa_pod_parser __p; \
const struct spa_pod_object *__obj = object; \
spa_pod_parser_pod(&__p, &__obj->pod); \
spa_pod_parser_get(&__p, "<", ##__VA_ARGS__, NULL); \
})
#ifdef __cplusplus
} /* extern "C" */

View file

@ -43,23 +43,33 @@ extern "C" {
enum spa_pod_type {
SPA_POD_TYPE_INVALID = 0,
SPA_POD_TYPE_NONE = 1,
SPA_POD_TYPE_BOOL,
SPA_POD_TYPE_ID,
SPA_POD_TYPE_INT,
SPA_POD_TYPE_LONG,
SPA_POD_TYPE_FLOAT,
SPA_POD_TYPE_DOUBLE,
SPA_POD_TYPE_STRING,
SPA_POD_TYPE_BYTES,
SPA_POD_TYPE_POINTER,
SPA_POD_TYPE_RECTANGLE,
SPA_POD_TYPE_FRACTION,
SPA_POD_TYPE_BITMASK,
SPA_POD_TYPE_BITMAP,
SPA_POD_TYPE_ARRAY,
SPA_POD_TYPE_STRUCT,
SPA_POD_TYPE_OBJECT,
SPA_POD_TYPE_POINTER,
SPA_POD_TYPE_FD,
SPA_POD_TYPE_PROP,
SPA_POD_TYPE_POD,
SPA_POD_TYPE_CUSTOM_START = 64,
};
struct spa_pod {
@ -67,12 +77,6 @@ struct spa_pod {
uint32_t type; /* one of spa_pod_type */
};
struct spa_pod_int {
struct spa_pod pod;
int32_t value;
int32_t __padding;
};
struct spa_pod_bool {
struct spa_pod pod;
int32_t value;
@ -85,6 +89,12 @@ struct spa_pod_id {
int32_t __padding;
};
struct spa_pod_int {
struct spa_pod pod;
int32_t value;
int32_t __padding;
};
struct spa_pod_long {
struct spa_pod pod;
int64_t value;
@ -110,16 +120,6 @@ struct spa_pod_bytes {
/* value here */
};
struct spa_pod_pointer_body {
uint32_t type;
void *value;
};
struct spa_pod_pointer {
struct spa_pod pod;
struct spa_pod_pointer_body body;
};
struct spa_pod_rectangle {
struct spa_pod pod;
struct spa_rectangle value;
@ -150,6 +150,32 @@ struct spa_pod_struct {
/* one or more spa_pod follow */
};
struct spa_pod_object_body {
uint32_t id;
uint32_t type;
/* contents follow, series of spa_pod */
};
struct spa_pod_object {
struct spa_pod pod;
struct spa_pod_object_body body;
};
struct spa_pod_pointer_body {
uint32_t type;
void *value;
};
struct spa_pod_pointer {
struct spa_pod pod;
struct spa_pod_pointer_body body;
};
struct spa_pod_fd {
struct spa_pod pod;
int value;
};
struct spa_pod_prop_body {
uint32_t key;
#define SPA_POD_PROP_RANGE_NONE 0
@ -173,17 +199,6 @@ struct spa_pod_prop {
struct spa_pod_prop_body body;
};
struct spa_pod_object_body {
uint32_t id;
uint32_t type;
/* contents follow, series of spa_pod_prop */
};
struct spa_pod_object {
struct spa_pod pod;
struct spa_pod_object_body body;
};
#ifdef __cplusplus
} /* extern "C" */
#endif

View file

@ -26,6 +26,7 @@ extern "C" {
#include <spa/pod.h>
#include <spa/pod-builder.h>
#include <spa/pod-parser.h>
struct spa_props {
struct spa_pod_object object;
@ -58,20 +59,16 @@ spa_pod_builder_push_props(struct spa_pod_builder *builder,
return spa_pod_builder_push_object(builder, frame, 0, props_type);
}
#define spa_pod_builder_props(b,f,props_type,...) \
spa_pod_builder_object(b, f, 0, props_type,__VA_ARGS__)
#define spa_pod_builder_props(b,props_type,...) \
spa_pod_builder_object(b, 0, props_type,##__VA_ARGS__)
static inline uint32_t spa_props_query(const struct spa_props *props, uint32_t key, ...)
{
uint32_t count;
va_list args;
va_start(args, key);
count = spa_pod_contents_queryv(&props->object.pod, sizeof(struct spa_props), key, args);
va_end(args);
return count;
}
#define spa_props_parse(props,...) \
({ \
struct spa_pod_parser __p; \
const struct spa_props *__props = props; \
spa_pod_parser_pod(&__p, &__props->object.pod); \
spa_pod_parser_get(&__p, "<", ##__VA_ARGS__, NULL); \
})
#ifdef __cplusplus
} /* extern "C" */

View file

@ -74,50 +74,53 @@ spa_type_format_video_map(struct spa_type_map *map, struct spa_type_format_video
}
}
static inline bool
static inline int
spa_format_video_raw_parse(const struct spa_format *format,
struct spa_video_info_raw *info, struct spa_type_format_video *type)
{
spa_format_query(format,
type->format, SPA_POD_TYPE_ID, &info->format,
type->size, SPA_POD_TYPE_RECTANGLE, &info->size,
type->framerate, SPA_POD_TYPE_FRACTION, &info->framerate,
type->max_framerate, SPA_POD_TYPE_FRACTION, &info->max_framerate,
type->views, SPA_POD_TYPE_INT, &info->views,
type->interlace_mode, SPA_POD_TYPE_INT, &info->interlace_mode,
type->pixel_aspect_ratio, SPA_POD_TYPE_FRACTION, &info->pixel_aspect_ratio,
type->multiview_mode, SPA_POD_TYPE_INT, &info->multiview_mode,
type->multiview_flags, SPA_POD_TYPE_INT, &info->multiview_flags,
type->chroma_site, SPA_POD_TYPE_INT, &info->chroma_site,
type->color_range, SPA_POD_TYPE_INT, &info->color_range,
type->color_matrix, SPA_POD_TYPE_INT, &info->color_matrix,
type->transfer_function, SPA_POD_TYPE_INT, &info->transfer_function,
type->color_primaries, SPA_POD_TYPE_INT, &info->color_primaries, 0);
return true;
struct spa_pod_parser prs;
spa_pod_parser_pod(&prs, &format->pod);
return spa_pod_parser_get(&prs,
":",type->format, "I", &info->format,
":",type->size, "R", &info->size,
":",type->framerate, "F", &info->framerate,
":",type->max_framerate, "?F", &info->max_framerate,
":",type->views, "?i", &info->views,
":",type->interlace_mode, "?i", &info->interlace_mode,
":",type->pixel_aspect_ratio, "?F", &info->pixel_aspect_ratio,
":",type->multiview_mode, "?i", &info->multiview_mode,
":",type->multiview_flags, "?i", &info->multiview_flags,
":",type->chroma_site, "?i", &info->chroma_site,
":",type->color_range, "?i", &info->color_range,
":",type->color_matrix, "?i", &info->color_matrix,
":",type->transfer_function, "?i", &info->transfer_function,
":",type->color_primaries, "?i", &info->color_primaries, NULL);
}
static inline bool
static inline int
spa_format_video_h264_parse(const struct spa_format *format,
struct spa_video_info_h264 *info, struct spa_type_format_video *type)
{
spa_format_query(format,
type->size, SPA_POD_TYPE_RECTANGLE, &info->size,
type->framerate, SPA_POD_TYPE_FRACTION, &info->framerate,
type->max_framerate, SPA_POD_TYPE_FRACTION, &info->max_framerate,
type->stream_format, SPA_POD_TYPE_INT, &info->stream_format,
type->alignment, SPA_POD_TYPE_INT, &info->alignment, 0);
return true;
struct spa_pod_parser prs;
spa_pod_parser_pod(&prs, &format->pod);
return spa_pod_parser_get(&prs,
":",type->size, "?R", &info->size,
":",type->framerate, "?F", &info->framerate,
":",type->max_framerate, "?F", &info->max_framerate,
":",type->stream_format, "?i", &info->stream_format,
":",type->alignment, "?i", &info->alignment, NULL);
}
static inline bool
static inline int
spa_format_video_mjpg_parse(const struct spa_format *format,
struct spa_video_info_mjpg *info, struct spa_type_format_video *type)
{
spa_format_query(format,
type->size, SPA_POD_TYPE_RECTANGLE, &info->size,
type->framerate, SPA_POD_TYPE_FRACTION, &info->framerate,
type->max_framerate, SPA_POD_TYPE_FRACTION, &info->max_framerate, 0);
return true;
struct spa_pod_parser prs;
spa_pod_parser_pod(&prs, &format->pod);
return spa_pod_parser_get(&prs,
":",type->size, "?R", &info->size,
":",type->framerate, "?F", &info->framerate,
":",type->max_framerate, "?F", &info->max_framerate, NULL);
}
#ifdef __cplusplus