PipeWire 1.2.6
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 (isinf(val))
461 val = signbit(val) ? FLT_MIN : FLT_MAX;
462 else
463 val = 0.0f;
464 }
465 return spa_dtoa(str, size, val);
467
468/* int */
469static inline int spa_json_parse_int(const char *val, int len, int *result)
470{
471 char buf[64];
472 char *end;
473
474 if (len <= 0 || len >= (int)sizeof(buf))
475 return 0;
476
477 memcpy(buf, val, len);
478 buf[len] = '\0';
479
480 *result = strtol(buf, &end, 0);
481 return len > 0 && end == buf + len;
482}
483static inline bool spa_json_is_int(const char *val, int len)
484{
485 int dummy;
486 return spa_json_parse_int(val, len, &dummy);
487}
488static inline int spa_json_get_int(struct spa_json *iter, int *res)
489{
490 const char *value;
491 int len;
492 if ((len = spa_json_next(iter, &value)) <= 0)
493 return len;
494 return spa_json_parse_int(value, len, res);
495}
496
497/* bool */
498static inline bool spa_json_is_true(const char *val, int len)
499{
500 return len == 4 && strncmp(val, "true", 4) == 0;
501}
502
503static inline bool spa_json_is_false(const char *val, int len)
504{
505 return len == 5 && strncmp(val, "false", 5) == 0;
506}
508static inline bool spa_json_is_bool(const char *val, int len)
509{
510 return spa_json_is_true(val, len) || spa_json_is_false(val, len);
511}
513static inline int spa_json_parse_bool(const char *val, int len, bool *result)
514{
515 if ((*result = spa_json_is_true(val, len)))
516 return 1;
517 if (!(*result = !spa_json_is_false(val, len)))
518 return 1;
519 return -1;
520}
521static inline int spa_json_get_bool(struct spa_json *iter, bool *res)
523 const char *value;
524 int len;
525 if ((len = spa_json_next(iter, &value)) <= 0)
526 return len;
527 return spa_json_parse_bool(value, len, res);
528}
529
530/* string */
531static inline bool spa_json_is_string(const char *val, int len)
532{
533 return len > 1 && *val == '"';
534}
535
536static inline int spa_json_parse_hex(const char *p, int num, uint32_t *res)
537{
538 int i;
539 *res = 0;
540 for (i = 0; i < num; i++) {
541 char v = p[i];
542 if (v >= '0' && v <= '9')
543 v = v - '0';
544 else if (v >= 'a' && v <= 'f')
545 v = v - 'a' + 10;
546 else if (v >= 'A' && v <= 'F')
547 v = v - 'A' + 10;
548 else
549 return -1;
550 *res = (*res << 4) | v;
551 }
552 return 1;
553}
554
555static inline int spa_json_parse_stringn(const char *val, int len, char *result, int maxlen)
556{
557 const char *p;
558 if (maxlen <= len)
559 return -1;
560 if (!spa_json_is_string(val, len)) {
561 if (result != val)
562 memmove(result, val, len);
563 result += len;
564 } else {
565 for (p = val+1; p < val + len; p++) {
566 if (*p == '\\') {
567 p++;
568 if (*p == 'n')
569 *result++ = '\n';
570 else if (*p == 'r')
571 *result++ = '\r';
572 else if (*p == 'b')
573 *result++ = '\b';
574 else if (*p == 't')
575 *result++ = '\t';
576 else if (*p == 'f')
577 *result++ = '\f';
578 else if (*p == 'u') {
579 uint8_t prefix[] = { 0, 0xc0, 0xe0, 0xf0 };
580 uint32_t idx, n, v, cp, enc[] = { 0x80, 0x800, 0x10000 };
581 if (val + len - p < 5 ||
582 spa_json_parse_hex(p+1, 4, &cp) < 0) {
583 *result++ = *p;
584 continue;
585 }
586 p += 4;
587
588 if (cp >= 0xd800 && cp <= 0xdbff) {
589 if (val + len - p < 7 ||
590 p[1] != '\\' || p[2] != 'u' ||
591 spa_json_parse_hex(p+3, 4, &v) < 0 ||
592 v < 0xdc00 || v > 0xdfff)
593 continue;
594 p += 6;
595 cp = 0x010000 + (((cp & 0x3ff) << 10) | (v & 0x3ff));
596 } else if (cp >= 0xdc00 && cp <= 0xdfff)
597 continue;
598
599 for (idx = 0; idx < 3; idx++)
600 if (cp < enc[idx])
601 break;
602 for (n = idx; n > 0; n--, cp >>= 6)
603 result[n] = (cp | 0x80) & 0xbf;
604 *result++ = (cp | prefix[idx]) & 0xff;
605 result += idx;
606 } else
607 *result++ = *p;
608 } else if (*p == '\"') {
609 break;
610 } else
611 *result++ = *p;
612 }
613 }
614 *result = '\0';
615 return 1;
616}
617
618static inline int spa_json_parse_string(const char *val, int len, char *result)
619{
620 return spa_json_parse_stringn(val, len, result, len+1);
621}
622
623static inline int spa_json_get_string(struct spa_json *iter, char *res, int maxlen)
624{
625 const char *value;
626 int len;
627 if ((len = spa_json_next(iter, &value)) <= 0)
628 return len;
629 return spa_json_parse_stringn(value, len, res, maxlen);
630}
631
632static inline int spa_json_encode_string(char *str, int size, const char *val)
633{
634 int len = 0;
635 static const char hex[] = { "0123456789abcdef" };
636#define __PUT(c) { if (len < size) *str++ = c; len++; }
637 __PUT('"');
638 while (*val) {
639 switch (*val) {
640 case '\n':
641 __PUT('\\'); __PUT('n');
642 break;
643 case '\r':
644 __PUT('\\'); __PUT('r');
645 break;
646 case '\b':
647 __PUT('\\'); __PUT('b');
648 break;
649 case '\t':
650 __PUT('\\'); __PUT('t');
651 break;
652 case '\f':
653 __PUT('\\'); __PUT('f');
654 break;
655 case '\\':
656 case '"':
657 __PUT('\\'); __PUT(*val);
658 break;
659 default:
660 if (*val > 0 && *val < 0x20) {
661 __PUT('\\'); __PUT('u');
662 __PUT('0'); __PUT('0');
663 __PUT(hex[((*val)>>4)&0xf]); __PUT(hex[(*val)&0xf]);
664 } else {
665 __PUT(*val);
666 }
667 break;
668 }
669 val++;
670 }
671 __PUT('"');
672 __PUT('\0');
673#undef __PUT
674 return len-1;
675}
676
681#ifdef __cplusplus
682} /* extern "C" */
683#endif
684
685#endif /* SPA_UTILS_JSON_H */
spa/utils/defs.h
static bool spa_json_is_string(const char *val, int len)
Definition json.h:540
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:507
static int spa_json_parse_stringn(const char *val, int len, char *result, int maxlen)
Definition json.h:564
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:545
static bool spa_json_is_false(const char *val, int len)
Definition json.h:512
static int spa_json_get_int(struct spa_json *iter, int *res)
Definition json.h:497
static int spa_json_parse_bool(const char *val, int len, bool *result)
Definition json.h:522
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:632
static bool spa_json_is_bool(const char *val, int len)
Definition json.h:517
#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:530
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:641
static int spa_json_parse_int(const char *val, int len, int *result)
Definition json.h:478
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:492
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:627
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