2 * Copyright (c) 2018 Christos Zoulas
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
15 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
16 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
28 * Parse JSON object serialization format (RFC-7159)
35 FILE_RCSID("@(#)$File: is_json.c,v 1.13 2019/03/02 01:08:10 christos Exp $")
44 #define DPRINTF(a, b, c) \
45 printf("%s [%.2x/%c] %.20s\n", (a), *(b), *(b), (const char *)(c))
47 #define DPRINTF(a, b, c) do { } while (/*CONSTCOND*/0)
51 #define JSON_CONSTANT 1
60 * count all the objects, require that we have the whole data file
62 * stop if we find an object or an array
68 static int json_parse(const unsigned char **, const unsigned char *, size_t *,
72 json_isspace(const unsigned char uc)
86 json_isdigit(unsigned char uc)
89 case '0': case '1': case '2': case '3': case '4':
90 case '5': case '6': case '7': case '8': case '9':
98 json_isxdigit(unsigned char uc)
100 if (json_isdigit(uc))
103 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
104 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
111 static const unsigned char *
112 json_skip_space(const unsigned char *uc, const unsigned char *ue)
114 while (uc < ue && json_isspace(*uc))
120 json_parse_string(const unsigned char **ucp, const unsigned char *ue)
122 const unsigned char *uc = *ucp;
125 DPRINTF("Parse string: ", uc, *ucp);
150 for (i = 0; i < 4; i++)
151 if (!json_isxdigit(*uc++))
165 DPRINTF("Bad string: ", uc, *ucp);
171 json_parse_array(const unsigned char **ucp, const unsigned char *ue,
172 size_t *st, size_t lvl)
174 const unsigned char *uc = *ucp;
175 int more = 0; /* Array has more than 1 element */
177 DPRINTF("Parse array: ", uc, *ucp);
179 if (!json_parse(&uc, ue, st, lvl + 1))
198 DPRINTF("Bad array: ", uc, *ucp);
204 json_parse_object(const unsigned char **ucp, const unsigned char *ue,
205 size_t *st, size_t lvl)
207 const unsigned char *uc = *ucp;
208 DPRINTF("Parse object: ", uc, *ucp);
210 uc = json_skip_space(uc, ue);
214 DPRINTF("not string", uc, *ucp);
217 DPRINTF("next field", uc, *ucp);
218 if (!json_parse_string(&uc, ue)) {
219 DPRINTF("not string", uc, *ucp);
222 uc = json_skip_space(uc, ue);
226 DPRINTF("not colon", uc, *ucp);
229 if (!json_parse(&uc, ue, st, lvl + 1)) {
230 DPRINTF("not json", uc, *ucp);
240 DPRINTF("Good object: ", uc, *ucp);
244 DPRINTF("not more", uc, *ucp);
249 DPRINTF("Bad object: ", uc, *ucp);
255 json_parse_number(const unsigned char **ucp, const unsigned char *ue)
257 const unsigned char *uc = *ucp;
260 DPRINTF("Parse number: ", uc, *ucp);
266 for (; uc < ue; uc++) {
267 if (!json_isdigit(*uc))
275 for (; uc < ue; uc++) {
276 if (!json_isdigit(*uc))
282 if (got && (*uc == 'e' || *uc == 'E')) {
287 if (*uc == '+' || *uc == '-')
289 for (; uc < ue; uc++) {
290 if (!json_isdigit(*uc))
297 DPRINTF("Bad number: ", uc, *ucp);
299 DPRINTF("Good number: ", uc, *ucp);
305 json_parse_const(const unsigned char **ucp, const unsigned char *ue,
306 const char *str, size_t len)
308 const unsigned char *uc = *ucp;
310 DPRINTF("Parse const: ", uc, *ucp);
311 for (len--; uc < ue && --len;) {
316 DPRINTF("Bad const: ", uc, *ucp);
322 json_parse(const unsigned char **ucp, const unsigned char *ue,
323 size_t *st, size_t lvl)
325 const unsigned char *uc;
329 uc = json_skip_space(*ucp, ue);
337 /* bail quickly if not counting */
338 if (lvl > 1 && (st[JSON_OBJECT] || st[JSON_ARRAYN]))
342 DPRINTF("Parse general: ", uc, *ucp);
345 rv = json_parse_string(&uc, ue);
349 rv = json_parse_array(&uc, ue, st, lvl + 1);
353 rv = json_parse_object(&uc, ue, st, lvl + 1);
357 rv = json_parse_const(&uc, ue, "true", sizeof("true"));
361 rv = json_parse_const(&uc, ue, "false", sizeof("false"));
365 rv = json_parse_const(&uc, ue, "null", sizeof("null"));
370 rv = json_parse_number(&uc, ue);
376 uc = json_skip_space(uc, ue);
379 DPRINTF("End general: ", uc, *ucp);
381 return rv && (st[JSON_ARRAYN] || st[JSON_OBJECT]);
387 file_is_json(struct magic_set *ms, const struct buffer *b)
389 const unsigned char *uc = CAST(const unsigned char *, b->fbuf);
390 const unsigned char *ue = uc + b->flen;
392 int mime = ms->flags & MAGIC_MIME;
395 if ((ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION)) != 0)
398 memset(st, 0, sizeof(st));
400 if (!json_parse(&uc, ue, st, 0))
403 if (mime == MAGIC_MIME_ENCODING)
406 if (file_printf(ms, "application/json") == -1)
410 if (file_printf(ms, "JSON data") == -1)
413 #define P(n) st[n], st[n] > 1 ? "s" : ""
414 if (file_printf(ms, " (%" SIZE_T_FORMAT "u object%s, %" SIZE_T_FORMAT
415 "u array%s, %" SIZE_T_FORMAT "u string%s, %" SIZE_T_FORMAT
416 "u constant%s, %" SIZE_T_FORMAT "u number%s, %" SIZE_T_FORMAT
418 P(JSON_OBJECT), P(JSON_ARRAY), P(JSON_STRING), P(JSON_CONSTANT),
419 P(JSON_NUMBER), P(JSON_ARRAYN))
428 #include <sys/types.h>
429 #include <sys/stat.h>
438 main(int argc, char *argv[])
443 size_t stats[JSON_MAX];
445 if ((fd = open(argv[1], O_RDONLY)) == -1)
446 err(EXIT_FAILURE, "Can't open `%s'", argv[1]);
448 if (fstat(fd, &st) == -1)
449 err(EXIT_FAILURE, "Can't stat `%s'", argv[1]);
451 if ((p = malloc(st.st_size)) == NULL)
452 err(EXIT_FAILURE, "Can't allocate %jd bytes",
453 (intmax_t)st.st_size);
454 if (read(fd, p, st.st_size) != st.st_size)
455 err(EXIT_FAILURE, "Can't read %jd bytes",
456 (intmax_t)st.st_size);
457 memset(stats, 0, sizeof(stats));
458 printf("is json %d\n", json_parse((const unsigned char **)&p,
459 p + st.st_size, stats, 0));