PipeWire  1.4.3
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  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 
325 error:
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 
640 #ifdef __cplusplus
641 } /* extern "C" */
642 #endif
643 
644 #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:511
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:406
SPA_API_JSON int spa_json_parse_hex(const char *p, int num, uint32_t *res)
Definition: json-core.h:516
SPA_API_JSON int spa_json_parse_float(const char *val, int len, float *result)
Definition: json-core.h:424
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_API_JSON int spa_json_parse_int(const char *val, int len, int *result)
Definition: json-core.h:465
SPA_API_JSON bool spa_json_is_null(const char *val, int len)
Definition: json-core.h:418
SPA_API_JSON bool spa_json_is_true(const char *val, int len)
Definition: json-core.h:486
#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:453
SPA_API_JSON bool spa_json_is_bool(const char *val, int len)
Definition: json-core.h:496
#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:501
SPA_API_JSON bool spa_json_is_int(const char *val, int len)
Definition: json-core.h:479
#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:535
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:412
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:491
SPA_API_JSON int spa_json_parse_string(const char *val, int len, char *result)
Definition: json-core.h:598
#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:447
SPA_API_JSON int spa_json_is_container(const char *val, int len)
Definition: json-core.h:400
SPA_API_JSON int spa_json_encode_string(char *str, int size, const char *val)
Definition: json-core.h:603
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