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