16fca56fbSSascha Wildner /*-
26fca56fbSSascha Wildner * Copyright (c) 2018 Christos Zoulas
36fca56fbSSascha Wildner * All rights reserved.
46fca56fbSSascha Wildner *
56fca56fbSSascha Wildner * Redistribution and use in source and binary forms, with or without
66fca56fbSSascha Wildner * modification, are permitted provided that the following conditions
76fca56fbSSascha Wildner * are met:
86fca56fbSSascha Wildner * 1. Redistributions of source code must retain the above copyright
96fca56fbSSascha Wildner * notice, this list of conditions and the following disclaimer.
106fca56fbSSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright
116fca56fbSSascha Wildner * notice, this list of conditions and the following disclaimer in the
126fca56fbSSascha Wildner * documentation and/or other materials provided with the distribution.
136fca56fbSSascha Wildner *
146fca56fbSSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
156fca56fbSSascha Wildner * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
166fca56fbSSascha Wildner * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
176fca56fbSSascha Wildner * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
186fca56fbSSascha Wildner * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
196fca56fbSSascha Wildner * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
206fca56fbSSascha Wildner * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
216fca56fbSSascha Wildner * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
226fca56fbSSascha Wildner * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
236fca56fbSSascha Wildner * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
246fca56fbSSascha Wildner * POSSIBILITY OF SUCH DAMAGE.
256fca56fbSSascha Wildner */
266fca56fbSSascha Wildner
276fca56fbSSascha Wildner /*
286fca56fbSSascha Wildner * Parse JSON object serialization format (RFC-7159)
296fca56fbSSascha Wildner */
306fca56fbSSascha Wildner
316fca56fbSSascha Wildner #ifndef TEST
326fca56fbSSascha Wildner #include "file.h"
336fca56fbSSascha Wildner
346fca56fbSSascha Wildner #ifndef lint
35*3b9cdfa3SAntonio Huete Jimenez FILE_RCSID("@(#)$File: is_json.c,v 1.26 2022/09/13 18:46:07 christos Exp $")
366fca56fbSSascha Wildner #endif
376fca56fbSSascha Wildner
386fca56fbSSascha Wildner #include "magic.h"
39*3b9cdfa3SAntonio Huete Jimenez #else
40*3b9cdfa3SAntonio Huete Jimenez #include <stdio.h>
41*3b9cdfa3SAntonio Huete Jimenez #include <stddef.h>
426fca56fbSSascha Wildner #endif
43*3b9cdfa3SAntonio Huete Jimenez #include <string.h>
446fca56fbSSascha Wildner
456fca56fbSSascha Wildner #ifdef DEBUG
466fca56fbSSascha Wildner #include <stdio.h>
476fca56fbSSascha Wildner #define DPRINTF(a, b, c) \
48*3b9cdfa3SAntonio Huete Jimenez printf("%*s%s [%.2x/%c] %.*s\n", (int)lvl, "", (a), *(b), *(b), \
49*3b9cdfa3SAntonio Huete Jimenez (int)(b - c), (const char *)(c))
50*3b9cdfa3SAntonio Huete Jimenez #define __file_debugused
516fca56fbSSascha Wildner #else
526fca56fbSSascha Wildner #define DPRINTF(a, b, c) do { } while (/*CONSTCOND*/0)
53*3b9cdfa3SAntonio Huete Jimenez #define __file_debugused __attribute__((__unused__))
546fca56fbSSascha Wildner #endif
556fca56fbSSascha Wildner
566fca56fbSSascha Wildner #define JSON_ARRAY 0
576fca56fbSSascha Wildner #define JSON_CONSTANT 1
586fca56fbSSascha Wildner #define JSON_NUMBER 2
596fca56fbSSascha Wildner #define JSON_OBJECT 3
606fca56fbSSascha Wildner #define JSON_STRING 4
616fca56fbSSascha Wildner #define JSON_ARRAYN 5
626fca56fbSSascha Wildner #define JSON_MAX 6
636fca56fbSSascha Wildner
646fca56fbSSascha Wildner /*
656fca56fbSSascha Wildner * if JSON_COUNT != 0:
666fca56fbSSascha Wildner * count all the objects, require that we have the whole data file
676fca56fbSSascha Wildner * otherwise:
686fca56fbSSascha Wildner * stop if we find an object or an array
696fca56fbSSascha Wildner */
706fca56fbSSascha Wildner #ifndef JSON_COUNT
716fca56fbSSascha Wildner #define JSON_COUNT 0
726fca56fbSSascha Wildner #endif
736fca56fbSSascha Wildner
746fca56fbSSascha Wildner static int json_parse(const unsigned char **, const unsigned char *, size_t *,
756fca56fbSSascha Wildner size_t);
766fca56fbSSascha Wildner
776fca56fbSSascha Wildner static int
json_isspace(const unsigned char uc)786fca56fbSSascha Wildner json_isspace(const unsigned char uc)
796fca56fbSSascha Wildner {
806fca56fbSSascha Wildner switch (uc) {
816fca56fbSSascha Wildner case ' ':
826fca56fbSSascha Wildner case '\n':
836fca56fbSSascha Wildner case '\r':
846fca56fbSSascha Wildner case '\t':
856fca56fbSSascha Wildner return 1;
866fca56fbSSascha Wildner default:
876fca56fbSSascha Wildner return 0;
886fca56fbSSascha Wildner }
896fca56fbSSascha Wildner }
906fca56fbSSascha Wildner
916fca56fbSSascha Wildner static int
json_isdigit(unsigned char uc)926fca56fbSSascha Wildner json_isdigit(unsigned char uc)
936fca56fbSSascha Wildner {
946fca56fbSSascha Wildner switch (uc) {
956fca56fbSSascha Wildner case '0': case '1': case '2': case '3': case '4':
966fca56fbSSascha Wildner case '5': case '6': case '7': case '8': case '9':
976fca56fbSSascha Wildner return 1;
986fca56fbSSascha Wildner default:
996fca56fbSSascha Wildner return 0;
1006fca56fbSSascha Wildner }
1016fca56fbSSascha Wildner }
1026fca56fbSSascha Wildner
1036fca56fbSSascha Wildner static int
json_isxdigit(unsigned char uc)1046fca56fbSSascha Wildner json_isxdigit(unsigned char uc)
1056fca56fbSSascha Wildner {
1066fca56fbSSascha Wildner if (json_isdigit(uc))
1076fca56fbSSascha Wildner return 1;
1086fca56fbSSascha Wildner switch (uc) {
1096fca56fbSSascha Wildner case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
1106fca56fbSSascha Wildner case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
1116fca56fbSSascha Wildner return 1;
1126fca56fbSSascha Wildner default:
1136fca56fbSSascha Wildner return 0;
1146fca56fbSSascha Wildner }
1156fca56fbSSascha Wildner }
1166fca56fbSSascha Wildner
1176fca56fbSSascha Wildner static const unsigned char *
json_skip_space(const unsigned char * uc,const unsigned char * ue)1186fca56fbSSascha Wildner json_skip_space(const unsigned char *uc, const unsigned char *ue)
1196fca56fbSSascha Wildner {
1206fca56fbSSascha Wildner while (uc < ue && json_isspace(*uc))
1216fca56fbSSascha Wildner uc++;
1226fca56fbSSascha Wildner return uc;
1236fca56fbSSascha Wildner }
1246fca56fbSSascha Wildner
125*3b9cdfa3SAntonio Huete Jimenez /*ARGSUSED*/
1266fca56fbSSascha Wildner static int
json_parse_string(const unsigned char ** ucp,const unsigned char * ue,size_t lvl __file_debugused)127*3b9cdfa3SAntonio Huete Jimenez json_parse_string(const unsigned char **ucp, const unsigned char *ue,
128*3b9cdfa3SAntonio Huete Jimenez size_t lvl __file_debugused)
1296fca56fbSSascha Wildner {
1306fca56fbSSascha Wildner const unsigned char *uc = *ucp;
1316fca56fbSSascha Wildner size_t i;
1326fca56fbSSascha Wildner
1336fca56fbSSascha Wildner DPRINTF("Parse string: ", uc, *ucp);
1346fca56fbSSascha Wildner while (uc < ue) {
1356fca56fbSSascha Wildner switch (*uc++) {
1366fca56fbSSascha Wildner case '\0':
1376fca56fbSSascha Wildner goto out;
1386fca56fbSSascha Wildner case '\\':
1396fca56fbSSascha Wildner if (uc == ue)
1406fca56fbSSascha Wildner goto out;
1416fca56fbSSascha Wildner switch (*uc++) {
1426fca56fbSSascha Wildner case '\0':
1436fca56fbSSascha Wildner goto out;
1446fca56fbSSascha Wildner case '"':
1456fca56fbSSascha Wildner case '\\':
1466fca56fbSSascha Wildner case '/':
1476fca56fbSSascha Wildner case 'b':
1486fca56fbSSascha Wildner case 'f':
1496fca56fbSSascha Wildner case 'n':
1506fca56fbSSascha Wildner case 'r':
1516fca56fbSSascha Wildner case 't':
1526fca56fbSSascha Wildner continue;
1536fca56fbSSascha Wildner case 'u':
1546fca56fbSSascha Wildner if (ue - uc < 4) {
1556fca56fbSSascha Wildner uc = ue;
1566fca56fbSSascha Wildner goto out;
1576fca56fbSSascha Wildner }
1586fca56fbSSascha Wildner for (i = 0; i < 4; i++)
1596fca56fbSSascha Wildner if (!json_isxdigit(*uc++))
1606fca56fbSSascha Wildner goto out;
1616fca56fbSSascha Wildner continue;
1626fca56fbSSascha Wildner default:
1636fca56fbSSascha Wildner goto out;
1646fca56fbSSascha Wildner }
1656fca56fbSSascha Wildner case '"':
166c990e5baSDaniel Fojt DPRINTF("Good string: ", uc, *ucp);
167*3b9cdfa3SAntonio Huete Jimenez *ucp = uc;
1686fca56fbSSascha Wildner return 1;
1696fca56fbSSascha Wildner default:
1706fca56fbSSascha Wildner continue;
1716fca56fbSSascha Wildner }
1726fca56fbSSascha Wildner }
1736fca56fbSSascha Wildner out:
1746fca56fbSSascha Wildner DPRINTF("Bad string: ", uc, *ucp);
1756fca56fbSSascha Wildner *ucp = uc;
1766fca56fbSSascha Wildner return 0;
1776fca56fbSSascha Wildner }
1786fca56fbSSascha Wildner
1796fca56fbSSascha Wildner static int
json_parse_array(const unsigned char ** ucp,const unsigned char * ue,size_t * st,size_t lvl)1806fca56fbSSascha Wildner json_parse_array(const unsigned char **ucp, const unsigned char *ue,
1816fca56fbSSascha Wildner size_t *st, size_t lvl)
1826fca56fbSSascha Wildner {
1836fca56fbSSascha Wildner const unsigned char *uc = *ucp;
1846fca56fbSSascha Wildner
1856fca56fbSSascha Wildner DPRINTF("Parse array: ", uc, *ucp);
1866fca56fbSSascha Wildner while (uc < ue) {
187*3b9cdfa3SAntonio Huete Jimenez uc = json_skip_space(uc, ue);
188*3b9cdfa3SAntonio Huete Jimenez if (uc == ue)
189*3b9cdfa3SAntonio Huete Jimenez goto out;
190c990e5baSDaniel Fojt if (*uc == ']')
191c990e5baSDaniel Fojt goto done;
1926fca56fbSSascha Wildner if (!json_parse(&uc, ue, st, lvl + 1))
1936fca56fbSSascha Wildner goto out;
1946fca56fbSSascha Wildner if (uc == ue)
1956fca56fbSSascha Wildner goto out;
1966fca56fbSSascha Wildner switch (*uc) {
1976fca56fbSSascha Wildner case ',':
1986fca56fbSSascha Wildner uc++;
1996fca56fbSSascha Wildner continue;
2006fca56fbSSascha Wildner case ']':
201c990e5baSDaniel Fojt done:
2026fca56fbSSascha Wildner st[JSON_ARRAYN]++;
203c990e5baSDaniel Fojt DPRINTF("Good array: ", uc, *ucp);
204*3b9cdfa3SAntonio Huete Jimenez *ucp = uc + 1;
2056fca56fbSSascha Wildner return 1;
2066fca56fbSSascha Wildner default:
2076fca56fbSSascha Wildner goto out;
2086fca56fbSSascha Wildner }
2096fca56fbSSascha Wildner }
2106fca56fbSSascha Wildner out:
2116fca56fbSSascha Wildner DPRINTF("Bad array: ", uc, *ucp);
2126fca56fbSSascha Wildner *ucp = uc;
2136fca56fbSSascha Wildner return 0;
2146fca56fbSSascha Wildner }
2156fca56fbSSascha Wildner
2166fca56fbSSascha Wildner static int
json_parse_object(const unsigned char ** ucp,const unsigned char * ue,size_t * st,size_t lvl)2176fca56fbSSascha Wildner json_parse_object(const unsigned char **ucp, const unsigned char *ue,
2186fca56fbSSascha Wildner size_t *st, size_t lvl)
2196fca56fbSSascha Wildner {
2206fca56fbSSascha Wildner const unsigned char *uc = *ucp;
2216fca56fbSSascha Wildner DPRINTF("Parse object: ", uc, *ucp);
2226fca56fbSSascha Wildner while (uc < ue) {
2236fca56fbSSascha Wildner uc = json_skip_space(uc, ue);
2246fca56fbSSascha Wildner if (uc == ue)
2256fca56fbSSascha Wildner goto out;
226c990e5baSDaniel Fojt if (*uc == '}') {
227c990e5baSDaniel Fojt uc++;
228c990e5baSDaniel Fojt goto done;
229c990e5baSDaniel Fojt }
2306fca56fbSSascha Wildner if (*uc++ != '"') {
2316fca56fbSSascha Wildner DPRINTF("not string", uc, *ucp);
2326fca56fbSSascha Wildner goto out;
2336fca56fbSSascha Wildner }
2346fca56fbSSascha Wildner DPRINTF("next field", uc, *ucp);
235*3b9cdfa3SAntonio Huete Jimenez if (!json_parse_string(&uc, ue, lvl)) {
2366fca56fbSSascha Wildner DPRINTF("not string", uc, *ucp);
2376fca56fbSSascha Wildner goto out;
2386fca56fbSSascha Wildner }
2396fca56fbSSascha Wildner uc = json_skip_space(uc, ue);
2406fca56fbSSascha Wildner if (uc == ue)
2416fca56fbSSascha Wildner goto out;
2426fca56fbSSascha Wildner if (*uc++ != ':') {
2436fca56fbSSascha Wildner DPRINTF("not colon", uc, *ucp);
2446fca56fbSSascha Wildner goto out;
2456fca56fbSSascha Wildner }
2466fca56fbSSascha Wildner if (!json_parse(&uc, ue, st, lvl + 1)) {
2476fca56fbSSascha Wildner DPRINTF("not json", uc, *ucp);
2486fca56fbSSascha Wildner goto out;
2496fca56fbSSascha Wildner }
2506fca56fbSSascha Wildner if (uc == ue)
2516fca56fbSSascha Wildner goto out;
2526fca56fbSSascha Wildner switch (*uc++) {
2536fca56fbSSascha Wildner case ',':
2546fca56fbSSascha Wildner continue;
2556fca56fbSSascha Wildner case '}': /* { */
256c990e5baSDaniel Fojt done:
2576fca56fbSSascha Wildner DPRINTF("Good object: ", uc, *ucp);
258*3b9cdfa3SAntonio Huete Jimenez *ucp = uc;
2596fca56fbSSascha Wildner return 1;
2606fca56fbSSascha Wildner default:
2616fca56fbSSascha Wildner DPRINTF("not more", uc, *ucp);
262*3b9cdfa3SAntonio Huete Jimenez *ucp = uc - 1;
2636fca56fbSSascha Wildner goto out;
2646fca56fbSSascha Wildner }
2656fca56fbSSascha Wildner }
2666fca56fbSSascha Wildner out:
2676fca56fbSSascha Wildner DPRINTF("Bad object: ", uc, *ucp);
2686fca56fbSSascha Wildner *ucp = uc;
2696fca56fbSSascha Wildner return 0;
2706fca56fbSSascha Wildner }
2716fca56fbSSascha Wildner
272*3b9cdfa3SAntonio Huete Jimenez /*ARGSUSED*/
2736fca56fbSSascha Wildner static int
json_parse_number(const unsigned char ** ucp,const unsigned char * ue,size_t lvl __file_debugused)274*3b9cdfa3SAntonio Huete Jimenez json_parse_number(const unsigned char **ucp, const unsigned char *ue,
275*3b9cdfa3SAntonio Huete Jimenez size_t lvl __file_debugused)
2766fca56fbSSascha Wildner {
2776fca56fbSSascha Wildner const unsigned char *uc = *ucp;
2786fca56fbSSascha Wildner int got = 0;
2796fca56fbSSascha Wildner
2806fca56fbSSascha Wildner DPRINTF("Parse number: ", uc, *ucp);
2816fca56fbSSascha Wildner if (uc == ue)
2826fca56fbSSascha Wildner return 0;
2836fca56fbSSascha Wildner if (*uc == '-')
2846fca56fbSSascha Wildner uc++;
2856fca56fbSSascha Wildner
2866fca56fbSSascha Wildner for (; uc < ue; uc++) {
2876fca56fbSSascha Wildner if (!json_isdigit(*uc))
2886fca56fbSSascha Wildner break;
2896fca56fbSSascha Wildner got = 1;
2906fca56fbSSascha Wildner }
2916fca56fbSSascha Wildner if (uc == ue)
2926fca56fbSSascha Wildner goto out;
2936fca56fbSSascha Wildner if (*uc == '.')
2946fca56fbSSascha Wildner uc++;
2956fca56fbSSascha Wildner for (; uc < ue; uc++) {
2966fca56fbSSascha Wildner if (!json_isdigit(*uc))
2976fca56fbSSascha Wildner break;
2986fca56fbSSascha Wildner got = 1;
2996fca56fbSSascha Wildner }
3006fca56fbSSascha Wildner if (uc == ue)
3016fca56fbSSascha Wildner goto out;
3026fca56fbSSascha Wildner if (got && (*uc == 'e' || *uc == 'E')) {
3036fca56fbSSascha Wildner uc++;
3046fca56fbSSascha Wildner got = 0;
3056fca56fbSSascha Wildner if (uc == ue)
3066fca56fbSSascha Wildner goto out;
3076fca56fbSSascha Wildner if (*uc == '+' || *uc == '-')
3086fca56fbSSascha Wildner uc++;
3096fca56fbSSascha Wildner for (; uc < ue; uc++) {
3106fca56fbSSascha Wildner if (!json_isdigit(*uc))
3116fca56fbSSascha Wildner break;
3126fca56fbSSascha Wildner got = 1;
3136fca56fbSSascha Wildner }
3146fca56fbSSascha Wildner }
3156fca56fbSSascha Wildner out:
3166fca56fbSSascha Wildner if (!got)
3176fca56fbSSascha Wildner DPRINTF("Bad number: ", uc, *ucp);
3186fca56fbSSascha Wildner else
3196fca56fbSSascha Wildner DPRINTF("Good number: ", uc, *ucp);
3206fca56fbSSascha Wildner *ucp = uc;
3216fca56fbSSascha Wildner return got;
3226fca56fbSSascha Wildner }
3236fca56fbSSascha Wildner
324*3b9cdfa3SAntonio Huete Jimenez /*ARGSUSED*/
3256fca56fbSSascha Wildner static int
json_parse_const(const unsigned char ** ucp,const unsigned char * ue,const char * str,size_t len,size_t lvl __file_debugused)3266fca56fbSSascha Wildner json_parse_const(const unsigned char **ucp, const unsigned char *ue,
327*3b9cdfa3SAntonio Huete Jimenez const char *str, size_t len, size_t lvl __file_debugused)
3286fca56fbSSascha Wildner {
3296fca56fbSSascha Wildner const unsigned char *uc = *ucp;
3306fca56fbSSascha Wildner
3316fca56fbSSascha Wildner DPRINTF("Parse const: ", uc, *ucp);
332*3b9cdfa3SAntonio Huete Jimenez *ucp += --len - 1;
333*3b9cdfa3SAntonio Huete Jimenez if (*ucp > ue)
334*3b9cdfa3SAntonio Huete Jimenez *ucp = ue;
335*3b9cdfa3SAntonio Huete Jimenez for (; uc < ue && --len;) {
336*3b9cdfa3SAntonio Huete Jimenez if (*uc++ != *++str) {
3376fca56fbSSascha Wildner DPRINTF("Bad const: ", uc, *ucp);
338*3b9cdfa3SAntonio Huete Jimenez return 0;
339*3b9cdfa3SAntonio Huete Jimenez }
340*3b9cdfa3SAntonio Huete Jimenez }
341*3b9cdfa3SAntonio Huete Jimenez DPRINTF("Good const: ", uc, *ucp);
342*3b9cdfa3SAntonio Huete Jimenez return 1;
3436fca56fbSSascha Wildner }
3446fca56fbSSascha Wildner
3456fca56fbSSascha Wildner static int
json_parse(const unsigned char ** ucp,const unsigned char * ue,size_t * st,size_t lvl)3466fca56fbSSascha Wildner json_parse(const unsigned char **ucp, const unsigned char *ue,
3476fca56fbSSascha Wildner size_t *st, size_t lvl)
3486fca56fbSSascha Wildner {
349*3b9cdfa3SAntonio Huete Jimenez const unsigned char *uc, *ouc;
3506fca56fbSSascha Wildner int rv = 0;
3516fca56fbSSascha Wildner int t;
3526fca56fbSSascha Wildner
353*3b9cdfa3SAntonio Huete Jimenez ouc = uc = json_skip_space(*ucp, ue);
3546fca56fbSSascha Wildner if (uc == ue)
3556fca56fbSSascha Wildner goto out;
3566fca56fbSSascha Wildner
3576fca56fbSSascha Wildner // Avoid recursion
358*3b9cdfa3SAntonio Huete Jimenez if (lvl > 500) {
359*3b9cdfa3SAntonio Huete Jimenez DPRINTF("Too many levels", uc, *ucp);
3606fca56fbSSascha Wildner return 0;
361*3b9cdfa3SAntonio Huete Jimenez }
3626fca56fbSSascha Wildner #if JSON_COUNT
3636fca56fbSSascha Wildner /* bail quickly if not counting */
3646fca56fbSSascha Wildner if (lvl > 1 && (st[JSON_OBJECT] || st[JSON_ARRAYN]))
3656fca56fbSSascha Wildner return 1;
3666fca56fbSSascha Wildner #endif
3676fca56fbSSascha Wildner
3686fca56fbSSascha Wildner DPRINTF("Parse general: ", uc, *ucp);
3696fca56fbSSascha Wildner switch (*uc++) {
3706fca56fbSSascha Wildner case '"':
371*3b9cdfa3SAntonio Huete Jimenez rv = json_parse_string(&uc, ue, lvl + 1);
3726fca56fbSSascha Wildner t = JSON_STRING;
3736fca56fbSSascha Wildner break;
3746fca56fbSSascha Wildner case '[':
3756fca56fbSSascha Wildner rv = json_parse_array(&uc, ue, st, lvl + 1);
3766fca56fbSSascha Wildner t = JSON_ARRAY;
3776fca56fbSSascha Wildner break;
3786fca56fbSSascha Wildner case '{': /* '}' */
3796fca56fbSSascha Wildner rv = json_parse_object(&uc, ue, st, lvl + 1);
3806fca56fbSSascha Wildner t = JSON_OBJECT;
3816fca56fbSSascha Wildner break;
3826fca56fbSSascha Wildner case 't':
383*3b9cdfa3SAntonio Huete Jimenez rv = json_parse_const(&uc, ue, "true", sizeof("true"), lvl + 1);
3846fca56fbSSascha Wildner t = JSON_CONSTANT;
3856fca56fbSSascha Wildner break;
3866fca56fbSSascha Wildner case 'f':
387*3b9cdfa3SAntonio Huete Jimenez rv = json_parse_const(&uc, ue, "false", sizeof("false"),
388*3b9cdfa3SAntonio Huete Jimenez lvl + 1);
3896fca56fbSSascha Wildner t = JSON_CONSTANT;
3906fca56fbSSascha Wildner break;
3916fca56fbSSascha Wildner case 'n':
392*3b9cdfa3SAntonio Huete Jimenez rv = json_parse_const(&uc, ue, "null", sizeof("null"), lvl + 1);
3936fca56fbSSascha Wildner t = JSON_CONSTANT;
3946fca56fbSSascha Wildner break;
3956fca56fbSSascha Wildner default:
3966fca56fbSSascha Wildner --uc;
397*3b9cdfa3SAntonio Huete Jimenez rv = json_parse_number(&uc, ue, lvl + 1);
3986fca56fbSSascha Wildner t = JSON_NUMBER;
3996fca56fbSSascha Wildner break;
4006fca56fbSSascha Wildner }
4016fca56fbSSascha Wildner if (rv)
4026fca56fbSSascha Wildner st[t]++;
4036fca56fbSSascha Wildner uc = json_skip_space(uc, ue);
4046fca56fbSSascha Wildner out:
4056fca56fbSSascha Wildner DPRINTF("End general: ", uc, *ucp);
406*3b9cdfa3SAntonio Huete Jimenez *ucp = uc;
407*3b9cdfa3SAntonio Huete Jimenez if (lvl == 0) {
408*3b9cdfa3SAntonio Huete Jimenez if (!rv)
409*3b9cdfa3SAntonio Huete Jimenez return 0;
410*3b9cdfa3SAntonio Huete Jimenez if (uc == ue)
411*3b9cdfa3SAntonio Huete Jimenez return (st[JSON_ARRAYN] || st[JSON_OBJECT]) ? 1 : 0;
412*3b9cdfa3SAntonio Huete Jimenez if (*ouc == *uc && json_parse(&uc, ue, st, 1))
413*3b9cdfa3SAntonio Huete Jimenez return (st[JSON_ARRAYN] || st[JSON_OBJECT]) ? 2 : 0;
414*3b9cdfa3SAntonio Huete Jimenez else
415*3b9cdfa3SAntonio Huete Jimenez return 0;
416*3b9cdfa3SAntonio Huete Jimenez }
4176fca56fbSSascha Wildner return rv;
4186fca56fbSSascha Wildner }
4196fca56fbSSascha Wildner
4206fca56fbSSascha Wildner #ifndef TEST
4216fca56fbSSascha Wildner int
file_is_json(struct magic_set * ms,const struct buffer * b)4226fca56fbSSascha Wildner file_is_json(struct magic_set *ms, const struct buffer *b)
4236fca56fbSSascha Wildner {
4246fca56fbSSascha Wildner const unsigned char *uc = CAST(const unsigned char *, b->fbuf);
4256fca56fbSSascha Wildner const unsigned char *ue = uc + b->flen;
4266fca56fbSSascha Wildner size_t st[JSON_MAX];
4276fca56fbSSascha Wildner int mime = ms->flags & MAGIC_MIME;
428*3b9cdfa3SAntonio Huete Jimenez int jt;
4296fca56fbSSascha Wildner
4306fca56fbSSascha Wildner
4316fca56fbSSascha Wildner if ((ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION)) != 0)
4326fca56fbSSascha Wildner return 0;
4336fca56fbSSascha Wildner
4346fca56fbSSascha Wildner memset(st, 0, sizeof(st));
4356fca56fbSSascha Wildner
436*3b9cdfa3SAntonio Huete Jimenez if ((jt = json_parse(&uc, ue, st, 0)) == 0)
4376fca56fbSSascha Wildner return 0;
4386fca56fbSSascha Wildner
4396fca56fbSSascha Wildner if (mime == MAGIC_MIME_ENCODING)
4406fca56fbSSascha Wildner return 1;
4416fca56fbSSascha Wildner if (mime) {
442*3b9cdfa3SAntonio Huete Jimenez if (file_printf(ms, "application/%s",
443*3b9cdfa3SAntonio Huete Jimenez jt == 1 ? "json" : "x-ndjason") == -1)
4446fca56fbSSascha Wildner return -1;
4456fca56fbSSascha Wildner return 1;
4466fca56fbSSascha Wildner }
447*3b9cdfa3SAntonio Huete Jimenez if (file_printf(ms, "%sJSON text data",
448*3b9cdfa3SAntonio Huete Jimenez jt == 1 ? "" : "New Line Delimited ") == -1)
4496fca56fbSSascha Wildner return -1;
4506fca56fbSSascha Wildner #if JSON_COUNT
4516fca56fbSSascha Wildner #define P(n) st[n], st[n] > 1 ? "s" : ""
4526fca56fbSSascha Wildner if (file_printf(ms, " (%" SIZE_T_FORMAT "u object%s, %" SIZE_T_FORMAT
4536fca56fbSSascha Wildner "u array%s, %" SIZE_T_FORMAT "u string%s, %" SIZE_T_FORMAT
4546fca56fbSSascha Wildner "u constant%s, %" SIZE_T_FORMAT "u number%s, %" SIZE_T_FORMAT
4556fca56fbSSascha Wildner "u >1array%s)",
4566fca56fbSSascha Wildner P(JSON_OBJECT), P(JSON_ARRAY), P(JSON_STRING), P(JSON_CONSTANT),
4576fca56fbSSascha Wildner P(JSON_NUMBER), P(JSON_ARRAYN))
4586fca56fbSSascha Wildner == -1)
4596fca56fbSSascha Wildner return -1;
4606fca56fbSSascha Wildner #endif
4616fca56fbSSascha Wildner return 1;
4626fca56fbSSascha Wildner }
4636fca56fbSSascha Wildner
4646fca56fbSSascha Wildner #else
4656fca56fbSSascha Wildner
4666fca56fbSSascha Wildner #include <sys/types.h>
4676fca56fbSSascha Wildner #include <sys/stat.h>
4686fca56fbSSascha Wildner #include <stdio.h>
4696fca56fbSSascha Wildner #include <fcntl.h>
4706fca56fbSSascha Wildner #include <unistd.h>
4716fca56fbSSascha Wildner #include <stdlib.h>
4726fca56fbSSascha Wildner #include <stdint.h>
4736fca56fbSSascha Wildner #include <err.h>
4746fca56fbSSascha Wildner
4756fca56fbSSascha Wildner int
main(int argc,char * argv[])4766fca56fbSSascha Wildner main(int argc, char *argv[])
4776fca56fbSSascha Wildner {
4786fca56fbSSascha Wildner int fd, rv;
4796fca56fbSSascha Wildner struct stat st;
4806fca56fbSSascha Wildner unsigned char *p;
4816fca56fbSSascha Wildner size_t stats[JSON_MAX];
4826fca56fbSSascha Wildner
4836fca56fbSSascha Wildner if ((fd = open(argv[1], O_RDONLY)) == -1)
4846fca56fbSSascha Wildner err(EXIT_FAILURE, "Can't open `%s'", argv[1]);
4856fca56fbSSascha Wildner
4866fca56fbSSascha Wildner if (fstat(fd, &st) == -1)
4876fca56fbSSascha Wildner err(EXIT_FAILURE, "Can't stat `%s'", argv[1]);
4886fca56fbSSascha Wildner
489*3b9cdfa3SAntonio Huete Jimenez if ((p = CAST(char *, malloc(st.st_size))) == NULL)
4906fca56fbSSascha Wildner err(EXIT_FAILURE, "Can't allocate %jd bytes",
4916fca56fbSSascha Wildner (intmax_t)st.st_size);
4926fca56fbSSascha Wildner if (read(fd, p, st.st_size) != st.st_size)
4936fca56fbSSascha Wildner err(EXIT_FAILURE, "Can't read %jd bytes",
4946fca56fbSSascha Wildner (intmax_t)st.st_size);
4956fca56fbSSascha Wildner memset(stats, 0, sizeof(stats));
4966fca56fbSSascha Wildner printf("is json %d\n", json_parse((const unsigned char **)&p,
4976fca56fbSSascha Wildner p + st.st_size, stats, 0));
4986fca56fbSSascha Wildner return 0;
4996fca56fbSSascha Wildner }
5006fca56fbSSascha Wildner #endif
501