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