xref: /dflybsd-src/contrib/file/src/is_json.c (revision 739f0ef867128a933e021db3d831e906fcafd825)
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