PipeWire: spa/utils/json-core.h Source File

PipeWire 1.4.9

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
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
34
39
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};
49
50#define SPA_JSON_INIT(data,size) ((struct spa_json) { (data), (data)+(size), NULL, 0, 0 })
51
52 SPA_API_JSON void spa_json_init(struct spa_json * iter, const char *data, size_t size)
53{
54 *iter = SPA_JSON_INIT(data, size);
55}
56#define SPA_JSON_ENTER(iter) ((struct spa_json) { (iter)->cur, (iter)->end, (iter), (iter)->state & 0xff0, 0 })
57
58 SPA_API_JSON void spa_json_enter(struct spa_json * iter, struct spa_json * sub)
59{
60 *sub = SPA_JSON_ENTER(iter);
61}
62
63#define SPA_JSON_SAVE(iter) ((struct spa_json) { (iter)->cur, (iter)->end, NULL, (iter)->state, 0 })
64
65 SPA_API_JSON void spa_json_save(struct spa_json * iter, struct spa_json * save)
66{
67 *save = SPA_JSON_SAVE(iter);
68}
69
70#define SPA_JSON_START(iter,p) ((struct spa_json) { (p), (iter)->end, NULL, 0, 0 })
71
72 SPA_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}
76
79 SPA_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++;
252 SPA_FALLTHROUGH;
253 case 224 ... 239:
254 utf8_remain++;
255 SPA_FALLTHROUGH;
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 default:
272 break;
273 }
274 _SPA_ERROR(CHARACTERS_NOT_ALLOWED);
275 case __ESC:
276 switch (cur) {
277 case '"': case '\\': case '/': case 'b': case 'f':
278 case 'n': case 'r': case 't': case 'u':
279 iter->state = __STRING | flag;
280 continue;
281 default:
282 break;
283 }
284 _SPA_ERROR(INVALID_ESCAPE);
285 case __COMMENT:
286 switch (cur) {
287 case '\n': case '\r':
288 iter->state = __STRUCT | flag;
289 break;
290 default:
291 break;
292 }
293 break;
294 default:
295 _SPA_ERROR(INVALID_STATE);
296 }
297
298 }
299 if (iter->depth != 0 || iter->parent)
300 _SPA_ERROR(MISMATCHED_BRACKET);
301
302 switch (iter->state & ~__FLAGS) {
303 case __STRING: case __UTF8: case __ESC:
304 /* string/escape not closed */
305 _SPA_ERROR(UNFINISHED_STRING);
306 case __COMMENT:
307 /* trailing comment */
308 return 0;
309 default:
310 break;
311 }
312
313 if ((iter->state & __SUB_FLAG) && (iter->state & __KEY_FLAG)) {
314 /* incomplete key-value pair */
315 _SPA_ERROR(EXPECTED_OBJECT_VALUE);
316 }
317
318 if ((iter->state & ~__FLAGS) != __STRUCT) {
319 iter->state = __STRUCT | (iter->state & __FLAGS);
320 return iter->cur - *value;
321 }
322 return 0;
323#undef _SPA_ERROR
324
325error:
326 iter->state = err;
327 while (iter->parent) {
328 if (iter->parent->state & SPA_JSON_ERROR_FLAG)
329 break;
330 iter->parent->state = err;
331 iter->parent->cur = iter->cur;
332 iter = iter->parent;
333 }
334 return -1;
335}
336
342 SPA_API_JSON bool spa_json_get_error(struct spa_json *iter, const char *start,
343 struct spa_error_location *loc)
344{
345 static const char *reasons[] = {
346 "System error",
347 "Invalid array separator",
348 "Expected object key",
349 "Expected object value",
350 "Too deep nesting",
351 "Expected array close bracket",
352 "Expected object close brace",
353 "Mismatched bracket",
354 "Escape not allowed",
355 "Character not allowed",
356 "Invalid escape",
357 "Invalid state",
358 "Unfinished string",
359 "Expected key separator",
360 };
361
362 if (!(iter->state & SPA_JSON_ERROR_FLAG))
363 return false;
364
365 if (loc) {
366 int linepos = 1, colpos = 1, code;
367 const char *p, *l;
368
369 for (l = p = start; p && p != iter->cur; ++p) {
370 if (*p == '\n') {
371 linepos++;
372 colpos = 1;
373 l = p+1;
374 } else {
375 colpos++;
376 }
377 }
378 code = SPA_CLAMP(iter->state & 0xff, 0u, SPA_N_ELEMENTS(reasons)-1);
379 loc->line = linepos;
380 loc->col = colpos;
381 loc->location = l;
382 loc->len = SPA_PTRDIFF(iter->end, loc->location) / sizeof(char);
383 loc->reason = code == 0 ? strerror(errno) : reasons[code];
384 }
385 return true;
386}
387
388 SPA_API_JSON int spa_json_is_container(const char *val, int len)
389{
390 return len > 0 && (*val == '{' || *val == '[');
391}
392
393/* object */
394 SPA_API_JSON int spa_json_is_object(const char *val, int len)
395{
396 return len > 0 && *val == '{';
397}
398
399/* array */
400 SPA_API_JSON bool spa_json_is_array(const char *val, int len)
401{
402 return len > 0 && *val == '[';
403}
404
405/* null */
406 SPA_API_JSON bool spa_json_is_null(const char *val, int len)
407{
408 return len == 4 && strncmp(val, "null", 4) == 0;
409}
410
411/* float */
412 SPA_API_JSON int spa_json_parse_float(const char *val, int len, float *result)
413{
414 char buf[96];
415 char *end;
416 int pos;
417
418 if (len <= 0 || len >= (int)sizeof(buf))
419 return 0;
420
421 for (pos = 0; pos < len; ++pos) {
422 switch (val[pos]) {
423 case '+': case '-': case '0' ... '9': case '.': case 'e': case 'E': break;
424 default: return 0;
425 }
426 }
427
428 memcpy(buf, val, len);
429 buf[len] = '\0';
430
431 *result = spa_strtof(buf, &end);
432 return len > 0 && end == buf + len;
433}
434
435 SPA_API_JSON bool spa_json_is_float(const char *val, int len)
436{
437 float dummy;
438 return spa_json_parse_float(val, len, &dummy);
439}
440
441 SPA_API_JSON char *spa_json_format_float(char *str, int size, float val)
442{
443 if (SPA_UNLIKELY(!isnormal(val))) {
444 if (isinf(val))
445 val = signbit(val) ? FLT_MIN : FLT_MAX;
446 else
447 val = 0.0f;
448 }
449 return spa_dtoa(str, size, val);
450}
451
452/* int */
453 SPA_API_JSON int spa_json_parse_int(const char *val, int len, int *result)
454{
455 char buf[64];
456 char *end;
457
458 if (len <= 0 || len >= (int)sizeof(buf))
459 return 0;
460
461 memcpy(buf, val, len);
462 buf[len] = '\0';
463
464 *result = strtol(buf, &end, 0);
465 return len > 0 && end == buf + len;
466}
467 SPA_API_JSON bool spa_json_is_int(const char *val, int len)
468{
469 int dummy;
470 return spa_json_parse_int(val, len, &dummy);
471}
472
473/* bool */
474 SPA_API_JSON bool spa_json_is_true(const char *val, int len)
475{
476 return len == 4 && strncmp(val, "true", 4) == 0;
477}
478
479 SPA_API_JSON bool spa_json_is_false(const char *val, int len)
480{
481 return len == 5 && strncmp(val, "false", 5) == 0;
482}
483
484 SPA_API_JSON bool spa_json_is_bool(const char *val, int len)
485{
486 return spa_json_is_true(val, len) || spa_json_is_false(val, len);
487}
488
489 SPA_API_JSON int spa_json_parse_bool(const char *val, int len, bool *result)
490{
491 if ((*result = spa_json_is_true(val, len)))
492 return 1;
493 if (!(*result = !spa_json_is_false(val, len)))
494 return 1;
495 return -1;
496}
497
498/* string */
499 SPA_API_JSON bool spa_json_is_string(const char *val, int len)
500{
501 return len > 1 && *val == '"';
502}
503
504 SPA_API_JSON int spa_json_parse_hex(const char *p, int num, uint32_t *res)
505{
506 int i;
507 *res = 0;
508 for (i = 0; i < num; i++) {
509 char v = p[i];
510 if (v >= '0' && v <= '9')
511 v = v - '0';
512 else if (v >= 'a' && v <= 'f')
513 v = v - 'a' + 10;
514 else if (v >= 'A' && v <= 'F')
515 v = v - 'A' + 10;
516 else
517 return -1;
518 *res = (*res << 4) | v;
519 }
520 return 1;
521}
522
523 SPA_API_JSON int spa_json_parse_stringn(const char *val, int len, char *result, int maxlen)
524{
525 const char *p;
526 if (maxlen <= len)
527 return -ENOSPC;
528 if (!spa_json_is_string(val, len)) {
529 if (result != val)
530 memmove(result, val, len);
531 result += len;
532 } else {
533 for (p = val+1; p < val + len; p++) {
534 if (*p == '\\') {
535 p++;
536 if (*p == 'n')
537 *result++ = '\n';
538 else if (*p == 'r')
539 *result++ = '\r';
540 else if (*p == 'b')
541 *result++ = '\b';
542 else if (*p == 't')
543 *result++ = '\t';
544 else if (*p == 'f')
545 *result++ = '\f';
546 else if (*p == 'u') {
547 uint8_t prefix[] = { 0, 0xc0, 0xe0, 0xf0 };
548 uint32_t idx, n, v, cp, enc[] = { 0x80, 0x800, 0x10000 };
549 if (val + len - p < 5 ||
550 spa_json_parse_hex(p+1, 4, &cp) < 0) {
551 *result++ = *p;
552 continue;
553 }
554 p += 4;
555
556 if (cp >= 0xd800 && cp <= 0xdbff) {
557 if (val + len - p < 7 ||
558 p[1] != '\\' || p[2] != 'u' ||
559 spa_json_parse_hex(p+3, 4, &v) < 0 ||
560 v < 0xdc00 || v > 0xdfff)
561 continue;
562 p += 6;
563 cp = 0x010000 + (((cp & 0x3ff) << 10) | (v & 0x3ff));
564 } else if (cp >= 0xdc00 && cp <= 0xdfff)
565 continue;
566
567 for (idx = 0; idx < 3; idx++)
568 if (cp < enc[idx])
569 break;
570 for (n = idx; n > 0; n--, cp >>= 6)
571 result[n] = (cp | 0x80) & 0xbf;
572 *result++ = (cp | prefix[idx]) & 0xff;
573 result += idx;
574 } else
575 *result++ = *p;
576 } else if (*p == '\"') {
577 break;
578 } else
579 *result++ = *p;
580 }
581 }
582 *result = '\0';
583 return 1;
584}
585
586 SPA_API_JSON int spa_json_parse_string(const char *val, int len, char *result)
587{
588 return spa_json_parse_stringn(val, len, result, len+1);
589}
590
591 SPA_API_JSON int spa_json_encode_string(char *str, int size, const char *val)
592{
593 int len = 0;
594 static const char hex[] = { "0123456789abcdef" };
595#define __PUT(c) { if (len < size) *str++ = c; len++; }
596 __PUT('"');
597 while (*val) {
598 switch (*val) {
599 case '\n':
600 __PUT('\\'); __PUT('n');
601 break;
602 case '\r':
603 __PUT('\\'); __PUT('r');
604 break;
605 case '\b':
606 __PUT('\\'); __PUT('b');
607 break;
608 case '\t':
609 __PUT('\\'); __PUT('t');
610 break;
611 case '\f':
612 __PUT('\\'); __PUT('f');
613 break;
614 case '\\':
615 case '"':
616 __PUT('\\'); __PUT(*val);
617 break;
618 default:
619 if (*val > 0 && *val < 0x20) {
620 __PUT('\\'); __PUT('u');
621 __PUT('0'); __PUT('0');
622 __PUT(hex[((*val)>>4)&0xf]); __PUT(hex[(*val)&0xf]);
623 } else {
624 __PUT(*val);
625 }
626 break;
627 }
628 val++;
629 }
630 __PUT('"');
631 __PUT('\0');
632#undef __PUT
633 return len-1;
634}
635
639
640#ifdef __cplusplus
641} /* extern "C" */
642#endif
643
644#endif /* SPA_UTILS_JSON_H */
defs.h
spa/utils/defs.h
res
uint32_t int int res
Definition core.h:433
SPA_JSON_SAVE
#define SPA_JSON_SAVE(iter)
Definition json-core.h:74
spa_json_init
SPA_API_JSON void spa_json_init(struct spa_json *iter, const char *data, size_t size)
Definition json-core.h:61
spa_json_is_string
SPA_API_JSON bool spa_json_is_string(const char *val, int len)
Definition json-core.h:511
spa_json_next
SPA_API_JSON int spa_json_next(struct spa_json *iter, const char **value)
Get the next token.
Definition json-core.h:91
spa_json_is_object
SPA_API_JSON int spa_json_is_object(const char *val, int len)
Definition json-core.h:406
spa_json_parse_hex
SPA_API_JSON int spa_json_parse_hex(const char *p, int num, uint32_t *res)
Definition json-core.h:516
spa_json_parse_float
SPA_API_JSON int spa_json_parse_float(const char *val, int len, float *result)
Definition json-core.h:424
spa_json_format_float
SPA_API_JSON char * spa_json_format_float(char *str, int size, float val)
Definition json-core.h:453
spa_json_get_error
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:354
spa_json_parse_int
SPA_API_JSON int spa_json_parse_int(const char *val, int len, int *result)
Definition json-core.h:465
spa_json_is_null
SPA_API_JSON bool spa_json_is_null(const char *val, int len)
Definition json-core.h:418
spa_json_is_true
SPA_API_JSON bool spa_json_is_true(const char *val, int len)
Definition json-core.h:486
SPA_JSON_INIT
#define SPA_JSON_INIT(data, size)
Definition json-core.h:59
spa_json_is_bool
SPA_API_JSON bool spa_json_is_bool(const char *val, int len)
Definition json-core.h:496
SPA_JSON_ERROR_FLAG
#define SPA_JSON_ERROR_FLAG
Definition json-core.h:53
spa_json_parse_bool
SPA_API_JSON int spa_json_parse_bool(const char *val, int len, bool *result)
Definition json-core.h:501
spa_json_is_int
SPA_API_JSON bool spa_json_is_int(const char *val, int len)
Definition json-core.h:479
SPA_JSON_ENTER
#define SPA_JSON_ENTER(iter)
Definition json-core.h:66
spa_json_start
SPA_API_JSON void spa_json_start(struct spa_json *iter, struct spa_json *sub, const char *pos)
Definition json-core.h:84
spa_json_parse_stringn
SPA_API_JSON int spa_json_parse_stringn(const char *val, int len, char *result, int maxlen)
Definition json-core.h:535
spa_json_enter
SPA_API_JSON void spa_json_enter(struct spa_json *iter, struct spa_json *sub)
Definition json-core.h:68
spa_json_is_array
SPA_API_JSON bool spa_json_is_array(const char *val, int len)
Definition json-core.h:412
spa_json_save
SPA_API_JSON void spa_json_save(struct spa_json *iter, struct spa_json *save)
Definition json-core.h:76
spa_json_is_false
SPA_API_JSON bool spa_json_is_false(const char *val, int len)
Definition json-core.h:491
spa_json_parse_string
SPA_API_JSON int spa_json_parse_string(const char *val, int len, char *result)
Definition json-core.h:598
SPA_JSON_START
#define SPA_JSON_START(iter, p)
Definition json-core.h:82
spa_json_is_float
SPA_API_JSON bool spa_json_is_float(const char *val, int len)
Definition json-core.h:447
spa_json_is_container
SPA_API_JSON int spa_json_is_container(const char *val, int len)
Definition json-core.h:400
spa_json_encode_string
SPA_API_JSON int spa_json_encode_string(char *str, int size, const char *val)
Definition json-core.h:603
spa_dtoa
SPA_API_STRING char * spa_dtoa(char *str, size_t size, double val)
Definition string.h:364
spa_strtof
SPA_API_STRING float spa_strtof(const char *str, char **endptr)
Convert str to a float in the C locale.
Definition string.h:271
SPA_CLAMP
#define SPA_CLAMP(v, low, high)
Definition defs.h:177
SPA_FLAG_UPDATE
#define SPA_FLAG_UPDATE(field, flag, val)
Definition defs.h:104
SPA_N_ELEMENTS
#define SPA_N_ELEMENTS(arr)
Definition defs.h:143
SPA_FLAG_IS_SET
#define SPA_FLAG_IS_SET(field, flag)
Definition defs.h:90
SPA_UNLIKELY
#define SPA_UNLIKELY(x)
Definition defs.h:394
SPA_FALLTHROUGH
#define SPA_FALLTHROUGH
SPA_FALLTHROUGH is an annotation to suppress compiler warnings about switch cases that fall through w...
Definition defs.h:84
SPA_FLAG_CLEAR
#define SPA_FLAG_CLEAR(field, flag)
Definition defs.h:94
SPA_PTRDIFF
#define SPA_PTRDIFF(p1, p2)
Definition defs.h:238
SPA_API_JSON
#define SPA_API_JSON
Definition json-core.h:34
_SPA_ERROR
#define _SPA_ERROR(reason)
__PUT
#define __PUT(c)
string.h
spa/utils/string.h
spa_error_location
Definition defs.h:439
spa_error_location::line
int line
Definition defs.h:440
spa_error_location::location
const char * location
Definition defs.h:443
spa_error_location::col
int col
Definition defs.h:441
spa_error_location::len
size_t len
Definition defs.h:442
spa_error_location::reason
const char * reason
Definition defs.h:444
spa_json
Definition json-core.h:48
spa_json::depth
uint32_t depth
Definition json-core.h:55
spa_json::cur
const char * cur
Definition json-core.h:49
spa_json::state
uint32_t state
Definition json-core.h:54
spa_json::end
const char * end
Definition json-core.h:50
spa_json::parent
struct spa_json * parent
Definition json-core.h:51