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