Loading...
Searching...
No Matches
json-core.h
Go to the documentation of this file.
/* Simple Plugin API */
/* SPDX-FileCopyrightText: Copyright © 2020 Wim Taymans */
/* SPDX-License-Identifier: MIT */
#ifndef SPA_UTILS_JSON_H
#define SPA_UTILS_JSON_H
#include <stddef.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <float.h>
#include <spa/utils/defs.h>
#include <spa/utils/string.h>
#ifdef __cplusplus
extern "C" {
#else
#include <stdbool.h>
#endif
#ifndef SPA_API_JSON
#ifdef SPA_API_IMPL
#define SPA_API_JSON SPA_API_IMPL
#else
#define SPA_API_JSON static inline
#endif
#endif
/* a simple JSON compatible tokenizer */
struct spa_json {
const char *cur;
const char *end;
struct spa_json *parent;
#define SPA_JSON_ERROR_FLAG 0x100
uint32_t state;
uint32_t depth;
};
#define SPA_JSON_INIT(data,size) ((struct spa_json) { (data), (data)+(size), NULL, 0, 0 })
SPA_API_JSON void spa_json_init(struct spa_json * iter, const char *data, size_t size)
{
*iter = SPA_JSON_INIT(data, size);
}
#define SPA_JSON_INIT_RELAX(type,data,size) \
((struct spa_json) { (data), (data)+(size), NULL, (uint32_t)((type) == '[' ? 0x10 : 0x0), 0 })
SPA_API_JSON void spa_json_init_relax(struct spa_json * iter, char type, const char *data, size_t size)
{
*iter = SPA_JSON_INIT_RELAX(type, data, size);
}
#define SPA_JSON_ENTER(iter) ((struct spa_json) { (iter)->cur, (iter)->end, (iter), (iter)->state & 0xff0, 0 })
SPA_API_JSON void spa_json_enter(struct spa_json * iter, struct spa_json * sub)
{
*sub = SPA_JSON_ENTER(iter);
}
#define SPA_JSON_SAVE(iter) ((struct spa_json) { (iter)->cur, (iter)->end, NULL, (iter)->state, 0 })
SPA_API_JSON void spa_json_save(struct spa_json * iter, struct spa_json * save)
{
*save = SPA_JSON_SAVE(iter);
}
#define SPA_JSON_START(iter,p) ((struct spa_json) { (p), (iter)->end, NULL, 0, 0 })
SPA_API_JSON void spa_json_start(struct spa_json * iter, struct spa_json * sub, const char *pos)
{
*sub = SPA_JSON_START(iter,pos);
}
SPA_API_JSON int spa_json_next(struct spa_json * iter, const char **value)
{
int utf8_remain = 0, err = 0;
enum {
__NONE, __STRUCT, __BARE, __STRING, __UTF8, __ESC, __COMMENT,
__ARRAY_FLAG = 0x10, /* in array context */
__PREV_ARRAY_FLAG = 0x20, /* depth=0 array context flag */
__KEY_FLAG = 0x40, /* inside object key */
__SUB_FLAG = 0x80, /* not at top-level */
__FLAGS = 0xff0,
__ERROR_SYSTEM = SPA_JSON_ERROR_FLAG,
__ERROR_INVALID_ARRAY_SEPARATOR,
__ERROR_EXPECTED_OBJECT_KEY,
__ERROR_EXPECTED_OBJECT_VALUE,
__ERROR_TOO_DEEP_NESTING,
__ERROR_EXPECTED_ARRAY_CLOSE,
__ERROR_EXPECTED_OBJECT_CLOSE,
__ERROR_MISMATCHED_BRACKET,
__ERROR_ESCAPE_NOT_ALLOWED,
__ERROR_CHARACTERS_NOT_ALLOWED,
__ERROR_INVALID_ESCAPE,
__ERROR_INVALID_STATE,
__ERROR_UNFINISHED_STRING,
};
uint64_t array_stack[8] = {0}; /* array context flags of depths 1...512 */
*value = iter->cur;
if (iter->state & SPA_JSON_ERROR_FLAG)
return -1;
for (; iter->cur < iter->end; iter->cur++) {
unsigned char cur = (unsigned char)*iter->cur;
uint32_t flag;
#define _SPA_ERROR(reason) { err = __ERROR_ ## reason; goto error; }
again:
flag = iter->state & __FLAGS;
switch (iter->state & ~__FLAGS) {
case __NONE:
flag &= ~(__KEY_FLAG | __PREV_ARRAY_FLAG);
iter->state = __STRUCT | flag;
iter->depth = 0;
goto again;
case __STRUCT:
switch (cur) {
case '\0': case '\t': case ' ': case '\r': case '\n': case ',':
continue;
case ':': case '=':
if (flag & __ARRAY_FLAG)
_SPA_ERROR(INVALID_ARRAY_SEPARATOR);
if (!(flag & __KEY_FLAG))
_SPA_ERROR(EXPECTED_OBJECT_KEY);
iter->state |= __SUB_FLAG;
continue;
case '#':
iter->state = __COMMENT | flag;
continue;
case '"':
if (flag & __KEY_FLAG)
flag |= __SUB_FLAG;
if (!(flag & __ARRAY_FLAG))
SPA_FLAG_UPDATE(flag, __KEY_FLAG, !(flag & __KEY_FLAG));
*value = iter->cur;
iter->state = __STRING | flag;
continue;
case '[': case '{':
if (!(flag & __ARRAY_FLAG)) {
/* At top-level we may be either in object context
* or in single-item context, and then we need to
* accept array/object here.
*/
if ((iter->state & __SUB_FLAG) && !(flag & __KEY_FLAG))
_SPA_ERROR(EXPECTED_OBJECT_KEY);
SPA_FLAG_CLEAR(flag, __KEY_FLAG);
}
iter->state = __STRUCT | __SUB_FLAG | flag;
SPA_FLAG_UPDATE(iter->state, __ARRAY_FLAG, cur == '[');
/* We need to remember previous array state across calls
* for depth=0, so store that in state. Others bits go to
* temporary stack.
*/
if (iter->depth == 0) {
SPA_FLAG_UPDATE(iter->state, __PREV_ARRAY_FLAG, flag & __ARRAY_FLAG);
} else if (((iter->depth-1) >> 6) < SPA_N_ELEMENTS(array_stack)) {
uint64_t mask = 1ULL << ((iter->depth-1) & 0x3f);
SPA_FLAG_UPDATE(array_stack[(iter->depth-1) >> 6], mask, flag & __ARRAY_FLAG);
} else {
/* too deep */
_SPA_ERROR(TOO_DEEP_NESTING);
}
*value = iter->cur;
if (++iter->depth > 1)
continue;
iter->cur++;
return 1;
case '}': case ']':
if ((flag & __ARRAY_FLAG) && cur != ']')
_SPA_ERROR(EXPECTED_ARRAY_CLOSE);
if (!(flag & __ARRAY_FLAG) && cur != '}')
_SPA_ERROR(EXPECTED_OBJECT_CLOSE);
if (flag & __KEY_FLAG) {
/* incomplete key-value pair */
_SPA_ERROR(EXPECTED_OBJECT_VALUE);
}
iter->state = __STRUCT | __SUB_FLAG | flag;
if (iter->depth == 0) {
if (iter->parent)
iter->parent->cur = iter->cur;
else
_SPA_ERROR(MISMATCHED_BRACKET);
return 0;
}
--iter->depth;
if (iter->depth == 0) {
SPA_FLAG_UPDATE(iter->state, __ARRAY_FLAG, flag & __PREV_ARRAY_FLAG);
} else if (((iter->depth-1) >> 6) < SPA_N_ELEMENTS(array_stack)) {
uint64_t mask = 1ULL << ((iter->depth-1) & 0x3f);
SPA_FLAG_UPDATE(iter->state, __ARRAY_FLAG,
SPA_FLAG_IS_SET(array_stack[(iter->depth-1) >> 6], mask));
} else {
/* too deep */
_SPA_ERROR(TOO_DEEP_NESTING);
}
continue;
case '\\':
/* disallow bare escape */
_SPA_ERROR(ESCAPE_NOT_ALLOWED);
default:
/* allow bare ascii */
if (!(cur >= 32 && cur <= 126))
_SPA_ERROR(CHARACTERS_NOT_ALLOWED);
if (flag & __KEY_FLAG)
flag |= __SUB_FLAG;
if (!(flag & __ARRAY_FLAG))
SPA_FLAG_UPDATE(flag, __KEY_FLAG, !(flag & __KEY_FLAG));
*value = iter->cur;
iter->state = __BARE | flag;
}
continue;
case __BARE:
switch (cur) {
case '\0':
case '\t': case ' ': case '\r': case '\n':
case '"': case '#':
case ':': case ',': case '=': case ']': case '}':
iter->state = __STRUCT | flag;
if (iter->depth > 0)
goto again;
return iter->cur - *value;
case '\\':
/* disallow bare escape */
_SPA_ERROR(ESCAPE_NOT_ALLOWED);
default:
/* allow bare ascii */
if (cur >= 32 && cur <= 126)
continue;
}
_SPA_ERROR(CHARACTERS_NOT_ALLOWED);
case __STRING:
switch (cur) {
case '\\':
iter->state = __ESC | flag;
continue;
case '"':
iter->state = __STRUCT | flag;
if (iter->depth > 0)
continue;
return ++iter->cur - *value;
case 240 ... 247:
utf8_remain++;
SPA_FALLTHROUGH;
case 224 ... 239:
utf8_remain++;
SPA_FALLTHROUGH;
case 192 ... 223:
utf8_remain++;
iter->state = __UTF8 | flag;
continue;
default:
if (cur >= 32 && cur <= 127)
continue;
}
_SPA_ERROR(CHARACTERS_NOT_ALLOWED);
case __UTF8:
switch (cur) {
case 128 ... 191:
if (--utf8_remain == 0)
iter->state = __STRING | flag;
continue;
default:
break;
}
_SPA_ERROR(CHARACTERS_NOT_ALLOWED);
case __ESC:
switch (cur) {
case '"': case '\\': case '/': case 'b': case 'f':
case 'n': case 'r': case 't': case 'u':
iter->state = __STRING | flag;
continue;
default:
break;
}
_SPA_ERROR(INVALID_ESCAPE);
case __COMMENT:
switch (cur) {
case '\n': case '\r':
iter->state = __STRUCT | flag;
break;
default:
break;
}
break;
default:
_SPA_ERROR(INVALID_STATE);
}
}
if (iter->depth != 0 || iter->parent)
_SPA_ERROR(MISMATCHED_BRACKET);
switch (iter->state & ~__FLAGS) {
case __STRING: case __UTF8: case __ESC:
/* string/escape not closed */
_SPA_ERROR(UNFINISHED_STRING);
case __COMMENT:
/* trailing comment */
return 0;
default:
break;
}
if ((iter->state & __SUB_FLAG) && (iter->state & __KEY_FLAG)) {
/* incomplete key-value pair */
_SPA_ERROR(EXPECTED_OBJECT_VALUE);
}
if ((iter->state & ~__FLAGS) != __STRUCT) {
iter->state = __STRUCT | (iter->state & __FLAGS);
return iter->cur - *value;
}
return 0;
#undef _SPA_ERROR
error:
iter->state = err;
while (iter->parent) {
if (iter->parent->state & SPA_JSON_ERROR_FLAG)
break;
iter->parent->state = err;
iter->parent->cur = iter->cur;
iter = iter->parent;
}
return -1;
}
SPA_API_JSON bool spa_json_get_error(struct spa_json *iter, const char *start,
struct spa_error_location *loc)
{
static const char *reasons[] = {
"System error",
"Invalid array separator",
"Expected object key",
"Expected object value",
"Too deep nesting",
"Expected array close bracket",
"Expected object close brace",
"Mismatched bracket",
"Escape not allowed",
"Character not allowed",
"Invalid escape",
"Invalid state",
"Unfinished string",
"Expected key separator",
};
if (!(iter->state & SPA_JSON_ERROR_FLAG))
return false;
if (loc) {
int linepos = 1, colpos = 1, code;
const char *p, *l;
for (l = p = start; p && p != iter->cur; ++p) {
if (*p == '\n') {
linepos++;
colpos = 1;
l = p+1;
} else {
colpos++;
}
}
code = SPA_CLAMP(iter->state & 0xff, 0u, SPA_N_ELEMENTS(reasons)-1);
loc->line = linepos;
loc->col = colpos;
loc->location = l;
loc->len = SPA_PTRDIFF(iter->end, loc->location) / sizeof(char);
loc->reason = code == 0 ? strerror(errno) : reasons[code];
}
return true;
}
SPA_API_JSON int spa_json_is_container(const char *val, int len)
{
return len > 0 && (*val == '{' || *val == '[');
}
/* object */
SPA_API_JSON int spa_json_is_object(const char *val, int len)
{
return len > 0 && *val == '{';
}
/* array */
SPA_API_JSON bool spa_json_is_array(const char *val, int len)
{
return len > 0 && *val == '[';
}
/* null */
SPA_API_JSON bool spa_json_is_null(const char *val, int len)
{
return len == 4 && strncmp(val, "null", 4) == 0;
}
/* float */
SPA_API_JSON int spa_json_parse_float(const char *val, int len, float *result)
{
char buf[96];
char *end;
int pos;
if (len <= 0 || len >= (int)sizeof(buf))
return 0;
for (pos = 0; pos < len; ++pos) {
switch (val[pos]) {
case '+': case '-': case '0' ... '9': case '.': case 'e': case 'E': break;
default: return 0;
}
}
memcpy(buf, val, len);
buf[len] = '\0';
*result = spa_strtof(buf, &end);
return len > 0 && end == buf + len;
}
SPA_API_JSON bool spa_json_is_float(const char *val, int len)
{
float dummy;
return spa_json_parse_float(val, len, &dummy);
}
SPA_API_JSON char *spa_json_format_float(char *str, int size, float val)
{
if (SPA_UNLIKELY(!isnormal(val))) {
if (isinf(val))
val = signbit(val) ? FLT_MIN : FLT_MAX;
else
val = 0.0f;
}
return spa_dtoa(str, size, val);
}
/* int */
SPA_API_JSON int spa_json_parse_int(const char *val, int len, int *result)
{
char buf[64];
char *end;
if (len <= 0 || len >= (int)sizeof(buf))
return 0;
memcpy(buf, val, len);
buf[len] = '\0';
*result = strtol(buf, &end, 0);
return len > 0 && end == buf + len;
}
SPA_API_JSON bool spa_json_is_int(const char *val, int len)
{
int dummy;
return spa_json_parse_int(val, len, &dummy);
}
/* bool */
SPA_API_JSON bool spa_json_is_true(const char *val, int len)
{
return len == 4 && strncmp(val, "true", 4) == 0;
}
SPA_API_JSON bool spa_json_is_false(const char *val, int len)
{
return len == 5 && strncmp(val, "false", 5) == 0;
}
SPA_API_JSON bool spa_json_is_bool(const char *val, int len)
{
return spa_json_is_true(val, len) || spa_json_is_false(val, len);
}
SPA_API_JSON int spa_json_parse_bool(const char *val, int len, bool *result)
{
if ((*result = spa_json_is_true(val, len)))
return 1;
if (!(*result = !spa_json_is_false(val, len)))
return 1;
return -1;
}
/* string */
SPA_API_JSON bool spa_json_is_string(const char *val, int len)
{
return len > 1 && *val == '"';
}
SPA_API_JSON int spa_json_parse_hex(const char *p, int num, uint32_t *res)
{
int i;
*res = 0;
for (i = 0; i < num; i++) {
char v = p[i];
if (v >= '0' && v <= '9')
v = v - '0';
else if (v >= 'a' && v <= 'f')
v = v - 'a' + 10;
else if (v >= 'A' && v <= 'F')
v = v - 'A' + 10;
else
return -1;
*res = (*res << 4) | v;
}
return 1;
}
SPA_API_JSON int spa_json_parse_stringn(const char *val, int len, char *result, int maxlen)
{
const char *p;
if (maxlen <= len)
return -ENOSPC;
if (!spa_json_is_string(val, len)) {
if (result != val)
memmove(result, val, len);
result += len;
} else {
for (p = val+1; p < val + len; p++) {
if (*p == '\\') {
p++;
if (*p == 'n')
*result++ = '\n';
else if (*p == 'r')
*result++ = '\r';
else if (*p == 'b')
*result++ = '\b';
else if (*p == 't')
*result++ = '\t';
else if (*p == 'f')
*result++ = '\f';
else if (*p == 'u') {
uint8_t prefix[] = { 0, 0xc0, 0xe0, 0xf0 };
uint32_t idx, n, v, cp, enc[] = { 0x80, 0x800, 0x10000 };
if (val + len - p < 5 ||
spa_json_parse_hex(p+1, 4, &cp) < 0) {
*result++ = *p;
continue;
}
p += 4;
if (cp >= 0xd800 && cp <= 0xdbff) {
if (val + len - p < 7 ||
p[1] != '\\' || p[2] != 'u' ||
spa_json_parse_hex(p+3, 4, &v) < 0 ||
v < 0xdc00 || v > 0xdfff)
continue;
p += 6;
cp = 0x010000 + (((cp & 0x3ff) << 10) | (v & 0x3ff));
} else if (cp >= 0xdc00 && cp <= 0xdfff)
continue;
for (idx = 0; idx < 3; idx++)
if (cp < enc[idx])
break;
for (n = idx; n > 0; n--, cp >>= 6)
result[n] = (cp | 0x80) & 0xbf;
*result++ = (cp | prefix[idx]) & 0xff;
result += idx;
} else
*result++ = *p;
} else if (*p == '\"') {
break;
} else
*result++ = *p;
}
}
*result = '\0';
return 1;
}
SPA_API_JSON int spa_json_parse_string(const char *val, int len, char *result)
{
return spa_json_parse_stringn(val, len, result, len+1);
}
SPA_API_JSON int spa_json_encode_string(char *str, int size, const char *val)
{
int len = 0;
static const char hex[] = { "0123456789abcdef" };
#define __PUT(c) { if (len < size) *str++ = c; len++; }
__PUT('"');
while (*val) {
switch (*val) {
case '\n':
__PUT('\\'); __PUT('n');
break;
case '\r':
__PUT('\\'); __PUT('r');
break;
case '\b':
__PUT('\\'); __PUT('b');
break;
case '\t':
__PUT('\\'); __PUT('t');
break;
case '\f':
__PUT('\\'); __PUT('f');
break;
case '\\':
case '"':
__PUT('\\'); __PUT(*val);
break;
default:
if (*val > 0 && *val < 0x20) {
__PUT('\\'); __PUT('u');
__PUT('0'); __PUT('0');
__PUT(hex[((*val)>>4)&0xf]); __PUT(hex[(*val)&0xf]);
} else {
__PUT(*val);
}
break;
}
val++;
}
__PUT('"');
__PUT('\0');
#undef __PUT
return len-1;
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* SPA_UTILS_JSON_H */
defs.h
spa/utils/defs.h
res
uint32_t int int res
Definition core.h:433
SPA_JSON_SAVE
#define SPA_JSON_SAVE(iter)
Definition json-core.h:84
spa_json_init
SPA_API_JSON void spa_json_init(struct spa_json *iter, const char *data, size_t size)
Definition json-core.h:62
spa_json_is_string
SPA_API_JSON bool spa_json_is_string(const char *val, int len)
Definition json-core.h:521
spa_json_next
SPA_API_JSON int spa_json_next(struct spa_json *iter, const char **value)
Get the next token.
Definition json-core.h:101
spa_json_is_object
SPA_API_JSON int spa_json_is_object(const char *val, int len)
Definition json-core.h:416
spa_json_parse_hex
SPA_API_JSON int spa_json_parse_hex(const char *p, int num, uint32_t *res)
Definition json-core.h:526
spa_json_parse_float
SPA_API_JSON int spa_json_parse_float(const char *val, int len, float *result)
Definition json-core.h:434
spa_json_format_float
SPA_API_JSON char * spa_json_format_float(char *str, int size, float val)
Definition json-core.h:463
spa_json_get_error
SPA_API_JSON bool spa_json_get_error(struct spa_json *iter, const char *start, struct spa_error_location *loc)
Return if there was a parse error, and its possible location.
Definition json-core.h:364
spa_json_parse_int
SPA_API_JSON int spa_json_parse_int(const char *val, int len, int *result)
Definition json-core.h:475
SPA_JSON_INIT_RELAX
#define SPA_JSON_INIT_RELAX(type, data, size)
Definition json-core.h:67
spa_json_is_null
SPA_API_JSON bool spa_json_is_null(const char *val, int len)
Definition json-core.h:428
spa_json_is_true
SPA_API_JSON bool spa_json_is_true(const char *val, int len)
Definition json-core.h:496
SPA_JSON_INIT
#define SPA_JSON_INIT(data, size)
Definition json-core.h:60
spa_json_is_bool
SPA_API_JSON bool spa_json_is_bool(const char *val, int len)
Definition json-core.h:506
spa_json_init_relax
SPA_API_JSON void spa_json_init_relax(struct spa_json *iter, char type, const char *data, size_t size)
Definition json-core.h:70
SPA_JSON_ERROR_FLAG
#define SPA_JSON_ERROR_FLAG
Definition json-core.h:54
spa_json_parse_bool
SPA_API_JSON int spa_json_parse_bool(const char *val, int len, bool *result)
Definition json-core.h:511
spa_json_is_int
SPA_API_JSON bool spa_json_is_int(const char *val, int len)
Definition json-core.h:489
SPA_JSON_ENTER
#define SPA_JSON_ENTER(iter)
Definition json-core.h:76
spa_json_start
SPA_API_JSON void spa_json_start(struct spa_json *iter, struct spa_json *sub, const char *pos)
Definition json-core.h:94
spa_json_parse_stringn
SPA_API_JSON int spa_json_parse_stringn(const char *val, int len, char *result, int maxlen)
Definition json-core.h:545
spa_json_enter
SPA_API_JSON void spa_json_enter(struct spa_json *iter, struct spa_json *sub)
Definition json-core.h:78
spa_json_is_array
SPA_API_JSON bool spa_json_is_array(const char *val, int len)
Definition json-core.h:422
spa_json_save
SPA_API_JSON void spa_json_save(struct spa_json *iter, struct spa_json *save)
Definition json-core.h:86
spa_json_is_false
SPA_API_JSON bool spa_json_is_false(const char *val, int len)
Definition json-core.h:501
spa_json_parse_string
SPA_API_JSON int spa_json_parse_string(const char *val, int len, char *result)
Definition json-core.h:608
SPA_JSON_START
#define SPA_JSON_START(iter, p)
Definition json-core.h:92
spa_json_is_float
SPA_API_JSON bool spa_json_is_float(const char *val, int len)
Definition json-core.h:457
spa_json_is_container
SPA_API_JSON int spa_json_is_container(const char *val, int len)
Definition json-core.h:410
spa_json_encode_string
SPA_API_JSON int spa_json_encode_string(char *str, int size, const char *val)
Definition json-core.h:613
spa_dtoa
SPA_API_STRING char * spa_dtoa(char *str, size_t size, double val)
Definition string.h:365
spa_strtof
SPA_API_STRING float spa_strtof(const char *str, char **endptr)
Convert str to a float in the C locale.
Definition string.h:272
SPA_CLAMP
#define SPA_CLAMP(v, low, high)
Definition defs.h:177
SPA_FLAG_UPDATE
#define SPA_FLAG_UPDATE(field, flag, val)
Definition defs.h:104
SPA_N_ELEMENTS
#define SPA_N_ELEMENTS(arr)
Definition defs.h:143
SPA_FLAG_IS_SET
#define SPA_FLAG_IS_SET(field, flag)
Definition defs.h:90
SPA_UNLIKELY
#define SPA_UNLIKELY(x)
Definition defs.h:398
SPA_FALLTHROUGH
#define SPA_FALLTHROUGH
SPA_FALLTHROUGH is an annotation to suppress compiler warnings about switch cases that fall through w...
Definition defs.h:84
SPA_FLAG_CLEAR
#define SPA_FLAG_CLEAR(field, flag)
Definition defs.h:94
SPA_PTRDIFF
#define SPA_PTRDIFF(p1, p2)
Definition defs.h:238
SPA_API_JSON
#define SPA_API_JSON
Definition json-core.h:35
_SPA_ERROR
#define _SPA_ERROR(reason)
__PUT
#define __PUT(c)
string.h
spa/utils/string.h
spa_error_location
Definition defs.h:443
spa_error_location::line
int line
Definition defs.h:444
spa_error_location::location
const char * location
Definition defs.h:447
spa_error_location::col
int col
Definition defs.h:445
spa_error_location::len
size_t len
Definition defs.h:446
spa_error_location::reason
const char * reason
Definition defs.h:448
spa_json
Definition json-core.h:49
spa_json::depth
uint32_t depth
Definition json-core.h:56
spa_json::cur
const char * cur
Definition json-core.h:50
spa_json::state
uint32_t state
Definition json-core.h:55
spa_json::end
const char * end
Definition json-core.h:51
spa_json::parent
struct spa_json * parent
Definition json-core.h:52