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