PipeWire 1.3.0
Loading...
Searching...
No Matches
json-core.h
Go to the documentation of this file.
1/* Simple Plugin API */
2/* SPDX-FileCopyrightText: Copyright © 2020 Wim Taymans */
3/* SPDX-License-Identifier: MIT */
4
5#ifndef SPA_UTILS_JSON_H
6#define SPA_UTILS_JSON_H
7
8#ifdef __cplusplus
9extern "C" {
10#else
11#include <stdbool.h>
12#endif
13#include <stddef.h>
14#include <stdlib.h>
15#include <stdint.h>
16#include <string.h>
17#include <math.h>
18#include <float.h>
19
20#include <spa/utils/defs.h>
21#include <spa/utils/string.h>
22
32/* a simple JSON compatible tokenizer */
33struct spa_json {
34 const char *cur;
35 const char *end;
36 struct spa_json *parent;
37#define SPA_JSON_ERROR_FLAG 0x100
38 uint32_t state;
39 uint32_t depth;
40};
42#define SPA_JSON_INIT(data,size) ((struct spa_json) { (data), (data)+(size), NULL, 0, 0 })
44static inline void spa_json_init(struct spa_json * iter, const char *data, size_t size)
46 *iter = SPA_JSON_INIT(data, size);
47}
48#define SPA_JSON_ENTER(iter) ((struct spa_json) { (iter)->cur, (iter)->end, (iter), (iter)->state & 0xff0, 0 })
50static inline void spa_json_enter(struct spa_json * iter, struct spa_json * sub)
52 *sub = SPA_JSON_ENTER(iter);
53}
54
55#define SPA_JSON_SAVE(iter) ((struct spa_json) { (iter)->cur, (iter)->end, NULL, (iter)->state, 0 })
57#define SPA_JSON_START(iter,p) ((struct spa_json) { (p), (iter)->end, NULL, 0, 0 })
61static inline int spa_json_next(struct spa_json * iter, const char **value)
62{
63 int utf8_remain = 0, err = 0;
64 enum {
65 __NONE, __STRUCT, __BARE, __STRING, __UTF8, __ESC, __COMMENT,
66 __ARRAY_FLAG = 0x10, /* in array context */
67 __PREV_ARRAY_FLAG = 0x20, /* depth=0 array context flag */
68 __KEY_FLAG = 0x40, /* inside object key */
69 __SUB_FLAG = 0x80, /* not at top-level */
70 __FLAGS = 0xff0,
71 __ERROR_SYSTEM = SPA_JSON_ERROR_FLAG,
72 __ERROR_INVALID_ARRAY_SEPARATOR,
73 __ERROR_EXPECTED_OBJECT_KEY,
74 __ERROR_EXPECTED_OBJECT_VALUE,
75 __ERROR_TOO_DEEP_NESTING,
76 __ERROR_EXPECTED_ARRAY_CLOSE,
77 __ERROR_EXPECTED_OBJECT_CLOSE,
78 __ERROR_MISMATCHED_BRACKET,
79 __ERROR_ESCAPE_NOT_ALLOWED,
80 __ERROR_CHARACTERS_NOT_ALLOWED,
81 __ERROR_INVALID_ESCAPE,
82 __ERROR_INVALID_STATE,
83 __ERROR_UNFINISHED_STRING,
84 };
85 uint64_t array_stack[8] = {0}; /* array context flags of depths 1...512 */
86
87 *value = iter->cur;
88
89 if (iter->state & SPA_JSON_ERROR_FLAG)
90 return -1;
91
92 for (; iter->cur < iter->end; iter->cur++) {
93 unsigned char cur = (unsigned char)*iter->cur;
94 uint32_t flag;
95
96#define _SPA_ERROR(reason) { err = __ERROR_ ## reason; goto error; }
97 again:
98 flag = iter->state & __FLAGS;
99 switch (iter->state & ~__FLAGS) {
100 case __NONE:
101 flag &= ~(__KEY_FLAG | __PREV_ARRAY_FLAG);
102 iter->state = __STRUCT | flag;
103 iter->depth = 0;
104 goto again;
105 case __STRUCT:
106 switch (cur) {
107 case '\0': case '\t': case ' ': case '\r': case '\n': case ',':
108 continue;
109 case ':': case '=':
110 if (flag & __ARRAY_FLAG)
111 _SPA_ERROR(INVALID_ARRAY_SEPARATOR);
112 if (!(flag & __KEY_FLAG))
113 _SPA_ERROR(EXPECTED_OBJECT_KEY);
114 iter->state |= __SUB_FLAG;
115 continue;
116 case '#':
117 iter->state = __COMMENT | flag;
118 continue;
119 case '"':
120 if (flag & __KEY_FLAG)
121 flag |= __SUB_FLAG;
122 if (!(flag & __ARRAY_FLAG))
123 SPA_FLAG_UPDATE(flag, __KEY_FLAG, !(flag & __KEY_FLAG));
124 *value = iter->cur;
125 iter->state = __STRING | flag;
126 continue;
127 case '[': case '{':
128 if (!(flag & __ARRAY_FLAG)) {
129 /* At top-level we may be either in object context
130 * or in single-item context, and then we need to
131 * accept array/object here.
132 */
133 if ((iter->state & __SUB_FLAG) && !(flag & __KEY_FLAG))
134 _SPA_ERROR(EXPECTED_OBJECT_KEY);
135 SPA_FLAG_CLEAR(flag, __KEY_FLAG);
136 }
137 iter->state = __STRUCT | __SUB_FLAG | flag;
138 SPA_FLAG_UPDATE(iter->state, __ARRAY_FLAG, cur == '[');
139
140 /* We need to remember previous array state across calls
141 * for depth=0, so store that in state. Others bits go to
142 * temporary stack.
143 */
144 if (iter->depth == 0) {
145 SPA_FLAG_UPDATE(iter->state, __PREV_ARRAY_FLAG, flag & __ARRAY_FLAG);
146 } else if (((iter->depth-1) >> 6) < SPA_N_ELEMENTS(array_stack)) {
147 uint64_t mask = 1ULL << ((iter->depth-1) & 0x3f);
148 SPA_FLAG_UPDATE(array_stack[(iter->depth-1) >> 6], mask, flag & __ARRAY_FLAG);
149 } else {
150 /* too deep */
151 _SPA_ERROR(TOO_DEEP_NESTING);
152 }
153
154 *value = iter->cur;
155 if (++iter->depth > 1)
156 continue;
157 iter->cur++;
158 return 1;
159 case '}': case ']':
160 if ((flag & __ARRAY_FLAG) && cur != ']')
161 _SPA_ERROR(EXPECTED_ARRAY_CLOSE);
162 if (!(flag & __ARRAY_FLAG) && cur != '}')
163 _SPA_ERROR(EXPECTED_OBJECT_CLOSE);
164 if (flag & __KEY_FLAG) {
165 /* incomplete key-value pair */
166 _SPA_ERROR(EXPECTED_OBJECT_VALUE);
167 }
168 iter->state = __STRUCT | __SUB_FLAG | flag;
169 if (iter->depth == 0) {
170 if (iter->parent)
171 iter->parent->cur = iter->cur;
172 else
173 _SPA_ERROR(MISMATCHED_BRACKET);
174 return 0;
175 }
176 --iter->depth;
177 if (iter->depth == 0) {
178 SPA_FLAG_UPDATE(iter->state, __ARRAY_FLAG, flag & __PREV_ARRAY_FLAG);
179 } else if (((iter->depth-1) >> 6) < SPA_N_ELEMENTS(array_stack)) {
180 uint64_t mask = 1ULL << ((iter->depth-1) & 0x3f);
181 SPA_FLAG_UPDATE(iter->state, __ARRAY_FLAG,
182 SPA_FLAG_IS_SET(array_stack[(iter->depth-1) >> 6], mask));
183 } else {
184 /* too deep */
185 _SPA_ERROR(TOO_DEEP_NESTING);
186 }
187 continue;
188 case '\\':
189 /* disallow bare escape */
190 _SPA_ERROR(ESCAPE_NOT_ALLOWED);
191 default:
192 /* allow bare ascii */
193 if (!(cur >= 32 && cur <= 126))
194 _SPA_ERROR(CHARACTERS_NOT_ALLOWED);
195 if (flag & __KEY_FLAG)
196 flag |= __SUB_FLAG;
197 if (!(flag & __ARRAY_FLAG))
198 SPA_FLAG_UPDATE(flag, __KEY_FLAG, !(flag & __KEY_FLAG));
199 *value = iter->cur;
200 iter->state = __BARE | flag;
201 }
202 continue;
203 case __BARE:
204 switch (cur) {
205 case '\0':
206 case '\t': case ' ': case '\r': case '\n':
207 case '"': case '#':
208 case ':': case ',': case '=': case ']': case '}':
209 iter->state = __STRUCT | flag;
210 if (iter->depth > 0)
211 goto again;
212 return iter->cur - *value;
213 case '\\':
214 /* disallow bare escape */
215 _SPA_ERROR(ESCAPE_NOT_ALLOWED);
216 default:
217 /* allow bare ascii */
218 if (cur >= 32 && cur <= 126)
219 continue;
220 }
221 _SPA_ERROR(CHARACTERS_NOT_ALLOWED);
222 case __STRING:
223 switch (cur) {
224 case '\\':
225 iter->state = __ESC | flag;
226 continue;
227 case '"':
228 iter->state = __STRUCT | flag;
229 if (iter->depth > 0)
230 continue;
231 return ++iter->cur - *value;
232 case 240 ... 247:
233 utf8_remain++;
235 case 224 ... 239:
236 utf8_remain++;
238 case 192 ... 223:
239 utf8_remain++;
240 iter->state = __UTF8 | flag;
241 continue;
242 default:
243 if (cur >= 32 && cur <= 127)
244 continue;
245 }
246 _SPA_ERROR(CHARACTERS_NOT_ALLOWED);
247 case __UTF8:
248 switch (cur) {
249 case 128 ... 191:
250 if (--utf8_remain == 0)
251 iter->state = __STRING | flag;
252 continue;
253 }
254 _SPA_ERROR(CHARACTERS_NOT_ALLOWED);
255 case __ESC:
256 switch (cur) {
257 case '"': case '\\': case '/': case 'b': case 'f':
258 case 'n': case 'r': case 't': case 'u':
259 iter->state = __STRING | flag;
260 continue;
261 }
262 _SPA_ERROR(INVALID_ESCAPE);
263 case __COMMENT:
264 switch (cur) {
265 case '\n': case '\r':
266 iter->state = __STRUCT | flag;
267 }
268 break;
269 default:
270 _SPA_ERROR(INVALID_STATE);
271 }
272
273 }
274 if (iter->depth != 0 || iter->parent)
275 _SPA_ERROR(MISMATCHED_BRACKET);
276
277 switch (iter->state & ~__FLAGS) {
278 case __STRING: case __UTF8: case __ESC:
279 /* string/escape not closed */
280 _SPA_ERROR(UNFINISHED_STRING);
281 case __COMMENT:
282 /* trailing comment */
283 return 0;
284 }
285
286 if ((iter->state & __SUB_FLAG) && (iter->state & __KEY_FLAG)) {
287 /* incomplete key-value pair */
288 _SPA_ERROR(EXPECTED_OBJECT_VALUE);
289 }
290
291 if ((iter->state & ~__FLAGS) != __STRUCT) {
292 iter->state = __STRUCT | (iter->state & __FLAGS);
293 return iter->cur - *value;
294 }
295 return 0;
296#undef _SPA_ERROR
297
298error:
299 iter->state = err;
300 while (iter->parent) {
301 if (iter->parent->state & SPA_JSON_ERROR_FLAG)
302 break;
303 iter->parent->state = err;
304 iter->parent->cur = iter->cur;
305 iter = iter->parent;
306 }
307 return -1;
308}
309
315static inline bool spa_json_get_error(struct spa_json *iter, const char *start,
316 struct spa_error_location *loc)
317{
318 static const char *reasons[] = {
319 "System error",
320 "Invalid array separator",
321 "Expected object key",
322 "Expected object value",
323 "Too deep nesting",
324 "Expected array close bracket",
325 "Expected object close brace",
326 "Mismatched bracket",
327 "Escape not allowed",
328 "Character not allowed",
329 "Invalid escape",
330 "Invalid state",
331 "Unfinished string",
332 "Expected key separator",
333 };
334
335 if (!(iter->state & SPA_JSON_ERROR_FLAG))
336 return false;
337
338 if (loc) {
339 int linepos = 1, colpos = 1, code;
340 const char *p, *l;
341
342 for (l = p = start; p && p != iter->cur; ++p) {
343 if (*p == '\n') {
344 linepos++;
345 colpos = 1;
346 l = p+1;
347 } else {
348 colpos++;
349 }
350 }
351 code = SPA_CLAMP(iter->state & 0xff, 0u, SPA_N_ELEMENTS(reasons)-1);
352 loc->line = linepos;
353 loc->col = colpos;
354 loc->location = l;
355 loc->len = SPA_PTRDIFF(iter->end, loc->location) / sizeof(char);
356 loc->reason = code == 0 ? strerror(errno) : reasons[code];
357 }
358 return true;
359}
360
361static inline int spa_json_is_container(const char *val, int len)
362{
363 return len > 0 && (*val == '{' || *val == '[');
364}
365
366/* object */
367static inline int spa_json_is_object(const char *val, int len)
368{
369 return len > 0 && *val == '{';
370}
372/* array */
373static inline bool spa_json_is_array(const char *val, int len)
374{
375 return len > 0 && *val == '[';
376}
378/* null */
379static inline bool spa_json_is_null(const char *val, int len)
380{
381 return len == 4 && strncmp(val, "null", 4) == 0;
382}
384/* float */
385static inline int spa_json_parse_float(const char *val, int len, float *result)
386{
387 char buf[96];
388 char *end;
389 int pos;
390
391 if (len <= 0 || len >= (int)sizeof(buf))
392 return 0;
393
394 for (pos = 0; pos < len; ++pos) {
395 switch (val[pos]) {
396 case '+': case '-': case '0' ... '9': case '.': case 'e': case 'E': break;
397 default: return 0;
398 }
399 }
400
401 memcpy(buf, val, len);
402 buf[len] = '\0';
403
404 *result = spa_strtof(buf, &end);
405 return len > 0 && end == buf + len;
406}
407
408static inline bool spa_json_is_float(const char *val, int len)
409{
410 float dummy;
411 return spa_json_parse_float(val, len, &dummy);
412}
413
414static inline char *spa_json_format_float(char *str, int size, float val)
415{
416 if (SPA_UNLIKELY(!isnormal(val))) {
417 if (isinf(val))
418 val = signbit(val) ? FLT_MIN : FLT_MAX;
419 else
420 val = 0.0f;
421 }
422 return spa_dtoa(str, size, val);
423}
425/* int */
426static inline int spa_json_parse_int(const char *val, int len, int *result)
427{
428 char buf[64];
429 char *end;
430
431 if (len <= 0 || len >= (int)sizeof(buf))
432 return 0;
433
434 memcpy(buf, val, len);
435 buf[len] = '\0';
437 *result = strtol(buf, &end, 0);
438 return len > 0 && end == buf + len;
439}
440static inline bool spa_json_is_int(const char *val, int len)
441{
442 int dummy;
443 return spa_json_parse_int(val, len, &dummy);
444}
445
446/* bool */
447static inline bool spa_json_is_true(const char *val, int len)
448{
449 return len == 4 && strncmp(val, "true", 4) == 0;
451
452static inline bool spa_json_is_false(const char *val, int len)
453{
454 return len == 5 && strncmp(val, "false", 5) == 0;
455}
456
457static inline bool spa_json_is_bool(const char *val, int len)
458{
459 return spa_json_is_true(val, len) || spa_json_is_false(val, len);
460}
461
462static inline int spa_json_parse_bool(const char *val, int len, bool *result)
463{
464 if ((*result = spa_json_is_true(val, len)))
465 return 1;
466 if (!(*result = !spa_json_is_false(val, len)))
467 return 1;
468 return -1;
469}
470
471/* string */
472static inline bool spa_json_is_string(const char *val, int len)
473{
474 return len > 1 && *val == '"';
475}
476
477static inline int spa_json_parse_hex(const char *p, int num, uint32_t *res)
478{
479 int i;
480 *res = 0;
481 for (i = 0; i < num; i++) {
482 char v = p[i];
483 if (v >= '0' && v <= '9')
484 v = v - '0';
485 else if (v >= 'a' && v <= 'f')
486 v = v - 'a' + 10;
487 else if (v >= 'A' && v <= 'F')
488 v = v - 'A' + 10;
489 else
490 return -1;
491 *res = (*res << 4) | v;
492 }
493 return 1;
494}
495
496static inline int spa_json_parse_stringn(const char *val, int len, char *result, int maxlen)
497{
498 const char *p;
499 if (maxlen <= len)
500 return -ENOSPC;
501 if (!spa_json_is_string(val, len)) {
502 if (result != val)
503 memmove(result, val, len);
504 result += len;
505 } else {
506 for (p = val+1; p < val + len; p++) {
507 if (*p == '\\') {
508 p++;
509 if (*p == 'n')
510 *result++ = '\n';
511 else if (*p == 'r')
512 *result++ = '\r';
513 else if (*p == 'b')
514 *result++ = '\b';
515 else if (*p == 't')
516 *result++ = '\t';
517 else if (*p == 'f')
518 *result++ = '\f';
519 else if (*p == 'u') {
520 uint8_t prefix[] = { 0, 0xc0, 0xe0, 0xf0 };
521 uint32_t idx, n, v, cp, enc[] = { 0x80, 0x800, 0x10000 };
522 if (val + len - p < 5 ||
523 spa_json_parse_hex(p+1, 4, &cp) < 0) {
524 *result++ = *p;
525 continue;
526 }
527 p += 4;
528
529 if (cp >= 0xd800 && cp <= 0xdbff) {
530 if (val + len - p < 7 ||
531 p[1] != '\\' || p[2] != 'u' ||
532 spa_json_parse_hex(p+3, 4, &v) < 0 ||
533 v < 0xdc00 || v > 0xdfff)
534 continue;
535 p += 6;
536 cp = 0x010000 + (((cp & 0x3ff) << 10) | (v & 0x3ff));
537 } else if (cp >= 0xdc00 && cp <= 0xdfff)
538 continue;
539
540 for (idx = 0; idx < 3; idx++)
541 if (cp < enc[idx])
542 break;
543 for (n = idx; n > 0; n--, cp >>= 6)
544 result[n] = (cp | 0x80) & 0xbf;
545 *result++ = (cp | prefix[idx]) & 0xff;
546 result += idx;
547 } else
548 *result++ = *p;
549 } else if (*p == '\"') {
550 break;
551 } else
552 *result++ = *p;
553 }
554 }
555 *result = '\0';
556 return 1;
557}
558
559static inline int spa_json_parse_string(const char *val, int len, char *result)
560{
561 return spa_json_parse_stringn(val, len, result, len+1);
562}
563
564static inline int spa_json_encode_string(char *str, int size, const char *val)
565{
566 int len = 0;
567 static const char hex[] = { "0123456789abcdef" };
568#define __PUT(c) { if (len < size) *str++ = c; len++; }
569 __PUT('"');
570 while (*val) {
571 switch (*val) {
572 case '\n':
573 __PUT('\\'); __PUT('n');
574 break;
575 case '\r':
576 __PUT('\\'); __PUT('r');
577 break;
578 case '\b':
579 __PUT('\\'); __PUT('b');
580 break;
581 case '\t':
582 __PUT('\\'); __PUT('t');
583 break;
584 case '\f':
585 __PUT('\\'); __PUT('f');
586 break;
587 case '\\':
588 case '"':
589 __PUT('\\'); __PUT(*val);
590 break;
591 default:
592 if (*val > 0 && *val < 0x20) {
593 __PUT('\\'); __PUT('u');
594 __PUT('0'); __PUT('0');
595 __PUT(hex[((*val)>>4)&0xf]); __PUT(hex[(*val)&0xf]);
596 } else {
597 __PUT(*val);
598 }
599 break;
600 }
601 val++;
602 }
603 __PUT('"');
604 __PUT('\0');
605#undef __PUT
606 return len-1;
607}
608
613#ifdef __cplusplus
614} /* extern "C" */
615#endif
616
617#endif /* SPA_UTILS_JSON_H */
spa/utils/defs.h
static bool spa_json_is_string(const char *val, int len)
Definition json-core.h:482
static bool spa_json_is_float(const char *val, int len)
Definition json-core.h:418
static int spa_json_parse_float(const char *val, int len, float *result)
Definition json-core.h:395
static bool spa_json_is_true(const char *val, int len)
Definition json-core.h:457
static int spa_json_parse_stringn(const char *val, int len, char *result, int maxlen)
Definition json-core.h:506
static void spa_json_enter(struct spa_json *iter, struct spa_json *sub)
Definition json-core.h:58
static int spa_json_parse_hex(const char *p, int num, uint32_t *res)
Definition json-core.h:487
static bool spa_json_is_false(const char *val, int len)
Definition json-core.h:462
static int spa_json_parse_bool(const char *val, int len, bool *result)
Definition json-core.h:472
static bool spa_json_is_bool(const char *val, int len)
Definition json-core.h:467
#define SPA_JSON_INIT(data, size)
Definition json-core.h:49
static 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:325
#define SPA_JSON_ERROR_FLAG
Definition json-core.h:43
static char * spa_json_format_float(char *str, int size, float val)
Definition json-core.h:424
static bool spa_json_is_array(const char *val, int len)
Definition json-core.h:383
static bool spa_json_is_null(const char *val, int len)
Definition json-core.h:389
#define SPA_JSON_ENTER(iter)
Definition json-core.h:56
static int spa_json_encode_string(char *str, int size, const char *val)
Definition json-core.h:574
static int spa_json_parse_int(const char *val, int len, int *result)
Definition json-core.h:436
static int spa_json_next(struct spa_json *iter, const char **value)
Get the next token.
Definition json-core.h:71
static int spa_json_is_container(const char *val, int len)
Definition json-core.h:371
static void spa_json_init(struct spa_json *iter, const char *data, size_t size)
Definition json-core.h:51
static bool spa_json_is_int(const char *val, int len)
Definition json-core.h:450
static int spa_json_is_object(const char *val, int len)
Definition json-core.h:377
static int spa_json_parse_string(const char *val, int len, char *result)
Definition json-core.h:569
static float spa_strtof(const char *str, char **endptr)
Convert str to a float in the C locale.
Definition string.h:261
static char * spa_dtoa(char *str, size_t size, double val)
Definition string.h:354
#define SPA_CLAMP(v, low, high)
Definition defs.h:177
#define SPA_FLAG_UPDATE(field, flag, val)
Definition defs.h:104
#define SPA_N_ELEMENTS(arr)
Definition defs.h:143
#define SPA_FLAG_IS_SET(field, flag)
Definition defs.h:90
#define SPA_UNLIKELY(x)
Definition defs.h:369
#define SPA_FALLTHROUGH
SPA_FALLTHROUGH is an annotation to suppress compiler warnings about switch cases that fall through w...
Definition defs.h:84
#define SPA_FLAG_CLEAR(field, flag)
Definition defs.h:94
#define SPA_PTRDIFF(p1, p2)
Definition defs.h:238
#define _SPA_ERROR(reason)
#define __PUT(c)
spa/utils/string.h
Definition defs.h:414
int line
Definition defs.h:415
const char * location
Definition defs.h:418
int col
Definition defs.h:416
size_t len
Definition defs.h:417
const char * reason
Definition defs.h:419
Definition json-core.h:38
uint32_t depth
Definition json-core.h:45
const char * cur
Definition json-core.h:39
uint32_t state
Definition json-core.h:44
const char * end
Definition json-core.h:40
struct spa_json * parent
Definition json-core.h:41