PipeWire  0.3.34
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 
70 #define SPA_JSON_SAVE(iter) (struct spa_json) { (iter)->cur, (iter)->end, }
71 
74 /* static */ inline int spa_json_next(struct spa_json * iter, const char **value)
75 {
76  int utf8_remain = 0;
77  enum { __NONE, __STRUCT, __BARE, __STRING, __UTF8, __ESC, __COMMENT };
78 
79  *value = iter->cur;
80  for (; iter->cur < iter->end; iter->cur++) {
81  unsigned char cur = (unsigned char)*iter->cur;
82  again:
83  switch (iter->state) {
84  case __NONE:
85  iter->state = __STRUCT;
86  iter->depth = 0;
87  goto again;
88  case __STRUCT:
89  switch (cur) {
90  case '\0': case '\t': case ' ': case '\r': case '\n': case ':': case '=': case ',':
91  continue;
92  case '#':
93  iter->state = __COMMENT;
94  continue;
95  case '"':
96  *value = iter->cur;
97  iter->state = __STRING;
98  continue;
99  case '[': case '{':
100  *value = iter->cur;
101  if (++iter->depth > 1)
102  continue;
103  iter->cur++;
104  return 1;
105  case '}': case ']':
106  if (iter->depth == 0) {
107  if (iter->parent)
108  iter->parent->cur = iter->cur;
109  return 0;
110  }
111  --iter->depth;
112  continue;
113  default:
114  *value = iter->cur;
115  iter->state = __BARE;
116  }
117  continue;
118  case __BARE:
119  switch (cur) {
120  case '\t': case ' ': case '\r': case '\n':
121  case ':': case ',': case '=': case ']': case '}':
122  iter->state = __STRUCT;
123  if (iter->depth > 0)
124  goto again;
125  return iter->cur - *value;
126  }
127  continue;
128  case __STRING:
129  switch (cur) {
130  case '\\':
131  iter->state = __ESC;
132  continue;
133  case '"':
134  iter->state = __STRUCT;
135  if (iter->depth > 0)
136  continue;
137  return ++iter->cur - *value;
138  case 240 ... 247:
139  utf8_remain++;
141  case 224 ... 239:
142  utf8_remain++;
144  case 192 ... 223:
145  utf8_remain++;
146  iter->state = __UTF8;
147  continue;
148  default:
149  if (cur >= 32 && cur <= 126)
150  continue;
151  }
152  return -1;
153  case __UTF8:
154  switch (cur) {
155  case 128 ... 191:
156  if (--utf8_remain == 0)
157  iter->state = __STRING;
158  continue;
159  }
160  return -1;
161  case __ESC:
162  switch (cur) {
163  case '"': case '\\': case '/': case 'b': case 'f':
164  case 'n': case 'r': case 't': case 'u':
165  iter->state = __STRING;
166  continue;
167  }
168  return -1;
169  case __COMMENT:
170  switch (cur) {
171  case '\n': case '\r':
172  iter->state = __STRUCT;
173  }
174  }
175 
176  }
177  if (iter->depth != 0)
178  return -1;
179  if (iter->state != __STRUCT) {
180  iter->state = __STRUCT;
181  return iter->cur - *value;
182  }
183  return 0;
184 }
185 
186 /* static */ inline int spa_json_enter_container(struct spa_json *iter, struct spa_json *sub, char type)
187 {
188  const char *value;
189  if (spa_json_next(iter, &value) <= 0 || *value != type)
190  return -1;
191  spa_json_enter(iter, sub);
192  return 1;
193 }
194 
195 /* static */ inline int spa_json_is_container(const char *val, int len)
196 {
197  return len > 0 && (*val == '{' || *val == '[');
198 }
199 
200 /* static */ inline int spa_json_container_len(struct spa_json *iter, const char *value, int len)
201 {
202  const char *val;
203  struct spa_json sub;
204  spa_json_enter(iter, &sub);
205  while (spa_json_next(&sub, &val) > 0);
206  return sub.cur + 1 - value;
207 }
208 
209 /* object */
210 /* static */ inline int spa_json_is_object(const char *val, int len)
211 {
212  return len > 0 && *val == '{';
213 }
214 /* static */ inline int spa_json_enter_object(struct spa_json *iter, struct spa_json *sub)
215 {
216  return spa_json_enter_container(iter, sub, '{');
217 }
218 
219 /* array */
220 /* static */ inline bool spa_json_is_array(const char *val, int len)
221 {
222  return len > 0 && *val == '[';
223 }
224 /* static */ inline int spa_json_enter_array(struct spa_json *iter, struct spa_json *sub)
225 {
226  return spa_json_enter_container(iter, sub, '[');
227 }
228 
229 /* null */
230 /* static */ inline bool spa_json_is_null(const char *val, int len)
231 {
232  return len == 4 && strncmp(val, "null", 4) == 0;
233 }
234 
235 /* float */
236 /* static */ inline int spa_json_parse_float(const char *val, int len, float *result)
237 {
238  char *end;
239  *result = strtof(val, &end);
240  return end == val + len;
241 }
242 /* static */ inline bool spa_json_is_float(const char *val, int len)
243 {
244  float dummy;
245  return spa_json_parse_float(val, len, &dummy);
246 }
247 /* static */ inline int spa_json_get_float(struct spa_json *iter, float *res)
248 {
249  const char *value;
250  int len;
251  if ((len = spa_json_next(iter, &value)) <= 0)
252  return -1;
253  return spa_json_parse_float(value, len, res);
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 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_string(const char *val, int len, char *result)
317 {
318  const char *p;
319  if (!spa_json_is_string(val, len)) {
320  if (result != val)
321  strncpy(result, val, len);
322  result += len;
323  } else {
324  for (p = val+1; p < val + len; p++) {
325  if (*p == '\\') {
326  p++;
327  if (*p == 'n')
328  *result++ = '\n';
329  else if (*p == 'r')
330  *result++ = '\r';
331  else if (*p == 'b')
332  *result++ = '\b';
333  else if (*p == 't')
334  *result++ = '\t';
335  else if (*p == 'f')
336  *result++ = '\f';
337  else if (*p == 'u') {
338  char *end;
339  uint16_t v = strtol(p+1, &end, 16);
340  if (p+1 == end) {
341  *result++ = *p;
342  } else {
343  p = end-1;
344  if (v > 0xff)
345  *result++ = (v >> 8) & 0xff;
346  *result++ = v & 0xff;
347  }
348  } else
349  *result++ = *p;
350  } else if (*p == '\"') {
351  break;
352  } else
353  *result++ = *p;
354  }
355  }
356  *result = '\0';
357  return 1;
358 }
359 
360 /* static */ inline int spa_json_get_string(struct spa_json *iter, char *res, int maxlen)
361 {
362  const char *value;
363  int len;
364  if ((len = spa_json_next(iter, &value)) <= 0 || maxlen <= len)
365  return -1;
366  return spa_json_parse_string(value, len, res);
367 }
368 
369 /* static */ inline int spa_json_encode_string(char *str, int size, const char *val)
370 {
371  int len = 0;
372  static const char hex[] = { "0123456789abcdef" };
373 #define __PUT(c) { if (len < size) *str++ = c; len++; }
374  __PUT('"');
375  while (*val) {
376  switch (*val) {
377  case '\n':
378  __PUT('\\'); __PUT('n');
379  break;
380  case '\r':
381  __PUT('\\'); __PUT('r');
382  break;
383  case '\b':
384  __PUT('\\'); __PUT('b');
385  break;
386  case '\t':
387  __PUT('\\'); __PUT('t');
388  break;
389  case '\f':
390  __PUT('\\'); __PUT('f');
391  break;
392  case '\\':
393  case '"':
394  __PUT('\\'); __PUT(*val);
395  break;
396  default:
397  if (*val > 0 && *val < 0x20) {
398  __PUT('\\'); __PUT('u');
399  __PUT('0'); __PUT('0');
400  __PUT(hex[((*val)>>4)&0xf]); __PUT(hex[(*val)&0xf]);
401  } else {
402  __PUT(*val);
403  }
404  break;
405  }
406  val++;
407  }
408  __PUT('"');
409  __PUT('\0');
410 #undef __PUT
411  return len-1;
412 }
413 
418 #ifdef __cplusplus
419 } /* extern "C" */
420 #endif
421 
422 #endif /* SPA_UTILS_JSON_H */
spa_json_get_int
int spa_json_get_int(struct spa_json *iter, int *res)
Definition: json.h:268
spa_json_is_true
bool spa_json_is_true(const char *val, int len)
Definition: json.h:278
spa_json_parse_int
int spa_json_parse_int(const char *val, int len, int *result)
Definition: json.h:257
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:200
spa_json_get_float
int spa_json_get_float(struct spa_json *iter, float *res)
Definition: json.h:247
spa_json_enter_object
int spa_json_enter_object(struct spa_json *iter, struct spa_json *sub)
Definition: json.h:214
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:186
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:288
spa_json_parse_float
int spa_json_parse_float(const char *val, int len, float *result)
Definition: json.h:236
spa_json_parse_bool
int spa_json_parse_bool(const char *val, int len, bool *result)
Definition: json.h:293
spa_json_is_float
bool spa_json_is_float(const char *val, int len)
Definition: json.h:242
spa_json_is_container
int spa_json_is_container(const char *val, int len)
Definition: json.h:195
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:210
spa_json_is_null
bool spa_json_is_null(const char *val, int len)
Definition: json.h:230
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:316
spa_json_get_string
int spa_json_get_string(struct spa_json *iter, char *res, int maxlen)
Definition: json.h:360
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:74
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:311
spa_json_enter_array
int spa_json_enter_array(struct spa_json *iter, struct spa_json *sub)
Definition: json.h:224
defs.h
spa_json_encode_string
int spa_json_encode_string(char *str, int size, const char *val)
Definition: json.h:369
spa_json_get_bool
int spa_json_get_bool(struct spa_json *iter, bool *res)
Definition: json.h:301
spa_json_is_array
bool spa_json_is_array(const char *val, int len)
Definition: json.h:220
spa_json
Definition: json.h:49
spa_json_is_int
bool spa_json_is_int(const char *val, int len)
Definition: json.h:263
spa_json_is_false
bool spa_json_is_false(const char *val, int len)
Definition: json.h:283