PipeWire  0.3.66
json.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 
32 /* a simple JSON compatible tokenizer */
33 struct spa_json {
34  const char *cur;
35  const char *end;
36  struct spa_json *parent;
37  uint32_t state;
38  uint32_t depth;
39 };
40 
41 #define SPA_JSON_INIT(data,size) ((struct spa_json) { (data), (data)+(size), })
42 
43 static inline void spa_json_init(struct spa_json * iter, const char *data, size_t size)
44 {
45  *iter = SPA_JSON_INIT(data, size);
46 }
47 #define SPA_JSON_ENTER(iter) ((struct spa_json) { (iter)->cur, (iter)->end, (iter), })
48 
49 static inline void spa_json_enter(struct spa_json * iter, struct spa_json * sub)
50 {
51  *sub = SPA_JSON_ENTER(iter);
52 }
53 
54 #define SPA_JSON_SAVE(iter) ((struct spa_json) { (iter)->cur, (iter)->end, })
55 
58 static inline int spa_json_next(struct spa_json * iter, const char **value)
59 {
60  int utf8_remain = 0;
61  enum { __NONE, __STRUCT, __BARE, __STRING, __UTF8, __ESC, __COMMENT };
62 
63  *value = iter->cur;
64  for (; iter->cur < iter->end; iter->cur++) {
65  unsigned char cur = (unsigned char)*iter->cur;
66  again:
67  switch (iter->state) {
68  case __NONE:
69  iter->state = __STRUCT;
70  iter->depth = 0;
71  goto again;
72  case __STRUCT:
73  switch (cur) {
74  case '\0': case '\t': case ' ': case '\r': case '\n': case ':': case '=': case ',':
75  continue;
76  case '#':
77  iter->state = __COMMENT;
78  continue;
79  case '"':
80  *value = iter->cur;
81  iter->state = __STRING;
82  continue;
83  case '[': case '{':
84  *value = iter->cur;
85  if (++iter->depth > 1)
86  continue;
87  iter->cur++;
88  return 1;
89  case '}': case ']':
90  if (iter->depth == 0) {
91  if (iter->parent)
92  iter->parent->cur = iter->cur;
93  return 0;
94  }
95  --iter->depth;
96  continue;
97  default:
98  *value = iter->cur;
99  iter->state = __BARE;
100  }
101  continue;
102  case __BARE:
103  switch (cur) {
104  case '\t': case ' ': case '\r': case '\n':
105  case ':': case ',': case '=': case ']': case '}':
106  iter->state = __STRUCT;
107  if (iter->depth > 0)
108  goto again;
109  return iter->cur - *value;
110  }
111  continue;
112  case __STRING:
113  switch (cur) {
114  case '\\':
115  iter->state = __ESC;
116  continue;
117  case '"':
118  iter->state = __STRUCT;
119  if (iter->depth > 0)
120  continue;
121  return ++iter->cur - *value;
122  case 240 ... 247:
123  utf8_remain++;
125  case 224 ... 239:
126  utf8_remain++;
128  case 192 ... 223:
129  utf8_remain++;
130  iter->state = __UTF8;
131  continue;
132  default:
133  if (cur >= 32 && cur <= 126)
134  continue;
135  }
136  return -1;
137  case __UTF8:
138  switch (cur) {
139  case 128 ... 191:
140  if (--utf8_remain == 0)
141  iter->state = __STRING;
142  continue;
143  }
144  return -1;
145  case __ESC:
146  switch (cur) {
147  case '"': case '\\': case '/': case 'b': case 'f':
148  case 'n': case 'r': case 't': case 'u':
149  iter->state = __STRING;
150  continue;
151  }
152  return -1;
153  case __COMMENT:
154  switch (cur) {
155  case '\n': case '\r':
156  iter->state = __STRUCT;
157  }
158  }
159 
160  }
161  if (iter->depth != 0)
162  return -1;
163  if (iter->state != __STRUCT) {
164  iter->state = __STRUCT;
165  return iter->cur - *value;
166  }
167  return 0;
168 }
169 
170 static inline int spa_json_enter_container(struct spa_json *iter, struct spa_json *sub, char type)
171 {
172  const char *value;
173  if (spa_json_next(iter, &value) <= 0 || *value != type)
174  return -1;
175  spa_json_enter(iter, sub);
176  return 1;
177 }
178 
179 static inline int spa_json_is_container(const char *val, int len)
180 {
181  return len > 0 && (*val == '{' || *val == '[');
182 }
183 
184 static inline int spa_json_container_len(struct spa_json *iter, const char *value, int len)
185 {
186  const char *val;
187  struct spa_json sub;
188  spa_json_enter(iter, &sub);
189  while (spa_json_next(&sub, &val) > 0);
190  return sub.cur + 1 - value;
191 }
192 
193 /* object */
194 static inline int spa_json_is_object(const char *val, int len)
195 {
196  return len > 0 && *val == '{';
197 }
198 static inline int spa_json_enter_object(struct spa_json *iter, struct spa_json *sub)
199 {
200  return spa_json_enter_container(iter, sub, '{');
201 }
202 
203 /* array */
204 static inline bool spa_json_is_array(const char *val, int len)
205 {
206  return len > 0 && *val == '[';
207 }
208 static inline int spa_json_enter_array(struct spa_json *iter, struct spa_json *sub)
209 {
210  return spa_json_enter_container(iter, sub, '[');
211 }
212 
213 /* null */
214 static inline bool spa_json_is_null(const char *val, int len)
215 {
216  return len == 4 && strncmp(val, "null", 4) == 0;
217 }
218 
219 /* float */
220 static inline int spa_json_parse_float(const char *val, int len, float *result)
221 {
222  char *end;
223  if (strspn(val, "+-0123456789.Ee") < (size_t)len)
224  return 0;
225  *result = spa_strtof(val, &end);
226  return len > 0 && end == val + len;
227 }
228 
229 static inline bool spa_json_is_float(const char *val, int len)
230 {
231  float dummy;
232  return spa_json_parse_float(val, len, &dummy);
233 }
234 static inline int spa_json_get_float(struct spa_json *iter, float *res)
235 {
236  const char *value;
237  int len;
238  if ((len = spa_json_next(iter, &value)) <= 0)
239  return -1;
240  return spa_json_parse_float(value, len, res);
241 }
242 
243 static inline char *spa_json_format_float(char *str, int size, float val)
244 {
245  if (SPA_UNLIKELY(!isnormal(val))) {
246  if (val == INFINITY)
247  val = FLT_MAX;
248  else if (val == -INFINITY)
249  val = FLT_MIN;
250  else
251  val = 0.0f;
252  }
253  return spa_dtoa(str, size, val);
254 }
255 
256 /* int */
257 static inline int spa_json_parse_int(const char *val, int len, int *result)
258 {
259  char *end;
260  *result = strtol(val, &end, 0);
261  return len > 0 && end == val + len;
262 }
263 static inline bool spa_json_is_int(const char *val, int len)
264 {
265  int dummy;
266  return spa_json_parse_int(val, len, &dummy);
267 }
268 static inline int spa_json_get_int(struct spa_json *iter, int *res)
269 {
270  const char *value;
271  int len;
272  if ((len = spa_json_next(iter, &value)) <= 0)
273  return -1;
274  return spa_json_parse_int(value, len, res);
275 }
276 
277 /* bool */
278 static inline bool spa_json_is_true(const char *val, int len)
279 {
280  return len == 4 && strncmp(val, "true", 4) == 0;
281 }
282 
283 static inline bool spa_json_is_false(const char *val, int len)
284 {
285  return len == 5 && strncmp(val, "false", 5) == 0;
286 }
287 
288 static inline bool spa_json_is_bool(const char *val, int len)
289 {
290  return spa_json_is_true(val, len) || spa_json_is_false(val, len);
291 }
292 
293 static inline int spa_json_parse_bool(const char *val, int len, bool *result)
294 {
295  if ((*result = spa_json_is_true(val, len)))
296  return 1;
297  if (!(*result = !spa_json_is_false(val, len)))
298  return 1;
299  return -1;
300 }
301 static inline int spa_json_get_bool(struct spa_json *iter, bool *res)
302 {
303  const char *value;
304  int len;
305  if ((len = spa_json_next(iter, &value)) <= 0)
306  return -1;
307  return spa_json_parse_bool(value, len, res);
308 }
309 
310 /* string */
311 static inline bool spa_json_is_string(const char *val, int len)
312 {
313  return len > 1 && *val == '"';
314 }
315 
316 static inline int spa_json_parse_hex(const char *p, int num, uint32_t *res)
317 {
318  int i;
319  *res = 0;
320  for (i = 0; i < num; i++) {
321  char v = p[i];
322  if (v >= '0' && v <= '9')
323  v = v - '0';
324  else if (v >= 'a' && v <= 'f')
325  v = v - 'a' + 10;
326  else if (v >= 'A' && v <= 'F')
327  v = v - 'A' + 10;
328  else
329  return -1;
330  *res = (*res << 4) | v;
331  }
332  return 1;
333 }
334 
335 static inline int spa_json_parse_stringn(const char *val, int len, char *result, int maxlen)
336 {
337  const char *p;
338  if (maxlen <= len)
339  return -1;
340  if (!spa_json_is_string(val, len)) {
341  if (result != val)
342  strncpy(result, val, len);
343  result += len;
344  } else {
345  for (p = val+1; p < val + len; p++) {
346  if (*p == '\\') {
347  p++;
348  if (*p == 'n')
349  *result++ = '\n';
350  else if (*p == 'r')
351  *result++ = '\r';
352  else if (*p == 'b')
353  *result++ = '\b';
354  else if (*p == 't')
355  *result++ = '\t';
356  else if (*p == 'f')
357  *result++ = '\f';
358  else if (*p == 'u') {
359  uint8_t prefix[] = { 0, 0xc0, 0xe0, 0xf0 };
360  uint32_t idx, n, v, cp, enc[] = { 0x80, 0x800, 0x10000 };
361  if (val + len - p < 5 ||
362  spa_json_parse_hex(p+1, 4, &cp) < 0) {
363  *result++ = *p;
364  continue;
365  }
366  p += 4;
367 
368  if (cp >= 0xd800 && cp <= 0xdbff) {
369  if (val + len - p < 7 ||
370  p[1] != '\\' || p[2] != 'u' ||
371  spa_json_parse_hex(p+3, 4, &v) < 0 ||
372  v < 0xdc00 || v > 0xdfff)
373  continue;
374  p += 6;
375  cp = 0x010000 | ((cp & 0x3ff) << 10) | (v & 0x3ff);
376  } else if (cp >= 0xdc00 && cp <= 0xdfff)
377  continue;
378 
379  for (idx = 0; idx < 3; idx++)
380  if (cp < enc[idx])
381  break;
382  for (n = idx; n > 0; n--, cp >>= 6)
383  result[n] = (cp | 0x80) & 0xbf;
384  *result++ = (cp | prefix[idx]) & 0xff;
385  result += idx;
386  } else
387  *result++ = *p;
388  } else if (*p == '\"') {
389  break;
390  } else
391  *result++ = *p;
392  }
393  }
394  *result = '\0';
395  return 1;
396 }
397 
398 static inline int spa_json_parse_string(const char *val, int len, char *result)
399 {
400  return spa_json_parse_stringn(val, len, result, len+1);
401 }
402 
403 static inline int spa_json_get_string(struct spa_json *iter, char *res, int maxlen)
404 {
405  const char *value;
406  int len;
407  if ((len = spa_json_next(iter, &value)) <= 0)
408  return -1;
409  return spa_json_parse_stringn(value, len, res, maxlen);
410 }
411 
412 static inline int spa_json_encode_string(char *str, int size, const char *val)
413 {
414  int len = 0;
415  static const char hex[] = { "0123456789abcdef" };
416 #define __PUT(c) { if (len < size) *str++ = c; len++; }
417  __PUT('"');
418  while (*val) {
419  switch (*val) {
420  case '\n':
421  __PUT('\\'); __PUT('n');
422  break;
423  case '\r':
424  __PUT('\\'); __PUT('r');
425  break;
426  case '\b':
427  __PUT('\\'); __PUT('b');
428  break;
429  case '\t':
430  __PUT('\\'); __PUT('t');
431  break;
432  case '\f':
433  __PUT('\\'); __PUT('f');
434  break;
435  case '\\':
436  case '"':
437  __PUT('\\'); __PUT(*val);
438  break;
439  default:
440  if (*val > 0 && *val < 0x20) {
441  __PUT('\\'); __PUT('u');
442  __PUT('0'); __PUT('0');
443  __PUT(hex[((*val)>>4)&0xf]); __PUT(hex[(*val)&0xf]);
444  } else {
445  __PUT(*val);
446  }
447  break;
448  }
449  val++;
450  }
451  __PUT('"');
452  __PUT('\0');
453 #undef __PUT
454  return len-1;
455 }
456 
461 #ifdef __cplusplus
462 } /* extern "C" */
463 #endif
464 
465 #endif /* SPA_UTILS_JSON_H */
spa/utils/defs.h
static int spa_json_container_len(struct spa_json *iter, const char *value, int len)
Definition: json.h:192
static bool spa_json_is_string(const char *val, int len)
Definition: json.h:319
static bool spa_json_is_float(const char *val, int len)
Definition: json.h:237
static int spa_json_parse_float(const char *val, int len, float *result)
Definition: json.h:228
static bool spa_json_is_true(const char *val, int len)
Definition: json.h:286
static int spa_json_parse_stringn(const char *val, int len, char *result, int maxlen)
Definition: json.h:343
static int spa_json_enter_container(struct spa_json *iter, struct spa_json *sub, char type)
Definition: json.h:178
static void spa_json_enter(struct spa_json *iter, struct spa_json *sub)
Definition: json.h:56
static int spa_json_parse_hex(const char *p, int num, uint32_t *res)
Definition: json.h:324
static bool spa_json_is_false(const char *val, int len)
Definition: json.h:291
static int spa_json_get_int(struct spa_json *iter, int *res)
Definition: json.h:276
static int spa_json_parse_bool(const char *val, int len, bool *result)
Definition: json.h:301
static int spa_json_enter_object(struct spa_json *iter, struct spa_json *sub)
Definition: json.h:206
static int spa_json_get_string(struct spa_json *iter, char *res, int maxlen)
Definition: json.h:411
static bool spa_json_is_bool(const char *val, int len)
Definition: json.h:296
#define SPA_JSON_INIT(data, size)
Definition: json.h:47
static bool spa_json_is_array(const char *val, int len)
Definition: json.h:212
static int spa_json_get_bool(struct spa_json *iter, bool *res)
Definition: json.h:309
static bool spa_json_is_null(const char *val, int len)
Definition: json.h:222
#define SPA_JSON_ENTER(iter)
Definition: json.h:54
static int spa_json_encode_string(char *str, int size, const char *val)
Definition: json.h:420
static char * spa_json_format_float(char *str, int size, float val)
Definition: json.h:251
static int spa_json_parse_int(const char *val, int len, int *result)
Definition: json.h:265
static int spa_json_next(struct spa_json *iter, const char **value)
Get the next token.
Definition: json.h:66
static int spa_json_is_container(const char *val, int len)
Definition: json.h:187
static void spa_json_init(struct spa_json *iter, const char *data, size_t size)
Definition: json.h:49
static bool spa_json_is_int(const char *val, int len)
Definition: json.h:271
static int spa_json_enter_array(struct spa_json *iter, struct spa_json *sub)
Definition: json.h:216
static int spa_json_get_float(struct spa_json *iter, float *res)
Definition: json.h:242
static int spa_json_is_object(const char *val, int len)
Definition: json.h:202
static int spa_json_parse_string(const char *val, int len, char *result)
Definition: json.h:406
static float spa_strtof(const char *str, char **endptr)
Convert str to a float in the C locale.
Definition: string.h:261
static char * spa_dtoa(char *str, size_t size, double val)
Definition: string.h:354
#define SPA_UNLIKELY(x)
Definition: defs.h:347
#define SPA_FALLTHROUGH
SPA_FALLTHROUGH is an annotation to suppress compiler warnings about switch cases that fall through w...
Definition: defs.h:70
#define __PUT(c)
spa/utils/string.h
Definition: json.h:38
uint32_t depth
Definition: json.h:43
const char * cur
Definition: json.h:39
uint32_t state
Definition: json.h:42
const char * end
Definition: json.h:40
struct spa_json * parent
Definition: json.h:41