mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
spa_json_init assumes that we start in an object and always requires a key/value pair. If the last part is a key, it returns and error and does not want to return the key value. This causes problems when parsing AUX0,AUX1,AUX2 or any relaxed array withand odd number of elements. Make a new spa_json_init_relax that takes the type of the container we're assuming we're in and set the state of the parser to array when we are parsing a relaxed array. Fixes #4944
223 lines
5.5 KiB
C
223 lines
5.5 KiB
C
/* Simple Plugin API */
|
|
/* SPDX-FileCopyrightText: Copyright © 2020 Wim Taymans */
|
|
/* SPDX-License-Identifier: MIT */
|
|
|
|
#ifndef SPA_UTILS_JSON_UTILS_H
|
|
#define SPA_UTILS_JSON_UTILS_H
|
|
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <float.h>
|
|
|
|
#include <spa/utils/json-core.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#else
|
|
#include <stdbool.h>
|
|
#endif
|
|
|
|
#ifndef SPA_API_JSON_UTILS
|
|
#ifdef SPA_API_IMPL
|
|
#define SPA_API_JSON_UTILS SPA_API_IMPL
|
|
#else
|
|
#define SPA_API_JSON_UTILS static inline
|
|
#endif
|
|
#endif
|
|
|
|
/** \defgroup spa_json_utils JSON Utils
|
|
* Relaxed JSON variant parsing Utils
|
|
*/
|
|
|
|
/**
|
|
* \addtogroup spa_json
|
|
* \{
|
|
*/
|
|
|
|
SPA_API_JSON_UTILS int spa_json_begin(struct spa_json * iter, const char *data, size_t size, const char **val)
|
|
{
|
|
spa_json_init(iter, data, size);
|
|
return spa_json_next(iter, val);
|
|
}
|
|
|
|
/* float */
|
|
SPA_API_JSON_UTILS int spa_json_get_float(struct spa_json *iter, float *res)
|
|
{
|
|
const char *value;
|
|
int len;
|
|
if ((len = spa_json_next(iter, &value)) <= 0)
|
|
return len;
|
|
return spa_json_parse_float(value, len, res);
|
|
}
|
|
|
|
/* int */
|
|
SPA_API_JSON_UTILS int spa_json_get_int(struct spa_json *iter, int *res)
|
|
{
|
|
const char *value;
|
|
int len;
|
|
if ((len = spa_json_next(iter, &value)) <= 0)
|
|
return len;
|
|
return spa_json_parse_int(value, len, res);
|
|
}
|
|
|
|
/* bool */
|
|
SPA_API_JSON_UTILS int spa_json_get_bool(struct spa_json *iter, bool *res)
|
|
{
|
|
const char *value;
|
|
int len;
|
|
if ((len = spa_json_next(iter, &value)) <= 0)
|
|
return len;
|
|
return spa_json_parse_bool(value, len, res);
|
|
}
|
|
|
|
/* string */
|
|
SPA_API_JSON_UTILS int spa_json_get_string(struct spa_json *iter, char *res, int maxlen)
|
|
{
|
|
const char *value;
|
|
int len;
|
|
if ((len = spa_json_next(iter, &value)) <= 0)
|
|
return len;
|
|
return spa_json_parse_stringn(value, len, res, maxlen);
|
|
}
|
|
|
|
|
|
SPA_API_JSON_UTILS int spa_json_enter_container(struct spa_json *iter, struct spa_json *sub, char type)
|
|
{
|
|
const char *value;
|
|
int len;
|
|
if ((len = spa_json_next(iter, &value)) <= 0)
|
|
return len;
|
|
if (!spa_json_is_container(value, len))
|
|
return -EPROTO;
|
|
if (*value != type)
|
|
return -EINVAL;
|
|
spa_json_enter(iter, sub);
|
|
return 1;
|
|
}
|
|
|
|
SPA_API_JSON_UTILS int spa_json_begin_container(struct spa_json * iter,
|
|
const char *data, size_t size, char type, bool relax)
|
|
{
|
|
int res;
|
|
spa_json_init(iter, data, size);
|
|
res = spa_json_enter_container(iter, iter, type);
|
|
if (res == -EPROTO && relax)
|
|
spa_json_init_relax(iter, type, data, size);
|
|
else if (res <= 0)
|
|
return res;
|
|
return 1;
|
|
}
|
|
/**
|
|
* Return length of container at current position, starting at \a value.
|
|
*
|
|
* \return Length of container including {} or [], or 0 on error.
|
|
*/
|
|
SPA_API_JSON_UTILS int spa_json_container_len(struct spa_json *iter, const char *value, int len SPA_UNUSED)
|
|
{
|
|
const char *val;
|
|
struct spa_json sub;
|
|
int res;
|
|
spa_json_enter(iter, &sub);
|
|
while ((res = spa_json_next(&sub, &val)) > 0);
|
|
if (res < 0)
|
|
return 0;
|
|
return sub.cur + 1 - value;
|
|
}
|
|
|
|
/* object */
|
|
SPA_API_JSON_UTILS int spa_json_enter_object(struct spa_json *iter, struct spa_json *sub)
|
|
{
|
|
return spa_json_enter_container(iter, sub, '{');
|
|
}
|
|
SPA_API_JSON_UTILS int spa_json_begin_object_relax(struct spa_json * iter, const char *data, size_t size)
|
|
{
|
|
return spa_json_begin_container(iter, data, size, '{', true);
|
|
}
|
|
SPA_API_JSON_UTILS int spa_json_begin_object(struct spa_json * iter, const char *data, size_t size)
|
|
{
|
|
return spa_json_begin_container(iter, data, size, '{', false);
|
|
}
|
|
|
|
SPA_API_JSON_UTILS int spa_json_object_next(struct spa_json *iter, char *key, int maxkeylen, const char **value)
|
|
{
|
|
int res1, res2;
|
|
while (true) {
|
|
res1 = spa_json_get_string(iter, key, maxkeylen);
|
|
if (res1 <= 0 && res1 != -ENOSPC)
|
|
return res1;
|
|
res2 = spa_json_next(iter, value);
|
|
if (res2 <= 0 || res1 != -ENOSPC)
|
|
return res2;
|
|
}
|
|
}
|
|
|
|
SPA_API_JSON_UTILS int spa_json_object_find(struct spa_json *iter, const char *key, const char **value)
|
|
{
|
|
struct spa_json obj = SPA_JSON_SAVE(iter);
|
|
int res, len = strlen(key) + 3;
|
|
char k[len];
|
|
|
|
while ((res = spa_json_object_next(&obj, k, len, value)) > 0)
|
|
if (spa_streq(k, key))
|
|
return res;
|
|
return -ENOENT;
|
|
}
|
|
|
|
SPA_API_JSON_UTILS int spa_json_str_object_find(const char *obj, size_t obj_len,
|
|
const char *key, char *value, size_t maxlen)
|
|
{
|
|
struct spa_json iter;
|
|
int l;
|
|
const char *v;
|
|
|
|
if (spa_json_begin_object(&iter, obj, obj_len) <= 0)
|
|
return -EINVAL;
|
|
if ((l = spa_json_object_find(&iter, key, &v)) <= 0)
|
|
return l;
|
|
return spa_json_parse_stringn(v, l, value, maxlen);
|
|
}
|
|
|
|
/* array */
|
|
SPA_API_JSON_UTILS int spa_json_enter_array(struct spa_json *iter, struct spa_json *sub)
|
|
{
|
|
return spa_json_enter_container(iter, sub, '[');
|
|
}
|
|
SPA_API_JSON_UTILS int spa_json_begin_array_relax(struct spa_json * iter, const char *data, size_t size)
|
|
{
|
|
return spa_json_begin_container(iter, data, size, '[', true);
|
|
}
|
|
SPA_API_JSON_UTILS int spa_json_begin_array(struct spa_json * iter, const char *data, size_t size)
|
|
{
|
|
return spa_json_begin_container(iter, data, size, '[', false);
|
|
}
|
|
|
|
#define spa_json_make_str_array_unpack(maxlen,type,conv) \
|
|
{ \
|
|
struct spa_json iter; \
|
|
char v[maxlen]; \
|
|
uint32_t count = 0; \
|
|
if (spa_json_begin_array_relax(&iter, arr, arr_len) <= 0) \
|
|
return -EINVAL; \
|
|
while (spa_json_get_string(&iter, v, sizeof(v)) > 0 && count < max) \
|
|
values[count++] = conv(v); \
|
|
return count; \
|
|
}
|
|
|
|
SPA_API_JSON_UTILS int spa_json_str_array_uint32(const char *arr, size_t arr_len,
|
|
uint32_t *values, size_t max)
|
|
{
|
|
spa_json_make_str_array_unpack(32,uint32_t, atoi);
|
|
}
|
|
|
|
/**
|
|
* \}
|
|
*/
|
|
|
|
#ifdef __cplusplus
|
|
} /* extern "C" */
|
|
#endif
|
|
|
|
#endif /* SPA_UTILS_JSON_UTILS_H */
|