PipeWire: spa/utils/json.h Source File

PipeWire 0.3.50

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_stringn(const char *val, int len, char *result, int maxlen)
335{
336 const char *p;
337 if (maxlen <= len)
338 return -1;
339 if (!spa_json_is_string(val, len)) {
340 if (result != val)
341 strncpy(result, val, len);
342 result += len;
343 } else {
344 for (p = val+1; p < val + len; p++) {
345 if (*p == '\\') {
346 p++;
347 if (*p == 'n')
348 *result++ = '\n';
349 else if (*p == 'r')
350 *result++ = '\r';
351 else if (*p == 'b')
352 *result++ = '\b';
353 else if (*p == 't')
354 *result++ = '\t';
355 else if (*p == 'f')
356 *result++ = '\f';
357 else if (*p == 'u') {
358 char *end;
359 uint16_t v = strtol(p+1, &end, 16);
360 if (p+1 == end) {
361 *result++ = *p;
362 } else {
363 p = end-1;
364 if (v > 0xff)
365 *result++ = (v >> 8) & 0xff;
366 *result++ = v & 0xff;
367 }
368 } else
369 *result++ = *p;
370 } else if (*p == '\"') {
371 break;
372 } else
373 *result++ = *p;
374 }
375 }
376 *result = '\0';
377 return 1;
378}
379
380static inline int spa_json_parse_string(const char *val, int len, char *result)
381{
382 return spa_json_parse_stringn(val, len, result, len+1);
383}
384
385static inline int spa_json_get_string(struct spa_json *iter, char *res, int maxlen)
386{
387 const char *value;
388 int len;
389 if ((len = spa_json_next(iter, &value)) <= 0)
390 return -1;
391 return spa_json_parse_stringn(value, len, res, maxlen);
392}
393
394static inline int spa_json_encode_string(char *str, int size, const char *val)
395{
396 int len = 0;
397 static const char hex[] = { "0123456789abcdef" };
398#define __PUT(c) { if (len < size) *str++ = c; len++; }
399 __PUT('"');
400 while (*val) {
401 switch (*val) {
402 case '\n':
403 __PUT('\\'); __PUT('n');
404 break;
405 case '\r':
406 __PUT('\\'); __PUT('r');
407 break;
408 case '\b':
409 __PUT('\\'); __PUT('b');
410 break;
411 case '\t':
412 __PUT('\\'); __PUT('t');
413 break;
414 case '\f':
415 __PUT('\\'); __PUT('f');
416 break;
417 case '\\':
418 case '"':
419 __PUT('\\'); __PUT(*val);
420 break;
421 default:
422 if (*val > 0 && *val < 0x20) {
423 __PUT('\\'); __PUT('u');
424 __PUT('0'); __PUT('0');
425 __PUT(hex[((*val)>>4)&0xf]); __PUT(hex[(*val)&0xf]);
426 } else {
427 __PUT(*val);
428 }
429 break;
430 }
431 val++;
432 }
433 __PUT('"');
434 __PUT('\0');
435#undef __PUT
436 return len-1;
437}
438
443#ifdef __cplusplus
444} /* extern "C" */
445#endif
446
447#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:342
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_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:393
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:402
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:388
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:360
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