PipeWire: spa/utils/json.h Source File

PipeWire 0.3.51

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};
60
61#define SPA_JSON_INIT(data,size) (struct spa_json) { (data), (data)+(size), }
62
63 static 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
69 static 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 };
82
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++;
144 SPA_FALLTHROUGH;
145 case 224 ... 239:
146 utf8_remain++;
147 SPA_FALLTHROUGH;
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}
198
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}
212
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}
222
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}
232
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 *result = spa_strtof(val, &end);
244 return len > 0 && end == val + len;
245}
246
247static inline bool spa_json_is_float(const char *val, int len)
248{
249 float dummy;
250 return spa_json_parse_float(val, len, &dummy);
251}
252static inline int spa_json_get_float(struct spa_json *iter, float *res)
253{
254 const char *value;
255 int len;
256 if ((len = spa_json_next(iter, &value)) <= 0)
257 return -1;
258 return spa_json_parse_float(value, len, res);
259}
260
261static inline char *spa_json_format_float(char *str, int size, float val)
262{
263 if (SPA_UNLIKELY(!isnormal(val))) {
264 if (val == INFINITY)
265 val = FLT_MAX;
266 else if (val == -INFINITY)
267 val = FLT_MIN;
268 else
269 val = 0.0f;
270 }
271 return spa_dtoa(str, size, val);
272}
273
274/* int */
275static inline int spa_json_parse_int(const char *val, int len, int *result)
276{
277 char *end;
278 *result = strtol(val, &end, 0);
279 return len > 0 && end == val + len;
280}
281static inline bool spa_json_is_int(const char *val, int len)
282{
283 int dummy;
284 return spa_json_parse_int(val, len, &dummy);
285}
286static inline int spa_json_get_int(struct spa_json *iter, int *res)
287{
288 const char *value;
289 int len;
290 if ((len = spa_json_next(iter, &value)) <= 0)
291 return -1;
292 return spa_json_parse_int(value, len, res);
293}
294
295/* bool */
296static inline bool spa_json_is_true(const char *val, int len)
297{
298 return len == 4 && strncmp(val, "true", 4) == 0;
299}
300
301static inline bool spa_json_is_false(const char *val, int len)
302{
303 return len == 5 && strncmp(val, "false", 5) == 0;
304}
305
306static inline bool spa_json_is_bool(const char *val, int len)
307{
308 return spa_json_is_true(val, len) || spa_json_is_false(val, len);
309}
310
311static inline int spa_json_parse_bool(const char *val, int len, bool *result)
312{
313 if ((*result = spa_json_is_true(val, len)))
314 return 1;
315 if (!(*result = !spa_json_is_false(val, len)))
316 return 1;
317 return -1;
318}
319 static inline int spa_json_get_bool(struct spa_json *iter, bool *res)
320{
321 const char *value;
322 int len;
323 if ((len = spa_json_next(iter, &value)) <= 0)
324 return -1;
325 return spa_json_parse_bool(value, len, res);
326}
327
328/* string */
329static inline bool spa_json_is_string(const char *val, int len)
330{
331 return len > 1 && *val == '"';
332}
333
334static inline int spa_json_parse_hex(const char *p, int num, uint32_t *res)
335{
336 int i;
337 *res = 0;
338 for (i = 0; i < num; i++) {
339 char v = p[i];
340 if (v >= '0' && v <= '9')
341 v = v - '0';
342 else if (v >= 'a' && v <= 'f')
343 v = v - 'a' + 10;
344 else if (v >= 'A' && v <= 'F')
345 v = v - 'A' + 10;
346 else
347 return -1;
348 *res = (*res << 4) | v;
349 }
350 return 1;
351}
352
353static inline int spa_json_parse_stringn(const char *val, int len, char *result, int maxlen)
354{
355 const char *p;
356 if (maxlen <= len)
357 return -1;
358 if (!spa_json_is_string(val, len)) {
359 if (result != val)
360 strncpy(result, val, len);
361 result += len;
362 } else {
363 for (p = val+1; p < val + len; p++) {
364 if (*p == '\\') {
365 p++;
366 if (*p == 'n')
367 *result++ = '\n';
368 else if (*p == 'r')
369 *result++ = '\r';
370 else if (*p == 'b')
371 *result++ = '\b';
372 else if (*p == 't')
373 *result++ = '\t';
374 else if (*p == 'f')
375 *result++ = '\f';
376 else if (*p == 'u') {
377 uint8_t prefix[] = { 0, 0xc0, 0xe0, 0xf0 };
378 uint32_t idx, n, v, cp, enc[] = { 0x80, 0x800, 0x10000 };
379 if (val + len - p < 5 ||
380 spa_json_parse_hex(p+1, 4, &cp) < 0) {
381 *result++ = *p;
382 continue;
383 }
384 p += 4;
385
386 if (cp >= 0xd800 && cp <= 0xdbff) {
387 if (val + len - p < 7 ||
388 p[1] != '\\' || p[2] != 'u' ||
389 spa_json_parse_hex(p+3, 4, &v) < 0 ||
390 v < 0xdc00 || v > 0xdfff)
391 continue;
392 p += 6;
393 cp = 0x010000 | ((cp & 0x3ff) << 10) | (v & 0x3ff);
394 } else if (cp >= 0xdc00 && cp <= 0xdfff)
395 continue;
396
397 for (idx = 0; idx < 3; idx++)
398 if (cp < enc[idx])
399 break;
400 for (n = idx; n > 0; n--, cp >>= 6)
401 result[n] = (cp | 0x80) & 0xbf;
402 *result++ = (cp | prefix[idx]) & 0xff;
403 result += idx;
404 } else
405 *result++ = *p;
406 } else if (*p == '\"') {
407 break;
408 } else
409 *result++ = *p;
410 }
411 }
412 *result = '\0';
413 return 1;
414}
415
416static inline int spa_json_parse_string(const char *val, int len, char *result)
417{
418 return spa_json_parse_stringn(val, len, result, len+1);
419}
420
421static inline int spa_json_get_string(struct spa_json *iter, char *res, int maxlen)
422{
423 const char *value;
424 int len;
425 if ((len = spa_json_next(iter, &value)) <= 0)
426 return -1;
427 return spa_json_parse_stringn(value, len, res, maxlen);
428}
429
430static inline int spa_json_encode_string(char *str, int size, const char *val)
431{
432 int len = 0;
433 static const char hex[] = { "0123456789abcdef" };
434#define __PUT(c) { if (len < size) *str++ = c; len++; }
435 __PUT('"');
436 while (*val) {
437 switch (*val) {
438 case '\n':
439 __PUT('\\'); __PUT('n');
440 break;
441 case '\r':
442 __PUT('\\'); __PUT('r');
443 break;
444 case '\b':
445 __PUT('\\'); __PUT('b');
446 break;
447 case '\t':
448 __PUT('\\'); __PUT('t');
449 break;
450 case '\f':
451 __PUT('\\'); __PUT('f');
452 break;
453 case '\\':
454 case '"':
455 __PUT('\\'); __PUT(*val);
456 break;
457 default:
458 if (*val > 0 && *val < 0x20) {
459 __PUT('\\'); __PUT('u');
460 __PUT('0'); __PUT('0');
461 __PUT(hex[((*val)>>4)&0xf]); __PUT(hex[(*val)&0xf]);
462 } else {
463 __PUT(*val);
464 }
465 break;
466 }
467 val++;
468 }
469 __PUT('"');
470 __PUT('\0');
471#undef __PUT
472 return len-1;
473}
474
479#ifdef __cplusplus
480} /* extern "C" */
481#endif
482
483#endif /* SPA_UTILS_JSON_H */
defs.h
spa/utils/defs.h
spa_json_container_len
static int spa_json_container_len(struct spa_json *iter, const char *value, int len)
Definition: json.h:212
spa_json_is_string
static bool spa_json_is_string(const char *val, int len)
Definition: json.h:337
spa_json_is_float
static bool spa_json_is_float(const char *val, int len)
Definition: json.h:255
spa_json_parse_float
static int spa_json_parse_float(const char *val, int len, float *result)
Definition: json.h:248
spa_json_is_true
static bool spa_json_is_true(const char *val, int len)
Definition: json.h:304
spa_json_parse_stringn
static int spa_json_parse_stringn(const char *val, int len, char *result, int maxlen)
Definition: json.h:361
spa_json_enter_container
static int spa_json_enter_container(struct spa_json *iter, struct spa_json *sub, char type)
Definition: json.h:198
spa_json_enter
static void spa_json_enter(struct spa_json *iter, struct spa_json *sub)
Definition: json.h:76
spa_json_parse_hex
static int spa_json_parse_hex(const char *p, int num, uint32_t *res)
Definition: json.h:342
spa_json_is_false
static bool spa_json_is_false(const char *val, int len)
Definition: json.h:309
spa_json_get_int
static int spa_json_get_int(struct spa_json *iter, int *res)
Definition: json.h:294
spa_json_parse_bool
static int spa_json_parse_bool(const char *val, int len, bool *result)
Definition: json.h:319
spa_json_enter_object
static int spa_json_enter_object(struct spa_json *iter, struct spa_json *sub)
Definition: json.h:226
spa_json_get_string
static int spa_json_get_string(struct spa_json *iter, char *res, int maxlen)
Definition: json.h:429
spa_json_is_bool
static bool spa_json_is_bool(const char *val, int len)
Definition: json.h:314
SPA_JSON_INIT
#define SPA_JSON_INIT(data, size)
Definition: json.h:67
spa_json_format_float
static char * spa_json_format_float(char *str, int size, float val)
Definition: json.h:269
spa_json_is_array
static bool spa_json_is_array(const char *val, int len)
Definition: json.h:232
spa_json_get_bool
static int spa_json_get_bool(struct spa_json *iter, bool *res)
Definition: json.h:327
spa_json_is_null
static bool spa_json_is_null(const char *val, int len)
Definition: json.h:242
SPA_JSON_ENTER
#define SPA_JSON_ENTER(iter)
Definition: json.h:74
spa_json_encode_string
static int spa_json_encode_string(char *str, int size, const char *val)
Definition: json.h:438
spa_json_parse_int
static int spa_json_parse_int(const char *val, int len, int *result)
Definition: json.h:283
spa_json_next
static int spa_json_next(struct spa_json *iter, const char **value)
Get the next token.
Definition: json.h:86
spa_json_is_container
static int spa_json_is_container(const char *val, int len)
Definition: json.h:207
spa_json_init
static void spa_json_init(struct spa_json *iter, const char *data, size_t size)
Definition: json.h:69
spa_json_is_int
static bool spa_json_is_int(const char *val, int len)
Definition: json.h:289
spa_json_enter_array
static int spa_json_enter_array(struct spa_json *iter, struct spa_json *sub)
Definition: json.h:236
spa_json_get_float
static int spa_json_get_float(struct spa_json *iter, float *res)
Definition: json.h:260
spa_json_is_object
static int spa_json_is_object(const char *val, int len)
Definition: json.h:222
spa_json_parse_string
static int spa_json_parse_string(const char *val, int len, char *result)
Definition: json.h:424
spa_strtof
static float spa_strtof(const char *str, char **endptr)
Convert str to a float in the C locale.
Definition: string.h:281
spa_dtoa
static char * spa_dtoa(char *str, size_t size, double val)
Definition: string.h:362
SPA_UNLIKELY
#define SPA_UNLIKELY(x)
Definition: defs.h:315
SPA_FALLTHROUGH
#define SPA_FALLTHROUGH
SPA_FALLTHROUGH is an annotation to suppress compiler warnings about switch cases that fall through w...
Definition: defs.h:76
__PUT
#define __PUT(c)
string.h
spa/utils/string.h
spa_json
Definition: json.h:58
spa_json::depth
uint32_t depth
Definition: json.h:63
spa_json::cur
const char * cur
Definition: json.h:59
spa_json::state
uint32_t state
Definition: json.h:62
spa_json::end
const char * end
Definition: json.h:60
spa_json::parent
struct spa_json * parent
Definition: json.h:61