mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2025-01-24 15:41:55 +00:00
48e8894b74
To parse poses from non-Monado configs with non-standard member names.
449 lines
7.4 KiB
C
449 lines
7.4 KiB
C
// Copyright 2019-2020, Collabora, Ltd.
|
|
// SPDX-License-Identifier: BSL-1.0
|
|
/*!
|
|
* @file
|
|
* @brief Tiny JSON wrapper around cJSON.
|
|
* @author Jakob Bornecrantz <jakob@collabora.com>
|
|
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
|
|
* @ingroup aux_util
|
|
*/
|
|
|
|
#include "util/u_json.h"
|
|
#ifndef XRT_HAVE_SYSTEM_CJSON
|
|
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
|
#define _CRT_SECURE_NO_WARNINGS
|
|
#endif
|
|
#endif
|
|
|
|
#include "util/u_logging.h"
|
|
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
|
|
#ifndef XRT_HAVE_SYSTEM_CJSON
|
|
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
|
#define _CRT_SECURE_NO_WARNINGS
|
|
#endif
|
|
// This includes the c file completely.
|
|
#include "cjson/cJSON.c"
|
|
#endif
|
|
|
|
|
|
/*!
|
|
* Less typing.
|
|
*/
|
|
static inline const cJSON *
|
|
get(const cJSON *json, const char *f)
|
|
{
|
|
return cJSON_GetObjectItemCaseSensitive(json, f);
|
|
}
|
|
|
|
const cJSON *
|
|
u_json_get(const cJSON *json, const char *f)
|
|
{
|
|
return get(json, f);
|
|
}
|
|
|
|
bool
|
|
u_json_get_string_into_array(const cJSON *json, char *out_str, size_t max_size)
|
|
{
|
|
assert(out_str != NULL);
|
|
|
|
if (!json) {
|
|
return false;
|
|
}
|
|
if (!cJSON_IsString(json)) {
|
|
return false;
|
|
}
|
|
|
|
int ret = snprintf(out_str, max_size, "%s", json->valuestring);
|
|
if (ret < 0) {
|
|
U_LOG_E("Printing string failed: %d", ret);
|
|
return false;
|
|
}
|
|
if ((size_t)ret < max_size) {
|
|
return true;
|
|
}
|
|
U_LOG_E("String size %d is bigger than available %zu", ret, max_size);
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
u_json_get_bool(const cJSON *json, bool *out_bool)
|
|
{
|
|
assert(out_bool != NULL);
|
|
|
|
if (!json) {
|
|
return false;
|
|
}
|
|
if (!cJSON_IsBool(json)) {
|
|
return false;
|
|
}
|
|
|
|
*out_bool = cJSON_IsTrue(json);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
u_json_get_int(const cJSON *json, int *out_int)
|
|
{
|
|
assert(out_int != NULL);
|
|
|
|
if (!json) {
|
|
return false;
|
|
}
|
|
if (!cJSON_IsNumber(json)) {
|
|
return false;
|
|
}
|
|
|
|
*out_int = json->valueint;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
u_json_get_double(const cJSON *json, double *out_double)
|
|
{
|
|
assert(out_double != NULL);
|
|
|
|
if (!json) {
|
|
return false;
|
|
}
|
|
if (!cJSON_IsNumber(json)) {
|
|
return false;
|
|
}
|
|
*out_double = json->valuedouble;
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
u_json_get_float(const cJSON *json, float *out_float)
|
|
{
|
|
assert(out_float != NULL);
|
|
|
|
double d = 0;
|
|
if (!u_json_get_double(json, &d)) {
|
|
return false;
|
|
}
|
|
|
|
*out_float = (float)d;
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
u_json_get_vec3(const cJSON *json, struct xrt_vec3 *out_vec3)
|
|
{
|
|
assert(out_vec3 != NULL);
|
|
|
|
if (!json) {
|
|
return false;
|
|
}
|
|
if (!cJSON_IsObject(json)) {
|
|
return false;
|
|
}
|
|
|
|
struct xrt_vec3 ret;
|
|
if (!u_json_get_float(get(json, "x"), &ret.x)) {
|
|
return false;
|
|
}
|
|
if (!u_json_get_float(get(json, "y"), &ret.y)) {
|
|
return false;
|
|
}
|
|
if (!u_json_get_float(get(json, "z"), &ret.z)) {
|
|
return false;
|
|
}
|
|
|
|
*out_vec3 = ret;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
u_json_get_vec3_array(const cJSON *json, struct xrt_vec3 *out_vec3)
|
|
{
|
|
assert(out_vec3 != NULL);
|
|
|
|
if (!json) {
|
|
return false;
|
|
}
|
|
if (!cJSON_IsArray(json)) {
|
|
return false;
|
|
}
|
|
|
|
if (cJSON_GetArraySize(json) != 3) {
|
|
return false;
|
|
}
|
|
|
|
float array[3] = {0, 0, 0};
|
|
const cJSON *item = NULL;
|
|
size_t i = 0;
|
|
cJSON_ArrayForEach(item, json)
|
|
{
|
|
assert(cJSON_IsNumber(item));
|
|
array[i] = (float)item->valuedouble;
|
|
++i;
|
|
if (i == 3) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
out_vec3->x = array[0];
|
|
out_vec3->y = array[1];
|
|
out_vec3->z = array[2];
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
u_json_get_vec3_f64_array(const cJSON *json, struct xrt_vec3_f64 *out_vec3)
|
|
{
|
|
assert(out_vec3 != NULL);
|
|
|
|
if (!json) {
|
|
return false;
|
|
}
|
|
if (!cJSON_IsArray(json)) {
|
|
return false;
|
|
}
|
|
|
|
if (cJSON_GetArraySize(json) != 3) {
|
|
return false;
|
|
}
|
|
|
|
double array[3] = {0, 0, 0};
|
|
const cJSON *item = NULL;
|
|
size_t i = 0;
|
|
cJSON_ArrayForEach(item, json)
|
|
{
|
|
assert(cJSON_IsNumber(item));
|
|
array[i] = item->valuedouble;
|
|
++i;
|
|
if (i == 3) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
out_vec3->x = array[0];
|
|
out_vec3->y = array[1];
|
|
out_vec3->z = array[2];
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
u_json_get_quat(const cJSON *json, struct xrt_quat *out_quat)
|
|
{
|
|
assert(out_quat != NULL);
|
|
|
|
if (!json) {
|
|
return false;
|
|
}
|
|
if (!cJSON_IsObject(json)) {
|
|
return false;
|
|
}
|
|
|
|
struct xrt_quat ret;
|
|
if (!u_json_get_float(get(json, "w"), &ret.w)) {
|
|
return false;
|
|
}
|
|
if (!u_json_get_float(get(json, "x"), &ret.x)) {
|
|
return false;
|
|
}
|
|
if (!u_json_get_float(get(json, "y"), &ret.y)) {
|
|
return false;
|
|
}
|
|
if (!u_json_get_float(get(json, "z"), &ret.z)) {
|
|
return false;
|
|
}
|
|
|
|
*out_quat = ret;
|
|
|
|
return true;
|
|
}
|
|
|
|
// note: you should be using "position" and "orientation" and lower-case xyz(w)
|
|
bool
|
|
u_json_get_pose(const cJSON *json, struct xrt_pose *out_pose)
|
|
{
|
|
struct xrt_pose tmp;
|
|
|
|
bool good = true;
|
|
good = good && u_json_get_vec3(u_json_get(json, "position"), &tmp.position);
|
|
good = good && u_json_get_quat(u_json_get(json, "orientation"), &tmp.orientation);
|
|
|
|
if (good) {
|
|
*out_pose = tmp;
|
|
}
|
|
return good;
|
|
}
|
|
|
|
bool
|
|
u_json_get_pose_permissive(const cJSON *json, struct xrt_pose *out_pose)
|
|
{
|
|
struct xrt_pose tmp;
|
|
|
|
const char *position_names[] = {"position", "translation", "location", "pos", "loc"};
|
|
const char *orientation_names[] = {"orientation", "rotation", "rot"};
|
|
|
|
bool found_position = false;
|
|
|
|
for (uint32_t i = 0; i < ARRAY_SIZE(position_names); i++) {
|
|
found_position = u_json_get_vec3(u_json_get(json, position_names[i]), &tmp.position);
|
|
if (found_position) {
|
|
break;
|
|
}
|
|
}
|
|
if (!found_position) {
|
|
return false;
|
|
}
|
|
|
|
bool found_orientation = false;
|
|
|
|
for (uint32_t i = 0; i < ARRAY_SIZE(orientation_names); i++) {
|
|
found_orientation = u_json_get_vec3(u_json_get(json, orientation_names[i]), &tmp.position);
|
|
if (found_orientation) {
|
|
break;
|
|
}
|
|
}
|
|
if (!found_orientation) {
|
|
return false;
|
|
}
|
|
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
size_t
|
|
u_json_get_float_array(const cJSON *json_array, float *out_array, size_t max_size)
|
|
{
|
|
assert(out_array != NULL);
|
|
|
|
if (!json_array) {
|
|
return 0;
|
|
}
|
|
if (!cJSON_IsArray(json_array)) {
|
|
return 0;
|
|
}
|
|
|
|
size_t i = 0;
|
|
const cJSON *elt;
|
|
cJSON_ArrayForEach(elt, json_array)
|
|
{
|
|
if (i >= max_size) {
|
|
break;
|
|
}
|
|
|
|
if (!u_json_get_float(elt, &out_array[i])) {
|
|
U_LOG_W(
|
|
"u_json_get_float_array got a non-number in a "
|
|
"numeric array");
|
|
return i;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
size_t
|
|
u_json_get_double_array(const cJSON *json_array, double *out_array, size_t max_size)
|
|
{
|
|
assert(out_array != NULL);
|
|
|
|
if (!json_array) {
|
|
return 0;
|
|
}
|
|
if (!cJSON_IsArray(json_array)) {
|
|
return 0;
|
|
}
|
|
|
|
size_t i = 0;
|
|
const cJSON *elt;
|
|
cJSON_ArrayForEach(elt, json_array)
|
|
{
|
|
if (i >= max_size) {
|
|
break;
|
|
}
|
|
|
|
if (!u_json_get_double(elt, &out_array[i])) {
|
|
U_LOG_W(
|
|
"u_json_get_double_array got a non-number in a "
|
|
"numeric array");
|
|
return i;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
size_t
|
|
u_json_get_int_array(const cJSON *json_array, int *out_array, size_t max_size)
|
|
{
|
|
assert(out_array != NULL);
|
|
|
|
if (!json_array) {
|
|
return 0;
|
|
}
|
|
if (!cJSON_IsArray(json_array)) {
|
|
return 0;
|
|
}
|
|
|
|
size_t i = 0;
|
|
const cJSON *elt;
|
|
cJSON_ArrayForEach(elt, json_array)
|
|
{
|
|
if (i >= max_size) {
|
|
break;
|
|
}
|
|
|
|
if (!u_json_get_int(elt, &out_array[i])) {
|
|
U_LOG_W(
|
|
"u_json_get_int got a non-number in a "
|
|
"numeric array");
|
|
return i;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
bool
|
|
u_json_get_matrix_3x3(const cJSON *json, struct xrt_matrix_3x3 *out_matrix)
|
|
{
|
|
assert(out_matrix != NULL);
|
|
|
|
if (!json) {
|
|
return false;
|
|
}
|
|
if (cJSON_GetArraySize(json) != 3) {
|
|
return false;
|
|
}
|
|
|
|
size_t total = 0;
|
|
const cJSON *vec = NULL;
|
|
cJSON_ArrayForEach(vec, json)
|
|
{
|
|
assert(cJSON_GetArraySize(vec) == 3);
|
|
const cJSON *elem = NULL;
|
|
cJSON_ArrayForEach(elem, vec)
|
|
{
|
|
// Just in case.
|
|
if (total >= 9) {
|
|
break;
|
|
}
|
|
|
|
assert(cJSON_IsNumber(elem));
|
|
out_matrix->v[total++] = (float)elem->valuedouble;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|