PipeWire  1.4.11
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 '#': 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