PipeWire  1.3.83
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
9 extern "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 */
41 struct 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++;
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 
316 error:
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 
333 SPA_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 
379 SPA_API_JSON int spa_json_is_container(const char *val, int len)
380 {
381  return len > 0 && (*val == '{' || *val == '[');
382 }
383 
384 /* object */
385 SPA_API_JSON int spa_json_is_object(const char *val, int len)
386 {
387  return len > 0 && *val == '{';
388 }
389 
390 /* array */
391 SPA_API_JSON bool spa_json_is_array(const char *val, int len)
392 {
393  return len > 0 && *val == '[';
394 }
395 
396 /* null */
397 SPA_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 */
403 SPA_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 
426 SPA_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 
432 SPA_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 */
444 SPA_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 }
458 SPA_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 */
465 SPA_API_JSON bool spa_json_is_true(const char *val, int len)
466 {
467  return len == 4 && strncmp(val, "true", 4) == 0;
468 }
469 
470 SPA_API_JSON bool spa_json_is_false(const char *val, int len)
471 {
472  return len == 5 && strncmp(val, "false", 5) == 0;
473 }
474 
475 SPA_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 
480 SPA_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;
487 }
488 
489 /* string */
490 SPA_API_JSON bool spa_json_is_string(const char *val, int len)
491 {
492  return len > 1 && *val == '"';
493 }
494 
495 SPA_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 
514 SPA_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 
577 SPA_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 
582 SPA_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 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 char * spa_json_format_float(char *str, int size, float val)
Definition: json-core.h:444
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