xref: /freebsd-src/contrib/file/src/is_json.c (revision 2726a7014867ad7224d09b66836c5d385f0350f4)
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*2726a701SXin LI FILE_RCSID("@(#)$File: is_json.c,v 1.15 2020/06/07 19:05:47 christos Exp $")
3648c779cdSXin LI #endif
3748c779cdSXin LI 
3848c779cdSXin LI #include <string.h>
3948c779cdSXin LI #include "magic.h"
4048c779cdSXin LI #endif
4148c779cdSXin LI 
4248c779cdSXin LI #ifdef DEBUG
4348c779cdSXin LI #include <stdio.h>
4448c779cdSXin LI #define DPRINTF(a, b, c)	\
4548c779cdSXin LI     printf("%s [%.2x/%c] %.20s\n", (a), *(b), *(b), (const char *)(c))
4648c779cdSXin LI #else
4748c779cdSXin LI #define DPRINTF(a, b, c)	do { } while (/*CONSTCOND*/0)
4848c779cdSXin LI #endif
4948c779cdSXin LI 
5048c779cdSXin LI #define JSON_ARRAY	0
5148c779cdSXin LI #define JSON_CONSTANT	1
5248c779cdSXin LI #define JSON_NUMBER	2
5348c779cdSXin LI #define JSON_OBJECT	3
5448c779cdSXin LI #define JSON_STRING	4
5548c779cdSXin LI #define JSON_ARRAYN	5
5648c779cdSXin LI #define JSON_MAX	6
5748c779cdSXin LI 
5848c779cdSXin LI /*
5948c779cdSXin LI  * if JSON_COUNT != 0:
6048c779cdSXin LI  *	count all the objects, require that we have the whole data file
6148c779cdSXin LI  * otherwise:
6248c779cdSXin LI  *	stop if we find an object or an array
6348c779cdSXin LI  */
6448c779cdSXin LI #ifndef JSON_COUNT
6548c779cdSXin LI #define JSON_COUNT 0
6648c779cdSXin LI #endif
6748c779cdSXin LI 
6848c779cdSXin LI static int json_parse(const unsigned char **, const unsigned char *, size_t *,
6948c779cdSXin LI 	size_t);
7048c779cdSXin LI 
7148c779cdSXin LI static int
7248c779cdSXin LI json_isspace(const unsigned char uc)
7348c779cdSXin LI {
7448c779cdSXin LI 	switch (uc) {
7548c779cdSXin LI 	case ' ':
7648c779cdSXin LI 	case '\n':
7748c779cdSXin LI 	case '\r':
7848c779cdSXin LI 	case '\t':
7948c779cdSXin LI 		return 1;
8048c779cdSXin LI 	default:
8148c779cdSXin LI 		return 0;
8248c779cdSXin LI 	}
8348c779cdSXin LI }
8448c779cdSXin LI 
8548c779cdSXin LI static int
8648c779cdSXin LI json_isdigit(unsigned char uc)
8748c779cdSXin LI {
8848c779cdSXin LI 	switch (uc) {
8948c779cdSXin LI 	case '0': case '1': case '2': case '3': case '4':
9048c779cdSXin LI 	case '5': case '6': case '7': case '8': case '9':
9148c779cdSXin LI 		return 1;
9248c779cdSXin LI 	default:
9348c779cdSXin LI 		return 0;
9448c779cdSXin LI 	}
9548c779cdSXin LI }
9648c779cdSXin LI 
9748c779cdSXin LI static int
9848c779cdSXin LI json_isxdigit(unsigned char uc)
9948c779cdSXin LI {
10048c779cdSXin LI 	if (json_isdigit(uc))
10148c779cdSXin LI 		return 1;
10248c779cdSXin LI 	switch (uc) {
10348c779cdSXin LI 	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
10448c779cdSXin LI 	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
10548c779cdSXin LI 		return 1;
10648c779cdSXin LI 	default:
10748c779cdSXin LI 		return 0;
10848c779cdSXin LI 	}
10948c779cdSXin LI }
11048c779cdSXin LI 
11148c779cdSXin LI static const unsigned char *
11248c779cdSXin LI json_skip_space(const unsigned char *uc, const unsigned char *ue)
11348c779cdSXin LI {
11448c779cdSXin LI 	while (uc < ue && json_isspace(*uc))
11548c779cdSXin LI 		uc++;
11648c779cdSXin LI 	return uc;
11748c779cdSXin LI }
11848c779cdSXin LI 
11948c779cdSXin LI static int
12048c779cdSXin LI json_parse_string(const unsigned char **ucp, const unsigned char *ue)
12148c779cdSXin LI {
12248c779cdSXin LI 	const unsigned char *uc = *ucp;
12348c779cdSXin LI 	size_t i;
12448c779cdSXin LI 
12548c779cdSXin LI 	DPRINTF("Parse string: ", uc, *ucp);
12648c779cdSXin LI 	while (uc < ue) {
12748c779cdSXin LI 		switch (*uc++) {
12848c779cdSXin LI 		case '\0':
12948c779cdSXin LI 			goto out;
13048c779cdSXin LI 		case '\\':
13148c779cdSXin LI 			if (uc == ue)
13248c779cdSXin LI 				goto out;
13348c779cdSXin LI 			switch (*uc++) {
13448c779cdSXin LI 			case '\0':
13548c779cdSXin LI 				goto out;
13648c779cdSXin LI 			case '"':
13748c779cdSXin LI 			case '\\':
13848c779cdSXin LI 			case '/':
13948c779cdSXin LI 			case 'b':
14048c779cdSXin LI 			case 'f':
14148c779cdSXin LI 			case 'n':
14248c779cdSXin LI 			case 'r':
14348c779cdSXin LI 			case 't':
14448c779cdSXin LI 				continue;
14548c779cdSXin LI 			case 'u':
14648c779cdSXin LI 				if (ue - uc < 4) {
14748c779cdSXin LI 					uc = ue;
14848c779cdSXin LI 					goto out;
14948c779cdSXin LI 				}
15048c779cdSXin LI 				for (i = 0; i < 4; i++)
15148c779cdSXin LI 					if (!json_isxdigit(*uc++))
15248c779cdSXin LI 						goto out;
15348c779cdSXin LI 				continue;
15448c779cdSXin LI 			default:
15548c779cdSXin LI 				goto out;
15648c779cdSXin LI 			}
15748c779cdSXin LI 		case '"':
15848c779cdSXin LI 			*ucp = uc;
159*2726a701SXin LI 			DPRINTF("Good string: ", uc, *ucp);
16048c779cdSXin LI 			return 1;
16148c779cdSXin LI 		default:
16248c779cdSXin LI 			continue;
16348c779cdSXin LI 		}
16448c779cdSXin LI 	}
16548c779cdSXin LI out:
16648c779cdSXin LI 	DPRINTF("Bad string: ", uc, *ucp);
16748c779cdSXin LI 	*ucp = uc;
16848c779cdSXin LI 	return 0;
16948c779cdSXin LI }
17048c779cdSXin LI 
17148c779cdSXin LI static int
17248c779cdSXin LI json_parse_array(const unsigned char **ucp, const unsigned char *ue,
17348c779cdSXin LI 	size_t *st, size_t lvl)
17448c779cdSXin LI {
17548c779cdSXin LI 	const unsigned char *uc = *ucp;
17648c779cdSXin LI 
17748c779cdSXin LI 	DPRINTF("Parse array: ", uc, *ucp);
17848c779cdSXin LI 	while (uc < ue) {
179*2726a701SXin LI 		if (*uc == ']')
180*2726a701SXin LI 			goto done;
18148c779cdSXin LI 		if (!json_parse(&uc, ue, st, lvl + 1))
18248c779cdSXin LI 			goto out;
18348c779cdSXin LI 		if (uc == ue)
18448c779cdSXin LI 			goto out;
18548c779cdSXin LI 		switch (*uc) {
18648c779cdSXin LI 		case ',':
18748c779cdSXin LI 			uc++;
18848c779cdSXin LI 			continue;
18948c779cdSXin LI 		case ']':
190*2726a701SXin LI 		done:
19148c779cdSXin LI 			st[JSON_ARRAYN]++;
19248c779cdSXin LI 			*ucp = uc + 1;
193*2726a701SXin LI 			DPRINTF("Good array: ", uc, *ucp);
19448c779cdSXin LI 			return 1;
19548c779cdSXin LI 		default:
19648c779cdSXin LI 			goto out;
19748c779cdSXin LI 		}
19848c779cdSXin LI 	}
19948c779cdSXin LI out:
20048c779cdSXin LI 	DPRINTF("Bad array: ", uc,  *ucp);
20148c779cdSXin LI 	*ucp = uc;
20248c779cdSXin LI 	return 0;
20348c779cdSXin LI }
20448c779cdSXin LI 
20548c779cdSXin LI static int
20648c779cdSXin LI json_parse_object(const unsigned char **ucp, const unsigned char *ue,
20748c779cdSXin LI 	size_t *st, size_t lvl)
20848c779cdSXin LI {
20948c779cdSXin LI 	const unsigned char *uc = *ucp;
21048c779cdSXin LI 	DPRINTF("Parse object: ", uc, *ucp);
21148c779cdSXin LI 	while (uc < ue) {
21248c779cdSXin LI 		uc = json_skip_space(uc, ue);
21348c779cdSXin LI 		if (uc == ue)
21448c779cdSXin LI 			goto out;
215*2726a701SXin LI 		if (*uc == '}') {
216*2726a701SXin LI 			uc++;
217*2726a701SXin LI 			goto done;
218*2726a701SXin LI 		}
21948c779cdSXin LI 		if (*uc++ != '"') {
22048c779cdSXin LI 			DPRINTF("not string", uc, *ucp);
22148c779cdSXin LI 			goto out;
22248c779cdSXin LI 		}
22348c779cdSXin LI 		DPRINTF("next field", uc, *ucp);
22448c779cdSXin LI 		if (!json_parse_string(&uc, ue)) {
22548c779cdSXin LI 			DPRINTF("not string", uc, *ucp);
22648c779cdSXin LI 			goto out;
22748c779cdSXin LI 		}
22848c779cdSXin LI 		uc = json_skip_space(uc, ue);
22948c779cdSXin LI 		if (uc == ue)
23048c779cdSXin LI 			goto out;
23148c779cdSXin LI 		if (*uc++ != ':') {
23248c779cdSXin LI 			DPRINTF("not colon", uc, *ucp);
23348c779cdSXin LI 			goto out;
23448c779cdSXin LI 		}
23548c779cdSXin LI 		if (!json_parse(&uc, ue, st, lvl + 1)) {
23648c779cdSXin LI 			DPRINTF("not json", uc, *ucp);
23748c779cdSXin LI 			goto out;
23848c779cdSXin LI 		}
23948c779cdSXin LI 		if (uc == ue)
24048c779cdSXin LI 			goto out;
24148c779cdSXin LI 		switch (*uc++) {
24248c779cdSXin LI 		case ',':
24348c779cdSXin LI 			continue;
24448c779cdSXin LI 		case '}': /* { */
245*2726a701SXin LI 		done:
24648c779cdSXin LI 			*ucp = uc;
24748c779cdSXin LI 			DPRINTF("Good object: ", uc, *ucp);
24848c779cdSXin LI 			return 1;
24948c779cdSXin LI 		default:
25048c779cdSXin LI 			*ucp = uc - 1;
25148c779cdSXin LI 			DPRINTF("not more", uc, *ucp);
25248c779cdSXin LI 			goto out;
25348c779cdSXin LI 		}
25448c779cdSXin LI 	}
25548c779cdSXin LI out:
25648c779cdSXin LI 	DPRINTF("Bad object: ", uc, *ucp);
25748c779cdSXin LI 	*ucp = uc;
25848c779cdSXin LI 	return 0;
25948c779cdSXin LI }
26048c779cdSXin LI 
26148c779cdSXin LI static int
26248c779cdSXin LI json_parse_number(const unsigned char **ucp, const unsigned char *ue)
26348c779cdSXin LI {
26448c779cdSXin LI 	const unsigned char *uc = *ucp;
26548c779cdSXin LI 	int got = 0;
26648c779cdSXin LI 
26748c779cdSXin LI 	DPRINTF("Parse number: ", uc, *ucp);
26848c779cdSXin LI 	if (uc == ue)
26948c779cdSXin LI 		return 0;
27048c779cdSXin LI 	if (*uc == '-')
27148c779cdSXin LI 		uc++;
27248c779cdSXin LI 
27348c779cdSXin LI 	for (; uc < ue; uc++) {
27448c779cdSXin LI 		if (!json_isdigit(*uc))
27548c779cdSXin LI 			break;
27648c779cdSXin LI 		got = 1;
27748c779cdSXin LI 	}
27848c779cdSXin LI 	if (uc == ue)
27948c779cdSXin LI 		goto out;
28048c779cdSXin LI 	if (*uc == '.')
28148c779cdSXin LI 		uc++;
28248c779cdSXin LI 	for (; uc < ue; uc++) {
28348c779cdSXin LI 		if (!json_isdigit(*uc))
28448c779cdSXin LI 			break;
28548c779cdSXin LI 		got = 1;
28648c779cdSXin LI 	}
28748c779cdSXin LI 	if (uc == ue)
28848c779cdSXin LI 		goto out;
28948c779cdSXin LI 	if (got && (*uc == 'e' || *uc == 'E')) {
29048c779cdSXin LI 		uc++;
29148c779cdSXin LI 		got = 0;
29248c779cdSXin LI 		if (uc == ue)
29348c779cdSXin LI 			goto out;
29448c779cdSXin LI 		if (*uc == '+' || *uc == '-')
29548c779cdSXin LI 			uc++;
29648c779cdSXin LI 		for (; uc < ue; uc++) {
29748c779cdSXin LI 			if (!json_isdigit(*uc))
29848c779cdSXin LI 				break;
29948c779cdSXin LI 			got = 1;
30048c779cdSXin LI 		}
30148c779cdSXin LI 	}
30248c779cdSXin LI out:
30348c779cdSXin LI 	if (!got)
30448c779cdSXin LI 		DPRINTF("Bad number: ", uc, *ucp);
30548c779cdSXin LI 	else
30648c779cdSXin LI 		DPRINTF("Good number: ", uc, *ucp);
30748c779cdSXin LI 	*ucp = uc;
30848c779cdSXin LI 	return got;
30948c779cdSXin LI }
31048c779cdSXin LI 
31148c779cdSXin LI static int
31248c779cdSXin LI json_parse_const(const unsigned char **ucp, const unsigned char *ue,
31348c779cdSXin LI     const char *str, size_t len)
31448c779cdSXin LI {
31548c779cdSXin LI 	const unsigned char *uc = *ucp;
31648c779cdSXin LI 
31748c779cdSXin LI 	DPRINTF("Parse const: ", uc, *ucp);
31848c779cdSXin LI 	for (len--; uc < ue && --len;) {
31948c779cdSXin LI 		if (*uc++ == *++str)
32048c779cdSXin LI 			continue;
32148c779cdSXin LI 	}
32248c779cdSXin LI 	if (len)
32348c779cdSXin LI 		DPRINTF("Bad const: ", uc, *ucp);
32448c779cdSXin LI 	*ucp = uc;
32548c779cdSXin LI 	return len == 0;
32648c779cdSXin LI }
32748c779cdSXin LI 
32848c779cdSXin LI static int
32948c779cdSXin LI json_parse(const unsigned char **ucp, const unsigned char *ue,
33048c779cdSXin LI     size_t *st, size_t lvl)
33148c779cdSXin LI {
33248c779cdSXin LI 	const unsigned char *uc;
33348c779cdSXin LI 	int rv = 0;
33448c779cdSXin LI 	int t;
33548c779cdSXin LI 
33648c779cdSXin LI 	uc = json_skip_space(*ucp, ue);
33748c779cdSXin LI 	if (uc == ue)
33848c779cdSXin LI 		goto out;
33948c779cdSXin LI 
34048c779cdSXin LI 	// Avoid recursion
34148c779cdSXin LI 	if (lvl > 20)
34248c779cdSXin LI 		return 0;
34348c779cdSXin LI #if JSON_COUNT
34448c779cdSXin LI 	/* bail quickly if not counting */
34548c779cdSXin LI 	if (lvl > 1 && (st[JSON_OBJECT] || st[JSON_ARRAYN]))
34648c779cdSXin LI 		return 1;
34748c779cdSXin LI #endif
34848c779cdSXin LI 
34948c779cdSXin LI 	DPRINTF("Parse general: ", uc, *ucp);
35048c779cdSXin LI 	switch (*uc++) {
35148c779cdSXin LI 	case '"':
35248c779cdSXin LI 		rv = json_parse_string(&uc, ue);
35348c779cdSXin LI 		t = JSON_STRING;
35448c779cdSXin LI 		break;
35548c779cdSXin LI 	case '[':
35648c779cdSXin LI 		rv = json_parse_array(&uc, ue, st, lvl + 1);
35748c779cdSXin LI 		t = JSON_ARRAY;
35848c779cdSXin LI 		break;
35948c779cdSXin LI 	case '{': /* '}' */
36048c779cdSXin LI 		rv = json_parse_object(&uc, ue, st, lvl + 1);
36148c779cdSXin LI 		t = JSON_OBJECT;
36248c779cdSXin LI 		break;
36348c779cdSXin LI 	case 't':
36448c779cdSXin LI 		rv = json_parse_const(&uc, ue, "true", sizeof("true"));
36548c779cdSXin LI 		t = JSON_CONSTANT;
36648c779cdSXin LI 		break;
36748c779cdSXin LI 	case 'f':
36848c779cdSXin LI 		rv = json_parse_const(&uc, ue, "false", sizeof("false"));
36948c779cdSXin LI 		t = JSON_CONSTANT;
37048c779cdSXin LI 		break;
37148c779cdSXin LI 	case 'n':
37248c779cdSXin LI 		rv = json_parse_const(&uc, ue, "null", sizeof("null"));
37348c779cdSXin LI 		t = JSON_CONSTANT;
37448c779cdSXin LI 		break;
37548c779cdSXin LI 	default:
37648c779cdSXin LI 		--uc;
37748c779cdSXin LI 		rv = json_parse_number(&uc, ue);
37848c779cdSXin LI 		t = JSON_NUMBER;
37948c779cdSXin LI 		break;
38048c779cdSXin LI 	}
38148c779cdSXin LI 	if (rv)
38248c779cdSXin LI 		st[t]++;
38348c779cdSXin LI 	uc = json_skip_space(uc, ue);
38448c779cdSXin LI out:
38548c779cdSXin LI 	*ucp = uc;
38648c779cdSXin LI 	DPRINTF("End general: ", uc, *ucp);
38748c779cdSXin LI 	if (lvl == 0)
38848c779cdSXin LI 		return rv && (st[JSON_ARRAYN] || st[JSON_OBJECT]);
38948c779cdSXin LI 	return rv;
39048c779cdSXin LI }
39148c779cdSXin LI 
39248c779cdSXin LI #ifndef TEST
39348c779cdSXin LI int
39448c779cdSXin LI file_is_json(struct magic_set *ms, const struct buffer *b)
39548c779cdSXin LI {
39648c779cdSXin LI 	const unsigned char *uc = CAST(const unsigned char *, b->fbuf);
39748c779cdSXin LI 	const unsigned char *ue = uc + b->flen;
39848c779cdSXin LI 	size_t st[JSON_MAX];
39948c779cdSXin LI 	int mime = ms->flags & MAGIC_MIME;
40048c779cdSXin LI 
40148c779cdSXin LI 
40248c779cdSXin LI 	if ((ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION)) != 0)
40348c779cdSXin LI 		return 0;
40448c779cdSXin LI 
40548c779cdSXin LI 	memset(st, 0, sizeof(st));
40648c779cdSXin LI 
40748c779cdSXin LI 	if (!json_parse(&uc, ue, st, 0))
40848c779cdSXin LI 		return 0;
40948c779cdSXin LI 
41048c779cdSXin LI 	if (mime == MAGIC_MIME_ENCODING)
41148c779cdSXin LI 		return 1;
41248c779cdSXin LI 	if (mime) {
41348c779cdSXin LI 		if (file_printf(ms, "application/json") == -1)
41448c779cdSXin LI 			return -1;
41548c779cdSXin LI 		return 1;
41648c779cdSXin LI 	}
41748c779cdSXin LI 	if (file_printf(ms, "JSON data") == -1)
41848c779cdSXin LI 		return -1;
41948c779cdSXin LI #if JSON_COUNT
42048c779cdSXin LI #define P(n) st[n], st[n] > 1 ? "s" : ""
42148c779cdSXin LI 	if (file_printf(ms, " (%" SIZE_T_FORMAT "u object%s, %" SIZE_T_FORMAT
42248c779cdSXin LI 	    "u array%s, %" SIZE_T_FORMAT "u string%s, %" SIZE_T_FORMAT
42348c779cdSXin LI 	    "u constant%s, %" SIZE_T_FORMAT "u number%s, %" SIZE_T_FORMAT
42448c779cdSXin LI 	    "u >1array%s)",
42548c779cdSXin LI 	    P(JSON_OBJECT), P(JSON_ARRAY), P(JSON_STRING), P(JSON_CONSTANT),
42648c779cdSXin LI 	    P(JSON_NUMBER), P(JSON_ARRAYN))
42748c779cdSXin LI 	    == -1)
42848c779cdSXin LI 		return -1;
42948c779cdSXin LI #endif
43048c779cdSXin LI 	return 1;
43148c779cdSXin LI }
43248c779cdSXin LI 
43348c779cdSXin LI #else
43448c779cdSXin LI 
43548c779cdSXin LI #include <sys/types.h>
43648c779cdSXin LI #include <sys/stat.h>
43748c779cdSXin LI #include <stdio.h>
43848c779cdSXin LI #include <fcntl.h>
43948c779cdSXin LI #include <unistd.h>
44048c779cdSXin LI #include <stdlib.h>
44148c779cdSXin LI #include <stdint.h>
44248c779cdSXin LI #include <err.h>
44348c779cdSXin LI 
44448c779cdSXin LI int
44548c779cdSXin LI main(int argc, char *argv[])
44648c779cdSXin LI {
44748c779cdSXin LI 	int fd, rv;
44848c779cdSXin LI 	struct stat st;
44948c779cdSXin LI 	unsigned char *p;
45048c779cdSXin LI 	size_t stats[JSON_MAX];
45148c779cdSXin LI 
45248c779cdSXin LI 	if ((fd = open(argv[1], O_RDONLY)) == -1)
45348c779cdSXin LI 		err(EXIT_FAILURE, "Can't open `%s'", argv[1]);
45448c779cdSXin LI 
45548c779cdSXin LI 	if (fstat(fd, &st) == -1)
45648c779cdSXin LI 		err(EXIT_FAILURE, "Can't stat `%s'", argv[1]);
45748c779cdSXin LI 
45848c779cdSXin LI 	if ((p = malloc(st.st_size)) == NULL)
45948c779cdSXin LI 		err(EXIT_FAILURE, "Can't allocate %jd bytes",
46048c779cdSXin LI 		    (intmax_t)st.st_size);
46148c779cdSXin LI 	if (read(fd, p, st.st_size) != st.st_size)
46248c779cdSXin LI 		err(EXIT_FAILURE, "Can't read %jd bytes",
46348c779cdSXin LI 		    (intmax_t)st.st_size);
46448c779cdSXin LI 	memset(stats, 0, sizeof(stats));
46548c779cdSXin LI 	printf("is json %d\n", json_parse((const unsigned char **)&p,
46648c779cdSXin LI 	    p + st.st_size, stats, 0));
46748c779cdSXin LI 	return 0;
46848c779cdSXin LI }
46948c779cdSXin LI #endif
470