PipeWire  0.3.40
json.h
Go to the documentation of this file.
1 /* Simple Plugin API
2  *
3  * Copyright © 2020 Wim Taymans
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24 
25 #ifndef SPA_UTILS_JSON_H
26 #define SPA_UTILS_JSON_H
27 
28 #ifdef __cplusplus
29 extern "C" {
30 #else
31 #include <stdbool.h>
32 #endif
33 #include <stddef.h>
34 #include <stdlib.h>
35 #include <stdint.h>
36 #include <string.h>
37 
38 #include <spa/utils/defs.h>
39 
49 /* a simple JSON compatible tokenizer */
50 struct spa_json {
51  const char *cur;
52  const char *end;
53  struct spa_json *parent;
54  uint32_t state;
55  uint32_t depth;
56 };
57 
58 #define SPA_JSON_INIT(data,size) (struct spa_json) { (data), (data)+(size), }
59 
60 static inline void spa_json_init(struct spa_json * iter, const char *data, size_t size)
61 {
62  *iter = SPA_JSON_INIT(data, size);
63 }
64 #define SPA_JSON_ENTER(iter) (struct spa_json) { (iter)->cur, (iter)->end, (iter), }
65 
66 static inline void spa_json_enter(struct spa_json * iter, struct spa_json * sub)
67 {
68  *sub = SPA_JSON_ENTER(iter);
69 }
70 
71 #define SPA_JSON_SAVE(iter) (struct spa_json) { (iter)->cur, (iter)->end, }
72 
75 static inline int spa_json_next(struct spa_json * iter, const char **value)
76 {
77  int utf8_remain = 0;
78  enum { __NONE, __STRUCT, __BARE, __STRING, __UTF8, __ESC, __COMMENT };
79 
80  *value = iter->cur;
81  for (; iter->cur < iter->end; iter->cur++) {
82  unsigned char cur = (unsigned char)*iter->cur;
83  again:
84  switch (iter->state) {
85  case __NONE:
86  iter->state = __STRUCT;
87  iter->depth = 0;
88  goto again;
89  case __STRUCT:
90  switch (cur) {
91  case '\0': case '\t': case ' ': case '\r': case '\n': case ':': case '=': case ',':
92  continue;
93  case '#':
94  iter->state = __COMMENT;
95  continue;
96  case '"':
97  *value = iter->cur;
98  iter->state = __STRING;
99  continue;
100  case '[': case '{':
101  *value = iter->cur;
102  if (++iter->depth > 1)
103  continue;
104  iter->cur++;
105  return 1;
106  case '}': case ']':
107  if (iter->depth == 0) {
108  if (iter->parent)
109  iter->parent->cur = iter->cur;
110  return 0;
111  }
112  --iter->depth;
113  continue;
114  default:
115  *value = iter->cur;
116  iter->state = __BARE;
117  }
118  continue;
119  case __BARE:
120  switch (cur) {
121  case '\t': case ' ': case '\r': case '\n':
122  case ':': case ',': case '=': case ']': case '}':
123  iter->state = __STRUCT;
124  if (iter->depth > 0)
125  goto again;
126  return iter->cur - *value;
127  }
128  continue;
129  case __STRING:
130  switch (cur) {
131  case '\\':
132  iter->state = __ESC;
133  continue;
134  case '"':
135  iter->state = __STRUCT;
136  if (iter->depth > 0)
137  continue;
138  return ++iter->cur - *value;
139  case 240 ... 247:
140  utf8_remain++;
142  case 224 ... 239:
143  utf8_remain++;
145  case 192 ... 223:
146  utf8_remain++;
147  iter->state = __UTF8;
148  continue;
149  default:
150  if (cur >= 32 && cur <= 126)
151  continue;
152  }
153  return -1;
154  case __UTF8:
155  switch (cur) {
156  case 128 ... 191:
157  if (--utf8_remain == 0)
158  iter->state = __STRING;
159  continue;
160  }
161  return -1;
162  case __ESC:
163  switch (cur) {
164  case '"': case '\\': case '/': case 'b': case 'f':
165  case 'n': case 'r': case 't': case 'u':
166  iter->state = __STRING;
167  continue;
168  }
169  return -1;
170  case __COMMENT:
171  switch (cur) {
172  case '\n': case '\r':
173  iter->state = __STRUCT;
174  }
175  }
176 
177  }
178  if (iter->depth != 0)
179  return -1;
180  if (iter->state != __STRUCT) {
181  iter->state = __STRUCT;
182  return iter->cur - *value;
183  }
184  return 0;
185 }
186 
187 static inline int spa_json_enter_container(struct spa_json *iter, struct spa_json *sub, char type)
188 {
189  const char *value;
190  if (spa_json_next(iter, &value) <= 0 || *value != type)
191  return -1;
192  spa_json_enter(iter, sub);
193  return 1;
194 }
195 
196 static inline int spa_json_is_container(const char *val, int len)
197 {
198  return len > 0 && (*val == '{' || *val == '[');
199 }
200 
201 static inline int spa_json_container_len(struct spa_json *iter, const char *value, int len)
202 {
203  const char *val;
204  struct spa_json sub;
205  spa_json_enter(iter, &sub);
206  while (spa_json_next(&sub, &val) > 0);
207  return sub.cur + 1 - value;
208 }
209 
210 /* object */
211 static inline int spa_json_is_object(const char *val, int len)
212 {
213  return len > 0 && *val == '{';
214 }
215 static inline int spa_json_enter_object(struct spa_json *iter, struct spa_json *sub)
216 {
217  return spa_json_enter_container(iter, sub, '{');
218 }
219 
220 /* array */
221 static inline bool spa_json_is_array(const char *val, int len)
222 {
223  return len > 0 && *val == '[';
224 }
225 static inline int spa_json_enter_array(struct spa_json *iter, struct spa_json *sub)
226 {
227  return spa_json_enter_container(iter, sub, '[');
228 }
229 
230 /* null */
231 static inline bool spa_json_is_null(const char *val, int len)
232 {
233  return len == 4 && strncmp(val, "null", 4) == 0;
234 }
235 
236 /* float */
237 static inline int spa_json_parse_float(const char *val, int len, float *result)
238 {
239  char *end;
240  *result = strtof(val, &end);
241  return end == val + len;
242 }
243 static inline bool spa_json_is_float(const char *val, int len)
244 {
245  float dummy;
246  return spa_json_parse_float(val, len, &dummy);
247 }
248 static inline int spa_json_get_float(struct spa_json *iter, float *res)
249 {
250  const char *value;
251  int len;
252  if ((len = spa_json_next(iter, &value)) <= 0)
253  return -1;
254  return spa_json_parse_float(value, len, res);
255 }
256 
257 /* int */
258 static inline int spa_json_parse_int(const char *val, int len, int *result)
259 {
260  char *end;
261  *result = strtol(val, &end, 0);
262  return end == val + len;
263 }
264 static inline bool spa_json_is_int(const char *val, int len)
265 {
266  int dummy;
267  return spa_json_parse_int(val, len, &dummy);
268 }
269 static inline int spa_json_get_int(struct spa_json *iter, int *res)
270 {
271  const char *value;
272  int len;
273  if ((len = spa_json_next(iter, &value)) <= 0)
274  return -1;
275  return spa_json_parse_int(value, len, res);
276 }
277 
278 /* bool */
279 static inline bool spa_json_is_true(const char *val, int len)
280 {
281  return len == 4 && strncmp(val, "true", 4) == 0;
282 }
283 
284 static inline bool spa_json_is_false(const char *val, int len)
285 {
286  return len == 5 && strncmp(val, "false", 5) == 0;
287 }
288 
289 static inline bool spa_json_is_bool(const char *val, int len)
290 {
291  return spa_json_is_true(val, len) || spa_json_is_false(val, len);
292 }
293 
294 static inline int spa_json_parse_bool(const char *val, int len, bool *result)
295 {
296  if ((*result = spa_json_is_true(val, len)))
297  return 1;
298  if (!(*result = !spa_json_is_false(val, len)))
299  return 1;
300  return -1;
301 }
302 static inline int spa_json_get_bool(struct spa_json *iter, bool *res)
303 {
304  const char *value;
305  int len;
306  if ((len = spa_json_next(iter, &value)) <= 0)
307  return -1;
308  return spa_json_parse_bool(value, len, res);
309 }
310 
311 /* string */
312 static inline bool spa_json_is_string(const char *val, int len)
313 {
314  return len > 1 && *val == '"';
315 }
316 
317 static inline int spa_json_parse_string(const char *val, int len, char *result)
318 {
319  const char *p;
320  if (!spa_json_is_string(val, len)) {
321  if (result != val)
322  strncpy(result, val, len);
323  result += len;
324  } else {
325  for (p = val+1; p < val + len; p++) {
326  if (*p == '\\') {
327  p++;
328  if (*p == 'n')
329  *result++ = '\n';
330  else if (*p == 'r')
331  *result++ = '\r';
332  else if (*p == 'b')
333  *result++ = '\b';
334  else if (*p == 't')
335  *result++ = '\t';
336  else if (*p == 'f')
337  *result++ = '\f';
338  else if (*p == 'u') {
339  char *end;
340  uint16_t v = strtol(p+1, &end, 16);
341  if (p+1 == end) {
342  *result++ = *p;
343  } else {
344  p = end-1;
345  if (v > 0xff)
346  *result++ = (v >> 8) & 0xff;
347  *result++ = v & 0xff;
348  }
349  } else
350  *result++ = *p;
351  } else if (*p == '\"') {
352  break;
353  } else
354  *result++ = *p;
355  }
356  }
357  *result = '\0';
358  return 1;
359 }
360 
361 static inline int spa_json_get_string(struct spa_json *iter, char *res, int maxlen)
362 {
363  const char *value;
364  int len;
365  if ((len = spa_json_next(iter, &value)) <= 0 || maxlen <= len)
366  return -1;
367  return spa_json_parse_string(value, len, res);
368 }
369 
370 static inline int spa_json_encode_string(char *str, int size, const char *val)
371 {
372  int len = 0;
373  static const char hex[] = { "0123456789abcdef" };
374 #define __PUT(c) { if (len < size) *str++ = c; len++; }
375  __PUT('"');
376  while (*val) {
377  switch (*val) {
378  case '\n':
379  __PUT('\\'); __PUT('n');
380  break;
381  case '\r':
382  __PUT('\\'); __PUT('r');
383  break;
384  case '\b':
385  __PUT('\\'); __PUT('b');
386  break;
387  case '\t':
388  __PUT('\\'); __PUT('t');
389  break;
390  case '\f':
391  __PUT('\\'); __PUT('f');
392  break;
393  case '\\':
394  case '"':
395  __PUT('\\'); __PUT(*val);
396  break;
397  default:
398  if (*val > 0 && *val < 0x20) {
399  __PUT('\\'); __PUT('u');
400  __PUT('0'); __PUT('0');
401  __PUT(hex[((*val)>>4)&0xf]); __PUT(hex[(*val)&0xf]);
402  } else {
403  __PUT(*val);
404  }
405  break;
406  }
407  val++;
408  }
409  __PUT('"');
410  __PUT('\0');
411 #undef __PUT
412  return len-1;
413 }
414 
419 #ifdef __cplusplus
420 } /* extern "C" */
421 #endif
422 
423 #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:209
static bool spa_json_is_string(const char *val, int len)
Definition: json.h:320
static bool spa_json_is_float(const char *val, int len)
Definition: json.h:251
static int spa_json_parse_float(const char *val, int len, float *result)
Definition: json.h:245
static bool spa_json_is_true(const char *val, int len)
Definition: json.h:287
static int spa_json_enter_container(struct spa_json *iter, struct spa_json *sub, char type)
Definition: json.h:195
static void spa_json_enter(struct spa_json *iter, struct spa_json *sub)
Definition: json.h:73
static bool spa_json_is_false(const char *val, int len)
Definition: json.h:292
static int spa_json_get_int(struct spa_json *iter, int *res)
Definition: json.h:277
static int spa_json_parse_bool(const char *val, int len, bool *result)
Definition: json.h:302
static int spa_json_enter_object(struct spa_json *iter, struct spa_json *sub)
Definition: json.h:223
static int spa_json_get_string(struct spa_json *iter, char *res, int maxlen)
Definition: json.h:369
static bool spa_json_is_bool(const char *val, int len)
Definition: json.h:297
#define SPA_JSON_INIT(data, size)
Definition: json.h:64
static bool spa_json_is_array(const char *val, int len)
Definition: json.h:229
static int spa_json_get_bool(struct spa_json *iter, bool *res)
Definition: json.h:310
static bool spa_json_is_null(const char *val, int len)
Definition: json.h:239
#define SPA_JSON_ENTER(iter)
Definition: json.h:71
static int spa_json_encode_string(char *str, int size, const char *val)
Definition: json.h:378
static int spa_json_parse_int(const char *val, int len, int *result)
Definition: json.h:266
static int spa_json_next(struct spa_json *iter, const char **value)
Get the next token.
Definition: json.h:83
static int spa_json_is_container(const char *val, int len)
Definition: json.h:204
static void spa_json_init(struct spa_json *iter, const char *data, size_t size)
Definition: json.h:66
static bool spa_json_is_int(const char *val, int len)
Definition: json.h:272
static int spa_json_enter_array(struct spa_json *iter, struct spa_json *sub)
Definition: json.h:233
static int spa_json_get_float(struct spa_json *iter, float *res)
Definition: json.h:256
static int spa_json_is_object(const char *val, int len)
Definition: json.h:219
static int spa_json_parse_string(const char *val, int len, char *result)
Definition: json.h:325
#define SPA_FALLTHROUGH
SPA_FALLTHROUGH is an annotation to suppress compiler warnings about switch cases that fall through w...
Definition: defs.h:76
#define __PUT(c)
spa/utils/string.h
Definition: json.h:55
uint32_t depth
Definition: json.h:60
const char * cur
Definition: json.h:56
uint32_t state
Definition: json.h:59
const char * end
Definition: json.h:57
struct spa_json * parent
Definition: json.h:58