The open source OpenXR runtime
at main 448 lines 7.6 kB view raw
1// Copyright 2019-2020, Collabora, Ltd. 2// SPDX-License-Identifier: BSL-1.0 3/*! 4 * @file 5 * @brief Tiny JSON wrapper around cJSON. 6 * @author Jakob Bornecrantz <jakob@collabora.com> 7 * @author Rylie Pavlik <rylie.pavlik@collabora.com> 8 * @ingroup aux_util 9 */ 10 11#include "util/u_json.h" 12#ifndef XRT_HAVE_SYSTEM_CJSON 13#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) 14#define _CRT_SECURE_NO_WARNINGS 15#endif 16#endif 17 18#include "util/u_logging.h" 19 20#include <assert.h> 21#include <stdio.h> 22 23#ifndef XRT_HAVE_SYSTEM_CJSON 24#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) 25#define _CRT_SECURE_NO_WARNINGS 26#endif 27// This includes the c file completely. 28#include "cjson/cJSON.c" 29#endif 30 31 32/*! 33 * Less typing. 34 */ 35static inline const cJSON * 36get(const cJSON *json, const char *f) 37{ 38 return cJSON_GetObjectItemCaseSensitive(json, f); 39} 40 41const cJSON * 42u_json_get(const cJSON *json, const char *f) 43{ 44 return get(json, f); 45} 46 47bool 48u_json_get_string_into_array(const cJSON *json, char *out_str, size_t max_size) 49{ 50 assert(out_str != NULL); 51 52 if (!json) { 53 return false; 54 } 55 if (!cJSON_IsString(json)) { 56 return false; 57 } 58 59 int ret = snprintf(out_str, max_size, "%s", json->valuestring); 60 if (ret < 0) { 61 U_LOG_E("Printing string failed: %d", ret); 62 return false; 63 } 64 if ((size_t)ret < max_size) { 65 return true; 66 } 67 U_LOG_E("String size %d is bigger than available %zu", ret, max_size); 68 return false; 69} 70 71bool 72u_json_get_bool(const cJSON *json, bool *out_bool) 73{ 74 assert(out_bool != NULL); 75 76 if (!json) { 77 return false; 78 } 79 if (!cJSON_IsBool(json)) { 80 return false; 81 } 82 83 *out_bool = cJSON_IsTrue(json); 84 85 return true; 86} 87 88bool 89u_json_get_int(const cJSON *json, int *out_int) 90{ 91 assert(out_int != NULL); 92 93 if (!json) { 94 return false; 95 } 96 if (!cJSON_IsNumber(json)) { 97 return false; 98 } 99 100 *out_int = json->valueint; 101 102 return true; 103} 104 105bool 106u_json_get_double(const cJSON *json, double *out_double) 107{ 108 assert(out_double != NULL); 109 110 if (!json) { 111 return false; 112 } 113 if (!cJSON_IsNumber(json)) { 114 return false; 115 } 116 *out_double = json->valuedouble; 117 return true; 118} 119 120bool 121u_json_get_float(const cJSON *json, float *out_float) 122{ 123 assert(out_float != NULL); 124 125 double d = 0; 126 if (!u_json_get_double(json, &d)) { 127 return false; 128 } 129 130 *out_float = (float)d; 131 return true; 132} 133 134bool 135u_json_get_vec3(const cJSON *json, struct xrt_vec3 *out_vec3) 136{ 137 assert(out_vec3 != NULL); 138 139 if (!json) { 140 return false; 141 } 142 if (!cJSON_IsObject(json)) { 143 return false; 144 } 145 146 struct xrt_vec3 ret; 147 if (!u_json_get_float(get(json, "x"), &ret.x)) { 148 return false; 149 } 150 if (!u_json_get_float(get(json, "y"), &ret.y)) { 151 return false; 152 } 153 if (!u_json_get_float(get(json, "z"), &ret.z)) { 154 return false; 155 } 156 157 *out_vec3 = ret; 158 159 return true; 160} 161 162bool 163u_json_get_vec3_array(const cJSON *json, struct xrt_vec3 *out_vec3) 164{ 165 assert(out_vec3 != NULL); 166 167 if (!json) { 168 return false; 169 } 170 if (!cJSON_IsArray(json)) { 171 return false; 172 } 173 174 if (cJSON_GetArraySize(json) != 3) { 175 return false; 176 } 177 178 float array[3] = {0, 0, 0}; 179 const cJSON *item = NULL; 180 size_t i = 0; 181 cJSON_ArrayForEach(item, json) 182 { 183 assert(cJSON_IsNumber(item)); 184 array[i] = (float)item->valuedouble; 185 ++i; 186 if (i == 3) { 187 break; 188 } 189 } 190 191 out_vec3->x = array[0]; 192 out_vec3->y = array[1]; 193 out_vec3->z = array[2]; 194 195 return true; 196} 197 198bool 199u_json_get_vec3_f64_array(const cJSON *json, struct xrt_vec3_f64 *out_vec3) 200{ 201 assert(out_vec3 != NULL); 202 203 if (!json) { 204 return false; 205 } 206 if (!cJSON_IsArray(json)) { 207 return false; 208 } 209 210 if (cJSON_GetArraySize(json) != 3) { 211 return false; 212 } 213 214 double array[3] = {0, 0, 0}; 215 const cJSON *item = NULL; 216 size_t i = 0; 217 cJSON_ArrayForEach(item, json) 218 { 219 assert(cJSON_IsNumber(item)); 220 array[i] = item->valuedouble; 221 ++i; 222 if (i == 3) { 223 break; 224 } 225 } 226 227 out_vec3->x = array[0]; 228 out_vec3->y = array[1]; 229 out_vec3->z = array[2]; 230 231 return true; 232} 233 234bool 235u_json_get_quat(const cJSON *json, struct xrt_quat *out_quat) 236{ 237 assert(out_quat != NULL); 238 239 if (!json) { 240 return false; 241 } 242 if (!cJSON_IsObject(json)) { 243 return false; 244 } 245 246 struct xrt_quat ret; 247 if (!u_json_get_float(get(json, "w"), &ret.w)) { 248 return false; 249 } 250 if (!u_json_get_float(get(json, "x"), &ret.x)) { 251 return false; 252 } 253 if (!u_json_get_float(get(json, "y"), &ret.y)) { 254 return false; 255 } 256 if (!u_json_get_float(get(json, "z"), &ret.z)) { 257 return false; 258 } 259 260 *out_quat = ret; 261 262 return true; 263} 264 265// note: you should be using "position" and "orientation" and lower-case xyz(w) 266bool 267u_json_get_pose(const cJSON *json, struct xrt_pose *out_pose) 268{ 269 struct xrt_pose tmp; 270 271 bool good = true; 272 good = good && u_json_get_vec3(u_json_get(json, "position"), &tmp.position); 273 good = good && u_json_get_quat(u_json_get(json, "orientation"), &tmp.orientation); 274 275 if (good) { 276 *out_pose = tmp; 277 } 278 return good; 279} 280 281bool 282u_json_get_pose_permissive(const cJSON *json, struct xrt_pose *out_pose) 283{ 284 struct xrt_pose tmp; 285 286 const char *position_names[] = {"position", "translation", "location", "pos", "loc"}; 287 const char *orientation_names[] = {"orientation", "rotation", "rot"}; 288 289 bool found_position = false; 290 291 for (uint32_t i = 0; i < ARRAY_SIZE(position_names); i++) { 292 found_position = u_json_get_vec3(u_json_get(json, position_names[i]), &tmp.position); 293 if (found_position) { 294 break; 295 } 296 } 297 if (!found_position) { 298 return false; 299 } 300 301 bool found_orientation = false; 302 303 for (uint32_t i = 0; i < ARRAY_SIZE(orientation_names); i++) { 304 found_orientation = u_json_get_vec3(u_json_get(json, orientation_names[i]), &tmp.position); 305 if (found_orientation) { 306 break; 307 } 308 } 309 if (!found_orientation) { 310 return false; 311 } 312 313 314 return true; 315} 316 317 318size_t 319u_json_get_float_array(const cJSON *json_array, float *out_array, size_t max_size) 320{ 321 assert(out_array != NULL); 322 323 if (!json_array) { 324 return 0; 325 } 326 if (!cJSON_IsArray(json_array)) { 327 return 0; 328 } 329 330 size_t i = 0; 331 const cJSON *elt; 332 cJSON_ArrayForEach(elt, json_array) 333 { 334 if (i >= max_size) { 335 break; 336 } 337 338 if (!u_json_get_float(elt, &out_array[i])) { 339 U_LOG_W( 340 "u_json_get_float_array got a non-number in a " 341 "numeric array"); 342 return i; 343 } 344 345 i++; 346 } 347 348 return i; 349} 350 351size_t 352u_json_get_double_array(const cJSON *json_array, double *out_array, size_t max_size) 353{ 354 assert(out_array != NULL); 355 356 if (!json_array) { 357 return 0; 358 } 359 if (!cJSON_IsArray(json_array)) { 360 return 0; 361 } 362 363 size_t i = 0; 364 const cJSON *elt; 365 cJSON_ArrayForEach(elt, json_array) 366 { 367 if (i >= max_size) { 368 break; 369 } 370 371 if (!u_json_get_double(elt, &out_array[i])) { 372 U_LOG_W( 373 "u_json_get_double_array got a non-number in a " 374 "numeric array"); 375 return i; 376 } 377 378 i++; 379 } 380 381 return i; 382} 383 384size_t 385u_json_get_int_array(const cJSON *json_array, int *out_array, size_t max_size) 386{ 387 assert(out_array != NULL); 388 389 if (!json_array) { 390 return 0; 391 } 392 if (!cJSON_IsArray(json_array)) { 393 return 0; 394 } 395 396 size_t i = 0; 397 const cJSON *elt; 398 cJSON_ArrayForEach(elt, json_array) 399 { 400 if (i >= max_size) { 401 break; 402 } 403 404 if (!u_json_get_int(elt, &out_array[i])) { 405 U_LOG_W( 406 "u_json_get_int got a non-number in a " 407 "numeric array"); 408 return i; 409 } 410 411 i++; 412 } 413 414 return i; 415} 416 417bool 418u_json_get_matrix_3x3(const cJSON *json, struct xrt_matrix_3x3 *out_matrix) 419{ 420 assert(out_matrix != NULL); 421 422 if (!json) { 423 return false; 424 } 425 if (cJSON_GetArraySize(json) != 3) { 426 return false; 427 } 428 429 size_t total = 0; 430 const cJSON *vec = NULL; 431 cJSON_ArrayForEach(vec, json) 432 { 433 assert(cJSON_GetArraySize(vec) == 3); 434 const cJSON *elem = NULL; 435 cJSON_ArrayForEach(elem, vec) 436 { 437 // Just in case. 438 if (total >= 9) { 439 break; 440 } 441 442 assert(cJSON_IsNumber(elem)); 443 out_matrix->v[total++] = (float)elem->valuedouble; 444 } 445 } 446 447 return true; 448}