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
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
38#include <spa/utils/defs.h>
39
48/* a simple JSON compatible tokenizer */
49struct spa_json {
50 const char *cur;
51 const char *end;
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 */
bool spa_json_is_null(const char *val, int len)
Definition: json.h:230
int spa_json_get_bool(struct spa_json *iter, bool *res)
Definition: json.h:301
int spa_json_parse_int(const char *val, int len, int *result)
Definition: json.h:257
bool spa_json_is_true(const char *val, int len)
Definition: json.h:278
int spa_json_enter_array(struct spa_json *iter, struct spa_json *sub)
Definition: json.h:224
bool spa_json_is_array(const char *val, int len)
Definition: json.h:220
int spa_json_parse_bool(const char *val, int len, bool *result)
Definition: json.h:293
bool spa_json_is_false(const char *val, int len)
Definition: json.h:283
int spa_json_is_object(const char *val, int len)
Definition: json.h:210
#define SPA_JSON_INIT(data, size)
Definition: json.h:57
bool spa_json_is_int(const char *val, int len)
Definition: json.h:263
bool spa_json_is_string(const char *val, int len)
Definition: json.h:311
int spa_json_parse_string(const char *val, int len, char *result)
Definition: json.h:316
bool spa_json_is_float(const char *val, int len)
Definition: json.h:242
int spa_json_encode_string(char *str, int size, const char *val)
Definition: json.h:369
int spa_json_parse_float(const char *val, int len, float *result)
Definition: json.h:236
int spa_json_enter_object(struct spa_json *iter, struct spa_json *sub)
Definition: json.h:214
int spa_json_container_len(struct spa_json *iter, const char *value, int len)
Definition: json.h:200
int spa_json_get_int(struct spa_json *iter, int *res)
Definition: json.h:268
#define SPA_JSON_ENTER(iter)
Definition: json.h:63
int spa_json_next(struct spa_json *iter, const char **value)
Get the next token.
Definition: json.h:74
void spa_json_enter(struct spa_json *iter, struct spa_json *sub)
Definition: json.h:65
int spa_json_enter_container(struct spa_json *iter, struct spa_json *sub, char type)
Definition: json.h:186
bool spa_json_is_bool(const char *val, int len)
Definition: json.h:288
int spa_json_is_container(const char *val, int len)
Definition: json.h:195
int spa_json_get_float(struct spa_json *iter, float *res)
Definition: json.h:247
int spa_json_get_string(struct spa_json *iter, char *res, int maxlen)
Definition: json.h:360
void spa_json_init(struct spa_json *iter, const char *data, size_t size)
Definition: json.h:59
#define SPA_FALLTHROUGH
SPA_FALLTHROUGH is an annotation to suppress compiler warnings about switch cases that fall through w...
Definition: defs.h:69
#define __PUT(c)
user data to add to an object
Definition: media-session.c:109
Definition: json.h:49
uint32_t depth
Definition: json.h:54
const char * cur
Definition: json.h:50
uint32_t state
Definition: json.h:53
const char * end
Definition: json.h:51
struct spa_json * parent
Definition: json.h:52