xref: /freebsd-src/contrib/file/src/is_json.c (revision a4d6d3b8910f3805eebcd8703e11e066aad2e2a1)
148c779cdSXin LI /*-
248c779cdSXin LI  * Copyright (c) 2018 Christos Zoulas
348c779cdSXin LI  * All rights reserved.
448c779cdSXin LI  *
548c779cdSXin LI  * Redistribution and use in source and binary forms, with or without
648c779cdSXin LI  * modification, are permitted provided that the following conditions
748c779cdSXin LI  * are met:
848c779cdSXin LI  * 1. Redistributions of source code must retain the above copyright
948c779cdSXin LI  *    notice, this list of conditions and the following disclaimer.
1048c779cdSXin LI  * 2. Redistributions in binary form must reproduce the above copyright
1148c779cdSXin LI  *    notice, this list of conditions and the following disclaimer in the
1248c779cdSXin LI  *    documentation and/or other materials provided with the distribution.
1348c779cdSXin LI  *
1448c779cdSXin LI  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1548c779cdSXin LI  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1648c779cdSXin LI  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1748c779cdSXin LI  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
1848c779cdSXin LI  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1948c779cdSXin LI  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2048c779cdSXin LI  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2148c779cdSXin LI  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2248c779cdSXin LI  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2348c779cdSXin LI  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2448c779cdSXin LI  * POSSIBILITY OF SUCH DAMAGE.
2548c779cdSXin LI  */
2648c779cdSXin LI 
2748c779cdSXin LI /*
2848c779cdSXin LI  * Parse JSON object serialization format (RFC-7159)
2948c779cdSXin LI  */
3048c779cdSXin LI 
3148c779cdSXin LI #ifndef TEST
3248c779cdSXin LI #include "file.h"
3348c779cdSXin LI 
3448c779cdSXin LI #ifndef lint
35*a4d6d3b8SXin LI FILE_RCSID("@(#)$File: is_json.c,v 1.20 2022/05/28 00:44:22 christos Exp $")
3648c779cdSXin LI #endif
3748c779cdSXin LI 
3848c779cdSXin LI #include "magic.h"
39*a4d6d3b8SXin LI #else
40*a4d6d3b8SXin LI #include <stdio.h>
41*a4d6d3b8SXin LI #include <stddef.h>
4248c779cdSXin LI #endif
43*a4d6d3b8SXin LI #include <string.h>
4448c779cdSXin LI 
4548c779cdSXin LI #ifdef DEBUG
4648c779cdSXin LI #include <stdio.h>
4748c779cdSXin LI #define DPRINTF(a, b, c)	\
48*a4d6d3b8SXin LI     printf("%*s%s [%.2x/%c] %.*s\n", (int)lvl, "", (a), *(b), *(b), \
49*a4d6d3b8SXin LI 	(int)(b - c), (const char *)(c))
50*a4d6d3b8SXin LI #define __file_debugused
5148c779cdSXin LI #else
5248c779cdSXin LI #define DPRINTF(a, b, c)	do { } while (/*CONSTCOND*/0)
53*a4d6d3b8SXin LI #define __file_debugused __attribute__((__unused__))
5448c779cdSXin LI #endif
5548c779cdSXin LI 
5648c779cdSXin LI #define JSON_ARRAY	0
5748c779cdSXin LI #define JSON_CONSTANT	1
5848c779cdSXin LI #define JSON_NUMBER	2
5948c779cdSXin LI #define JSON_OBJECT	3
6048c779cdSXin LI #define JSON_STRING	4
6148c779cdSXin LI #define JSON_ARRAYN	5
6248c779cdSXin LI #define JSON_MAX	6
6348c779cdSXin LI 
6448c779cdSXin LI /*
6548c779cdSXin LI  * if JSON_COUNT != 0:
6648c779cdSXin LI  *	count all the objects, require that we have the whole data file
6748c779cdSXin LI  * otherwise:
6848c779cdSXin LI  *	stop if we find an object or an array
6948c779cdSXin LI  */
7048c779cdSXin LI #ifndef JSON_COUNT
7148c779cdSXin LI #define JSON_COUNT 0
7248c779cdSXin LI #endif
7348c779cdSXin LI 
7448c779cdSXin LI static int json_parse(const unsigned char **, const unsigned char *, size_t *,
7548c779cdSXin LI 	size_t);
7648c779cdSXin LI 
7748c779cdSXin LI static int
7848c779cdSXin LI json_isspace(const unsigned char uc)
7948c779cdSXin LI {
8048c779cdSXin LI 	switch (uc) {
8148c779cdSXin LI 	case ' ':
8248c779cdSXin LI 	case '\n':
8348c779cdSXin LI 	case '\r':
8448c779cdSXin LI 	case '\t':
8548c779cdSXin LI 		return 1;
8648c779cdSXin LI 	default:
8748c779cdSXin LI 		return 0;
8848c779cdSXin LI 	}
8948c779cdSXin LI }
9048c779cdSXin LI 
9148c779cdSXin LI static int
9248c779cdSXin LI json_isdigit(unsigned char uc)
9348c779cdSXin LI {
9448c779cdSXin LI 	switch (uc) {
9548c779cdSXin LI 	case '0': case '1': case '2': case '3': case '4':
9648c779cdSXin LI 	case '5': case '6': case '7': case '8': case '9':
9748c779cdSXin LI 		return 1;
9848c779cdSXin LI 	default:
9948c779cdSXin LI 		return 0;
10048c779cdSXin LI 	}
10148c779cdSXin LI }
10248c779cdSXin LI 
10348c779cdSXin LI static int
10448c779cdSXin LI json_isxdigit(unsigned char uc)
10548c779cdSXin LI {
10648c779cdSXin LI 	if (json_isdigit(uc))
10748c779cdSXin LI 		return 1;
10848c779cdSXin LI 	switch (uc) {
10948c779cdSXin LI 	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
11048c779cdSXin LI 	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
11148c779cdSXin LI 		return 1;
11248c779cdSXin LI 	default:
11348c779cdSXin LI 		return 0;
11448c779cdSXin LI 	}
11548c779cdSXin LI }
11648c779cdSXin LI 
11748c779cdSXin LI static const unsigned char *
11848c779cdSXin LI json_skip_space(const unsigned char *uc, const unsigned char *ue)
11948c779cdSXin LI {
12048c779cdSXin LI 	while (uc < ue && json_isspace(*uc))
12148c779cdSXin LI 		uc++;
12248c779cdSXin LI 	return uc;
12348c779cdSXin LI }
12448c779cdSXin LI 
12548c779cdSXin LI static int
126*a4d6d3b8SXin LI json_parse_string(const unsigned char **ucp, const unsigned char *ue,
127*a4d6d3b8SXin LI     size_t lvl __file_debugused)
12848c779cdSXin LI {
12948c779cdSXin LI 	const unsigned char *uc = *ucp;
13048c779cdSXin LI 	size_t i;
13148c779cdSXin LI 
13248c779cdSXin LI 	DPRINTF("Parse string: ", uc, *ucp);
13348c779cdSXin LI 	while (uc < ue) {
13448c779cdSXin LI 		switch (*uc++) {
13548c779cdSXin LI 		case '\0':
13648c779cdSXin LI 			goto out;
13748c779cdSXin LI 		case '\\':
13848c779cdSXin LI 			if (uc == ue)
13948c779cdSXin LI 				goto out;
14048c779cdSXin LI 			switch (*uc++) {
14148c779cdSXin LI 			case '\0':
14248c779cdSXin LI 				goto out;
14348c779cdSXin LI 			case '"':
14448c779cdSXin LI 			case '\\':
14548c779cdSXin LI 			case '/':
14648c779cdSXin LI 			case 'b':
14748c779cdSXin LI 			case 'f':
14848c779cdSXin LI 			case 'n':
14948c779cdSXin LI 			case 'r':
15048c779cdSXin LI 			case 't':
15148c779cdSXin LI 				continue;
15248c779cdSXin LI 			case 'u':
15348c779cdSXin LI 				if (ue - uc < 4) {
15448c779cdSXin LI 					uc = ue;
15548c779cdSXin LI 					goto out;
15648c779cdSXin LI 				}
15748c779cdSXin LI 				for (i = 0; i < 4; i++)
15848c779cdSXin LI 					if (!json_isxdigit(*uc++))
15948c779cdSXin LI 						goto out;
16048c779cdSXin LI 				continue;
16148c779cdSXin LI 			default:
16248c779cdSXin LI 				goto out;
16348c779cdSXin LI 			}
16448c779cdSXin LI 		case '"':
1652726a701SXin LI 			DPRINTF("Good string: ", uc, *ucp);
166*a4d6d3b8SXin LI 			*ucp = uc;
16748c779cdSXin LI 			return 1;
16848c779cdSXin LI 		default:
16948c779cdSXin LI 			continue;
17048c779cdSXin LI 		}
17148c779cdSXin LI 	}
17248c779cdSXin LI out:
17348c779cdSXin LI 	DPRINTF("Bad string: ", uc, *ucp);
17448c779cdSXin LI 	*ucp = uc;
17548c779cdSXin LI 	return 0;
17648c779cdSXin LI }
17748c779cdSXin LI 
17848c779cdSXin LI static int
17948c779cdSXin LI json_parse_array(const unsigned char **ucp, const unsigned char *ue,
18048c779cdSXin LI 	size_t *st, size_t lvl)
18148c779cdSXin LI {
18248c779cdSXin LI 	const unsigned char *uc = *ucp;
18348c779cdSXin LI 
18448c779cdSXin LI 	DPRINTF("Parse array: ", uc, *ucp);
18548c779cdSXin LI 	while (uc < ue) {
1862726a701SXin LI 		if (*uc == ']')
1872726a701SXin LI 			goto done;
18848c779cdSXin LI 		if (!json_parse(&uc, ue, st, lvl + 1))
18948c779cdSXin LI 			goto out;
19048c779cdSXin LI 		if (uc == ue)
19148c779cdSXin LI 			goto out;
19248c779cdSXin LI 		switch (*uc) {
19348c779cdSXin LI 		case ',':
19448c779cdSXin LI 			uc++;
19548c779cdSXin LI 			continue;
19648c779cdSXin LI 		case ']':
1972726a701SXin LI 		done:
19848c779cdSXin LI 			st[JSON_ARRAYN]++;
1992726a701SXin LI 			DPRINTF("Good array: ", uc, *ucp);
200*a4d6d3b8SXin LI 			*ucp = uc + 1;
20148c779cdSXin LI 			return 1;
20248c779cdSXin LI 		default:
20348c779cdSXin LI 			goto out;
20448c779cdSXin LI 		}
20548c779cdSXin LI 	}
20648c779cdSXin LI out:
20748c779cdSXin LI 	DPRINTF("Bad array: ", uc,  *ucp);
20848c779cdSXin LI 	*ucp = uc;
20948c779cdSXin LI 	return 0;
21048c779cdSXin LI }
21148c779cdSXin LI 
21248c779cdSXin LI static int
21348c779cdSXin LI json_parse_object(const unsigned char **ucp, const unsigned char *ue,
21448c779cdSXin LI 	size_t *st, size_t lvl)
21548c779cdSXin LI {
21648c779cdSXin LI 	const unsigned char *uc = *ucp;
21748c779cdSXin LI 	DPRINTF("Parse object: ", uc, *ucp);
21848c779cdSXin LI 	while (uc < ue) {
21948c779cdSXin LI 		uc = json_skip_space(uc, ue);
22048c779cdSXin LI 		if (uc == ue)
22148c779cdSXin LI 			goto out;
2222726a701SXin LI 		if (*uc == '}') {
2232726a701SXin LI 			uc++;
2242726a701SXin LI 			goto done;
2252726a701SXin LI 		}
22648c779cdSXin LI 		if (*uc++ != '"') {
22748c779cdSXin LI 			DPRINTF("not string", uc, *ucp);
22848c779cdSXin LI 			goto out;
22948c779cdSXin LI 		}
23048c779cdSXin LI 		DPRINTF("next field", uc, *ucp);
231*a4d6d3b8SXin LI 		if (!json_parse_string(&uc, ue, lvl)) {
23248c779cdSXin LI 			DPRINTF("not string", uc, *ucp);
23348c779cdSXin LI 			goto out;
23448c779cdSXin LI 		}
23548c779cdSXin LI 		uc = json_skip_space(uc, ue);
23648c779cdSXin LI 		if (uc == ue)
23748c779cdSXin LI 			goto out;
23848c779cdSXin LI 		if (*uc++ != ':') {
23948c779cdSXin LI 			DPRINTF("not colon", uc, *ucp);
24048c779cdSXin LI 			goto out;
24148c779cdSXin LI 		}
24248c779cdSXin LI 		if (!json_parse(&uc, ue, st, lvl + 1)) {
24348c779cdSXin LI 			DPRINTF("not json", uc, *ucp);
24448c779cdSXin LI 			goto out;
24548c779cdSXin LI 		}
24648c779cdSXin LI 		if (uc == ue)
24748c779cdSXin LI 			goto out;
24848c779cdSXin LI 		switch (*uc++) {
24948c779cdSXin LI 		case ',':
25048c779cdSXin LI 			continue;
25148c779cdSXin LI 		case '}': /* { */
2522726a701SXin LI 		done:
25348c779cdSXin LI 			DPRINTF("Good object: ", uc, *ucp);
254*a4d6d3b8SXin LI 			*ucp = uc;
25548c779cdSXin LI 			return 1;
25648c779cdSXin LI 		default:
25748c779cdSXin LI 			DPRINTF("not more", uc, *ucp);
258*a4d6d3b8SXin LI 			*ucp = uc - 1;
25948c779cdSXin LI 			goto out;
26048c779cdSXin LI 		}
26148c779cdSXin LI 	}
26248c779cdSXin LI out:
26348c779cdSXin LI 	DPRINTF("Bad object: ", uc, *ucp);
26448c779cdSXin LI 	*ucp = uc;
26548c779cdSXin LI 	return 0;
26648c779cdSXin LI }
26748c779cdSXin LI 
26848c779cdSXin LI static int
269*a4d6d3b8SXin LI json_parse_number(const unsigned char **ucp, const unsigned char *ue,
270*a4d6d3b8SXin LI     size_t lvl __file_debugused)
27148c779cdSXin LI {
27248c779cdSXin LI 	const unsigned char *uc = *ucp;
27348c779cdSXin LI 	int got = 0;
27448c779cdSXin LI 
27548c779cdSXin LI 	DPRINTF("Parse number: ", uc, *ucp);
27648c779cdSXin LI 	if (uc == ue)
27748c779cdSXin LI 		return 0;
27848c779cdSXin LI 	if (*uc == '-')
27948c779cdSXin LI 		uc++;
28048c779cdSXin LI 
28148c779cdSXin LI 	for (; uc < ue; uc++) {
28248c779cdSXin LI 		if (!json_isdigit(*uc))
28348c779cdSXin LI 			break;
28448c779cdSXin LI 		got = 1;
28548c779cdSXin LI 	}
28648c779cdSXin LI 	if (uc == ue)
28748c779cdSXin LI 		goto out;
28848c779cdSXin LI 	if (*uc == '.')
28948c779cdSXin LI 		uc++;
29048c779cdSXin LI 	for (; uc < ue; uc++) {
29148c779cdSXin LI 		if (!json_isdigit(*uc))
29248c779cdSXin LI 			break;
29348c779cdSXin LI 		got = 1;
29448c779cdSXin LI 	}
29548c779cdSXin LI 	if (uc == ue)
29648c779cdSXin LI 		goto out;
29748c779cdSXin LI 	if (got && (*uc == 'e' || *uc == 'E')) {
29848c779cdSXin LI 		uc++;
29948c779cdSXin LI 		got = 0;
30048c779cdSXin LI 		if (uc == ue)
30148c779cdSXin LI 			goto out;
30248c779cdSXin LI 		if (*uc == '+' || *uc == '-')
30348c779cdSXin LI 			uc++;
30448c779cdSXin LI 		for (; uc < ue; uc++) {
30548c779cdSXin LI 			if (!json_isdigit(*uc))
30648c779cdSXin LI 				break;
30748c779cdSXin LI 			got = 1;
30848c779cdSXin LI 		}
30948c779cdSXin LI 	}
31048c779cdSXin LI out:
31148c779cdSXin LI 	if (!got)
31248c779cdSXin LI 		DPRINTF("Bad number: ", uc, *ucp);
31348c779cdSXin LI 	else
31448c779cdSXin LI 		DPRINTF("Good number: ", uc, *ucp);
31548c779cdSXin LI 	*ucp = uc;
31648c779cdSXin LI 	return got;
31748c779cdSXin LI }
31848c779cdSXin LI 
31948c779cdSXin LI static int
32048c779cdSXin LI json_parse_const(const unsigned char **ucp, const unsigned char *ue,
321*a4d6d3b8SXin LI     const char *str, size_t len, size_t lvl __file_debugused)
32248c779cdSXin LI {
32348c779cdSXin LI 	const unsigned char *uc = *ucp;
32448c779cdSXin LI 
32548c779cdSXin LI 	DPRINTF("Parse const: ", uc, *ucp);
32648c779cdSXin LI 	for (len--; uc < ue && --len;) {
32748c779cdSXin LI 		if (*uc++ == *++str)
32848c779cdSXin LI 			continue;
32948c779cdSXin LI 	}
33048c779cdSXin LI 	if (len)
33148c779cdSXin LI 		DPRINTF("Bad const: ", uc, *ucp);
33248c779cdSXin LI 	*ucp = uc;
33348c779cdSXin LI 	return len == 0;
33448c779cdSXin LI }
33548c779cdSXin LI 
33648c779cdSXin LI static int
33748c779cdSXin LI json_parse(const unsigned char **ucp, const unsigned char *ue,
33848c779cdSXin LI     size_t *st, size_t lvl)
33948c779cdSXin LI {
34048c779cdSXin LI 	const unsigned char *uc;
34148c779cdSXin LI 	int rv = 0;
34248c779cdSXin LI 	int t;
34348c779cdSXin LI 
34448c779cdSXin LI 	uc = json_skip_space(*ucp, ue);
34548c779cdSXin LI 	if (uc == ue)
34648c779cdSXin LI 		goto out;
34748c779cdSXin LI 
34848c779cdSXin LI 	// Avoid recursion
349*a4d6d3b8SXin LI 	if (lvl > 500) {
350*a4d6d3b8SXin LI 		DPRINTF("Too many levels", uc, *ucp);
35148c779cdSXin LI 		return 0;
352*a4d6d3b8SXin LI 	}
35348c779cdSXin LI #if JSON_COUNT
35448c779cdSXin LI 	/* bail quickly if not counting */
35548c779cdSXin LI 	if (lvl > 1 && (st[JSON_OBJECT] || st[JSON_ARRAYN]))
35648c779cdSXin LI 		return 1;
35748c779cdSXin LI #endif
35848c779cdSXin LI 
35948c779cdSXin LI 	DPRINTF("Parse general: ", uc, *ucp);
36048c779cdSXin LI 	switch (*uc++) {
36148c779cdSXin LI 	case '"':
362*a4d6d3b8SXin LI 		rv = json_parse_string(&uc, ue, lvl + 1);
36348c779cdSXin LI 		t = JSON_STRING;
36448c779cdSXin LI 		break;
36548c779cdSXin LI 	case '[':
36648c779cdSXin LI 		rv = json_parse_array(&uc, ue, st, lvl + 1);
36748c779cdSXin LI 		t = JSON_ARRAY;
36848c779cdSXin LI 		break;
36948c779cdSXin LI 	case '{': /* '}' */
37048c779cdSXin LI 		rv = json_parse_object(&uc, ue, st, lvl + 1);
37148c779cdSXin LI 		t = JSON_OBJECT;
37248c779cdSXin LI 		break;
37348c779cdSXin LI 	case 't':
374*a4d6d3b8SXin LI 		rv = json_parse_const(&uc, ue, "true", sizeof("true"), lvl + 1);
37548c779cdSXin LI 		t = JSON_CONSTANT;
37648c779cdSXin LI 		break;
37748c779cdSXin LI 	case 'f':
378*a4d6d3b8SXin LI 		rv = json_parse_const(&uc, ue, "false", sizeof("false"),
379*a4d6d3b8SXin LI 		    lvl + 1);
38048c779cdSXin LI 		t = JSON_CONSTANT;
38148c779cdSXin LI 		break;
38248c779cdSXin LI 	case 'n':
383*a4d6d3b8SXin LI 		rv = json_parse_const(&uc, ue, "null", sizeof("null"), lvl + 1);
38448c779cdSXin LI 		t = JSON_CONSTANT;
38548c779cdSXin LI 		break;
38648c779cdSXin LI 	default:
38748c779cdSXin LI 		--uc;
388*a4d6d3b8SXin LI 		rv = json_parse_number(&uc, ue, lvl + 1);
38948c779cdSXin LI 		t = JSON_NUMBER;
39048c779cdSXin LI 		break;
39148c779cdSXin LI 	}
39248c779cdSXin LI 	if (rv)
39348c779cdSXin LI 		st[t]++;
39448c779cdSXin LI 	uc = json_skip_space(uc, ue);
39548c779cdSXin LI out:
39648c779cdSXin LI 	DPRINTF("End general: ", uc, *ucp);
397*a4d6d3b8SXin LI 	*ucp = uc;
39848c779cdSXin LI 	if (lvl == 0)
399*a4d6d3b8SXin LI 		return rv && uc == ue && (st[JSON_ARRAYN] || st[JSON_OBJECT]);
40048c779cdSXin LI 	return rv;
40148c779cdSXin LI }
40248c779cdSXin LI 
40348c779cdSXin LI #ifndef TEST
40448c779cdSXin LI int
40548c779cdSXin LI file_is_json(struct magic_set *ms, const struct buffer *b)
40648c779cdSXin LI {
40748c779cdSXin LI 	const unsigned char *uc = CAST(const unsigned char *, b->fbuf);
40848c779cdSXin LI 	const unsigned char *ue = uc + b->flen;
40948c779cdSXin LI 	size_t st[JSON_MAX];
41048c779cdSXin LI 	int mime = ms->flags & MAGIC_MIME;
41148c779cdSXin LI 
41248c779cdSXin LI 
41348c779cdSXin LI 	if ((ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION)) != 0)
41448c779cdSXin LI 		return 0;
41548c779cdSXin LI 
41648c779cdSXin LI 	memset(st, 0, sizeof(st));
41748c779cdSXin LI 
41848c779cdSXin LI 	if (!json_parse(&uc, ue, st, 0))
41948c779cdSXin LI 		return 0;
42048c779cdSXin LI 
42148c779cdSXin LI 	if (mime == MAGIC_MIME_ENCODING)
42248c779cdSXin LI 		return 1;
42348c779cdSXin LI 	if (mime) {
42448c779cdSXin LI 		if (file_printf(ms, "application/json") == -1)
42548c779cdSXin LI 			return -1;
42648c779cdSXin LI 		return 1;
42748c779cdSXin LI 	}
428*a4d6d3b8SXin LI 	if (file_printf(ms, "JSON text data") == -1)
42948c779cdSXin LI 		return -1;
43048c779cdSXin LI #if JSON_COUNT
43148c779cdSXin LI #define P(n) st[n], st[n] > 1 ? "s" : ""
43248c779cdSXin LI 	if (file_printf(ms, " (%" SIZE_T_FORMAT "u object%s, %" SIZE_T_FORMAT
43348c779cdSXin LI 	    "u array%s, %" SIZE_T_FORMAT "u string%s, %" SIZE_T_FORMAT
43448c779cdSXin LI 	    "u constant%s, %" SIZE_T_FORMAT "u number%s, %" SIZE_T_FORMAT
43548c779cdSXin LI 	    "u >1array%s)",
43648c779cdSXin LI 	    P(JSON_OBJECT), P(JSON_ARRAY), P(JSON_STRING), P(JSON_CONSTANT),
43748c779cdSXin LI 	    P(JSON_NUMBER), P(JSON_ARRAYN))
43848c779cdSXin LI 	    == -1)
43948c779cdSXin LI 		return -1;
44048c779cdSXin LI #endif
44148c779cdSXin LI 	return 1;
44248c779cdSXin LI }
44348c779cdSXin LI 
44448c779cdSXin LI #else
44548c779cdSXin LI 
44648c779cdSXin LI #include <sys/types.h>
44748c779cdSXin LI #include <sys/stat.h>
44848c779cdSXin LI #include <stdio.h>
44948c779cdSXin LI #include <fcntl.h>
45048c779cdSXin LI #include <unistd.h>
45148c779cdSXin LI #include <stdlib.h>
45248c779cdSXin LI #include <stdint.h>
45348c779cdSXin LI #include <err.h>
45448c779cdSXin LI 
45548c779cdSXin LI int
45648c779cdSXin LI main(int argc, char *argv[])
45748c779cdSXin LI {
45848c779cdSXin LI 	int fd, rv;
45948c779cdSXin LI 	struct stat st;
46048c779cdSXin LI 	unsigned char *p;
46148c779cdSXin LI 	size_t stats[JSON_MAX];
46248c779cdSXin LI 
46348c779cdSXin LI 	if ((fd = open(argv[1], O_RDONLY)) == -1)
46448c779cdSXin LI 		err(EXIT_FAILURE, "Can't open `%s'", argv[1]);
46548c779cdSXin LI 
46648c779cdSXin LI 	if (fstat(fd, &st) == -1)
46748c779cdSXin LI 		err(EXIT_FAILURE, "Can't stat `%s'", argv[1]);
46848c779cdSXin LI 
469*a4d6d3b8SXin LI 	if ((p = CAST(char *, malloc(st.st_size))) == NULL)
47048c779cdSXin LI 		err(EXIT_FAILURE, "Can't allocate %jd bytes",
47148c779cdSXin LI 		    (intmax_t)st.st_size);
47248c779cdSXin LI 	if (read(fd, p, st.st_size) != st.st_size)
47348c779cdSXin LI 		err(EXIT_FAILURE, "Can't read %jd bytes",
47448c779cdSXin LI 		    (intmax_t)st.st_size);
47548c779cdSXin LI 	memset(stats, 0, sizeof(stats));
47648c779cdSXin LI 	printf("is json %d\n", json_parse((const unsigned char **)&p,
47748c779cdSXin LI 	    p + st.st_size, stats, 0));
47848c779cdSXin LI 	return 0;
47948c779cdSXin LI }
48048c779cdSXin LI #endif
481