mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-02 09:01:50 -05:00
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:
parent
3e49aec61b
commit
24d80e5c00
54 changed files with 3616 additions and 2817 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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" */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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__)
|
||||
|
|
|
|||
67
spa/include/spa/json-builder.h
Normal file
67
spa/include/spa/json-builder.h
Normal 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
510
spa/include/spa/json.h
Normal 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__ */
|
||||
|
|
@ -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(¶m->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); \
|
||||
|
|
|
|||
|
|
@ -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" */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
313
spa/include/spa/pod-parser.h
Normal file
313
spa/include/spa/pod-parser.h
Normal 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__ */
|
||||
|
|
@ -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" */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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" */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue