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