xref: /freebsd-src/contrib/file/src/is_json.c (revision 48c779cdecb5f803e5fe5d761987e976ca9609db)
1*48c779cdSXin LI /*-
2*48c779cdSXin LI  * Copyright (c) 2018 Christos Zoulas
3*48c779cdSXin LI  * All rights reserved.
4*48c779cdSXin LI  *
5*48c779cdSXin LI  * Redistribution and use in source and binary forms, with or without
6*48c779cdSXin LI  * modification, are permitted provided that the following conditions
7*48c779cdSXin LI  * are met:
8*48c779cdSXin LI  * 1. Redistributions of source code must retain the above copyright
9*48c779cdSXin LI  *    notice, this list of conditions and the following disclaimer.
10*48c779cdSXin LI  * 2. Redistributions in binary form must reproduce the above copyright
11*48c779cdSXin LI  *    notice, this list of conditions and the following disclaimer in the
12*48c779cdSXin LI  *    documentation and/or other materials provided with the distribution.
13*48c779cdSXin LI  *
14*48c779cdSXin LI  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
15*48c779cdSXin LI  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
16*48c779cdSXin LI  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17*48c779cdSXin LI  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
18*48c779cdSXin LI  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19*48c779cdSXin LI  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20*48c779cdSXin LI  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21*48c779cdSXin LI  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22*48c779cdSXin LI  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23*48c779cdSXin LI  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24*48c779cdSXin LI  * POSSIBILITY OF SUCH DAMAGE.
25*48c779cdSXin LI  */
26*48c779cdSXin LI 
27*48c779cdSXin LI /*
28*48c779cdSXin LI  * Parse JSON object serialization format (RFC-7159)
29*48c779cdSXin LI  */
30*48c779cdSXin LI 
31*48c779cdSXin LI #ifndef TEST
32*48c779cdSXin LI #include "file.h"
33*48c779cdSXin LI 
34*48c779cdSXin LI #ifndef lint
35*48c779cdSXin LI FILE_RCSID("@(#)$File: is_json.c,v 1.13 2019/03/02 01:08:10 christos Exp $")
36*48c779cdSXin LI #endif
37*48c779cdSXin LI 
38*48c779cdSXin LI #include <string.h>
39*48c779cdSXin LI #include "magic.h"
40*48c779cdSXin LI #endif
41*48c779cdSXin LI 
42*48c779cdSXin LI #ifdef DEBUG
43*48c779cdSXin LI #include <stdio.h>
44*48c779cdSXin LI #define DPRINTF(a, b, c)	\
45*48c779cdSXin LI     printf("%s [%.2x/%c] %.20s\n", (a), *(b), *(b), (const char *)(c))
46*48c779cdSXin LI #else
47*48c779cdSXin LI #define DPRINTF(a, b, c)	do { } while (/*CONSTCOND*/0)
48*48c779cdSXin LI #endif
49*48c779cdSXin LI 
50*48c779cdSXin LI #define JSON_ARRAY	0
51*48c779cdSXin LI #define JSON_CONSTANT	1
52*48c779cdSXin LI #define JSON_NUMBER	2
53*48c779cdSXin LI #define JSON_OBJECT	3
54*48c779cdSXin LI #define JSON_STRING	4
55*48c779cdSXin LI #define JSON_ARRAYN	5
56*48c779cdSXin LI #define JSON_MAX	6
57*48c779cdSXin LI 
58*48c779cdSXin LI /*
59*48c779cdSXin LI  * if JSON_COUNT != 0:
60*48c779cdSXin LI  *	count all the objects, require that we have the whole data file
61*48c779cdSXin LI  * otherwise:
62*48c779cdSXin LI  *	stop if we find an object or an array
63*48c779cdSXin LI  */
64*48c779cdSXin LI #ifndef JSON_COUNT
65*48c779cdSXin LI #define JSON_COUNT 0
66*48c779cdSXin LI #endif
67*48c779cdSXin LI 
68*48c779cdSXin LI static int json_parse(const unsigned char **, const unsigned char *, size_t *,
69*48c779cdSXin LI 	size_t);
70*48c779cdSXin LI 
71*48c779cdSXin LI static int
72*48c779cdSXin LI json_isspace(const unsigned char uc)
73*48c779cdSXin LI {
74*48c779cdSXin LI 	switch (uc) {
75*48c779cdSXin LI 	case ' ':
76*48c779cdSXin LI 	case '\n':
77*48c779cdSXin LI 	case '\r':
78*48c779cdSXin LI 	case '\t':
79*48c779cdSXin LI 		return 1;
80*48c779cdSXin LI 	default:
81*48c779cdSXin LI 		return 0;
82*48c779cdSXin LI 	}
83*48c779cdSXin LI }
84*48c779cdSXin LI 
85*48c779cdSXin LI static int
86*48c779cdSXin LI json_isdigit(unsigned char uc)
87*48c779cdSXin LI {
88*48c779cdSXin LI 	switch (uc) {
89*48c779cdSXin LI 	case '0': case '1': case '2': case '3': case '4':
90*48c779cdSXin LI 	case '5': case '6': case '7': case '8': case '9':
91*48c779cdSXin LI 		return 1;
92*48c779cdSXin LI 	default:
93*48c779cdSXin LI 		return 0;
94*48c779cdSXin LI 	}
95*48c779cdSXin LI }
96*48c779cdSXin LI 
97*48c779cdSXin LI static int
98*48c779cdSXin LI json_isxdigit(unsigned char uc)
99*48c779cdSXin LI {
100*48c779cdSXin LI 	if (json_isdigit(uc))
101*48c779cdSXin LI 		return 1;
102*48c779cdSXin LI 	switch (uc) {
103*48c779cdSXin LI 	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
104*48c779cdSXin LI 	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
105*48c779cdSXin LI 		return 1;
106*48c779cdSXin LI 	default:
107*48c779cdSXin LI 		return 0;
108*48c779cdSXin LI 	}
109*48c779cdSXin LI }
110*48c779cdSXin LI 
111*48c779cdSXin LI static const unsigned char *
112*48c779cdSXin LI json_skip_space(const unsigned char *uc, const unsigned char *ue)
113*48c779cdSXin LI {
114*48c779cdSXin LI 	while (uc < ue && json_isspace(*uc))
115*48c779cdSXin LI 		uc++;
116*48c779cdSXin LI 	return uc;
117*48c779cdSXin LI }
118*48c779cdSXin LI 
119*48c779cdSXin LI static int
120*48c779cdSXin LI json_parse_string(const unsigned char **ucp, const unsigned char *ue)
121*48c779cdSXin LI {
122*48c779cdSXin LI 	const unsigned char *uc = *ucp;
123*48c779cdSXin LI 	size_t i;
124*48c779cdSXin LI 
125*48c779cdSXin LI 	DPRINTF("Parse string: ", uc, *ucp);
126*48c779cdSXin LI 	while (uc < ue) {
127*48c779cdSXin LI 		switch (*uc++) {
128*48c779cdSXin LI 		case '\0':
129*48c779cdSXin LI 			goto out;
130*48c779cdSXin LI 		case '\\':
131*48c779cdSXin LI 			if (uc == ue)
132*48c779cdSXin LI 				goto out;
133*48c779cdSXin LI 			switch (*uc++) {
134*48c779cdSXin LI 			case '\0':
135*48c779cdSXin LI 				goto out;
136*48c779cdSXin LI 			case '"':
137*48c779cdSXin LI 			case '\\':
138*48c779cdSXin LI 			case '/':
139*48c779cdSXin LI 			case 'b':
140*48c779cdSXin LI 			case 'f':
141*48c779cdSXin LI 			case 'n':
142*48c779cdSXin LI 			case 'r':
143*48c779cdSXin LI 			case 't':
144*48c779cdSXin LI 				continue;
145*48c779cdSXin LI 			case 'u':
146*48c779cdSXin LI 				if (ue - uc < 4) {
147*48c779cdSXin LI 					uc = ue;
148*48c779cdSXin LI 					goto out;
149*48c779cdSXin LI 				}
150*48c779cdSXin LI 				for (i = 0; i < 4; i++)
151*48c779cdSXin LI 					if (!json_isxdigit(*uc++))
152*48c779cdSXin LI 						goto out;
153*48c779cdSXin LI 				continue;
154*48c779cdSXin LI 			default:
155*48c779cdSXin LI 				goto out;
156*48c779cdSXin LI 			}
157*48c779cdSXin LI 		case '"':
158*48c779cdSXin LI 			*ucp = uc;
159*48c779cdSXin LI 			return 1;
160*48c779cdSXin LI 		default:
161*48c779cdSXin LI 			continue;
162*48c779cdSXin LI 		}
163*48c779cdSXin LI 	}
164*48c779cdSXin LI out:
165*48c779cdSXin LI 	DPRINTF("Bad string: ", uc, *ucp);
166*48c779cdSXin LI 	*ucp = uc;
167*48c779cdSXin LI 	return 0;
168*48c779cdSXin LI }
169*48c779cdSXin LI 
170*48c779cdSXin LI static int
171*48c779cdSXin LI json_parse_array(const unsigned char **ucp, const unsigned char *ue,
172*48c779cdSXin LI 	size_t *st, size_t lvl)
173*48c779cdSXin LI {
174*48c779cdSXin LI 	const unsigned char *uc = *ucp;
175*48c779cdSXin LI 	int more = 0;	/* Array has more than 1 element */
176*48c779cdSXin LI 
177*48c779cdSXin LI 	DPRINTF("Parse array: ", uc, *ucp);
178*48c779cdSXin LI 	while (uc < ue) {
179*48c779cdSXin LI 		if (!json_parse(&uc, ue, st, lvl + 1))
180*48c779cdSXin LI 			goto out;
181*48c779cdSXin LI 		if (uc == ue)
182*48c779cdSXin LI 			goto out;
183*48c779cdSXin LI 		switch (*uc) {
184*48c779cdSXin LI 		case ',':
185*48c779cdSXin LI 			more++;
186*48c779cdSXin LI 			uc++;
187*48c779cdSXin LI 			continue;
188*48c779cdSXin LI 		case ']':
189*48c779cdSXin LI 			if (more)
190*48c779cdSXin LI 				st[JSON_ARRAYN]++;
191*48c779cdSXin LI 			*ucp = uc + 1;
192*48c779cdSXin LI 			return 1;
193*48c779cdSXin LI 		default:
194*48c779cdSXin LI 			goto out;
195*48c779cdSXin LI 		}
196*48c779cdSXin LI 	}
197*48c779cdSXin LI out:
198*48c779cdSXin LI 	DPRINTF("Bad array: ", uc,  *ucp);
199*48c779cdSXin LI 	*ucp = uc;
200*48c779cdSXin LI 	return 0;
201*48c779cdSXin LI }
202*48c779cdSXin LI 
203*48c779cdSXin LI static int
204*48c779cdSXin LI json_parse_object(const unsigned char **ucp, const unsigned char *ue,
205*48c779cdSXin LI 	size_t *st, size_t lvl)
206*48c779cdSXin LI {
207*48c779cdSXin LI 	const unsigned char *uc = *ucp;
208*48c779cdSXin LI 	DPRINTF("Parse object: ", uc, *ucp);
209*48c779cdSXin LI 	while (uc < ue) {
210*48c779cdSXin LI 		uc = json_skip_space(uc, ue);
211*48c779cdSXin LI 		if (uc == ue)
212*48c779cdSXin LI 			goto out;
213*48c779cdSXin LI 		if (*uc++ != '"') {
214*48c779cdSXin LI 			DPRINTF("not string", uc, *ucp);
215*48c779cdSXin LI 			goto out;
216*48c779cdSXin LI 		}
217*48c779cdSXin LI 		DPRINTF("next field", uc, *ucp);
218*48c779cdSXin LI 		if (!json_parse_string(&uc, ue)) {
219*48c779cdSXin LI 			DPRINTF("not string", uc, *ucp);
220*48c779cdSXin LI 			goto out;
221*48c779cdSXin LI 		}
222*48c779cdSXin LI 		uc = json_skip_space(uc, ue);
223*48c779cdSXin LI 		if (uc == ue)
224*48c779cdSXin LI 			goto out;
225*48c779cdSXin LI 		if (*uc++ != ':') {
226*48c779cdSXin LI 			DPRINTF("not colon", uc, *ucp);
227*48c779cdSXin LI 			goto out;
228*48c779cdSXin LI 		}
229*48c779cdSXin LI 		if (!json_parse(&uc, ue, st, lvl + 1)) {
230*48c779cdSXin LI 			DPRINTF("not json", uc, *ucp);
231*48c779cdSXin LI 			goto out;
232*48c779cdSXin LI 		}
233*48c779cdSXin LI 		if (uc == ue)
234*48c779cdSXin LI 			goto out;
235*48c779cdSXin LI 		switch (*uc++) {
236*48c779cdSXin LI 		case ',':
237*48c779cdSXin LI 			continue;
238*48c779cdSXin LI 		case '}': /* { */
239*48c779cdSXin LI 			*ucp = uc;
240*48c779cdSXin LI 			DPRINTF("Good object: ", uc, *ucp);
241*48c779cdSXin LI 			return 1;
242*48c779cdSXin LI 		default:
243*48c779cdSXin LI 			*ucp = uc - 1;
244*48c779cdSXin LI 			DPRINTF("not more", uc, *ucp);
245*48c779cdSXin LI 			goto out;
246*48c779cdSXin LI 		}
247*48c779cdSXin LI 	}
248*48c779cdSXin LI out:
249*48c779cdSXin LI 	DPRINTF("Bad object: ", uc, *ucp);
250*48c779cdSXin LI 	*ucp = uc;
251*48c779cdSXin LI 	return 0;
252*48c779cdSXin LI }
253*48c779cdSXin LI 
254*48c779cdSXin LI static int
255*48c779cdSXin LI json_parse_number(const unsigned char **ucp, const unsigned char *ue)
256*48c779cdSXin LI {
257*48c779cdSXin LI 	const unsigned char *uc = *ucp;
258*48c779cdSXin LI 	int got = 0;
259*48c779cdSXin LI 
260*48c779cdSXin LI 	DPRINTF("Parse number: ", uc, *ucp);
261*48c779cdSXin LI 	if (uc == ue)
262*48c779cdSXin LI 		return 0;
263*48c779cdSXin LI 	if (*uc == '-')
264*48c779cdSXin LI 		uc++;
265*48c779cdSXin LI 
266*48c779cdSXin LI 	for (; uc < ue; uc++) {
267*48c779cdSXin LI 		if (!json_isdigit(*uc))
268*48c779cdSXin LI 			break;
269*48c779cdSXin LI 		got = 1;
270*48c779cdSXin LI 	}
271*48c779cdSXin LI 	if (uc == ue)
272*48c779cdSXin LI 		goto out;
273*48c779cdSXin LI 	if (*uc == '.')
274*48c779cdSXin LI 		uc++;
275*48c779cdSXin LI 	for (; uc < ue; uc++) {
276*48c779cdSXin LI 		if (!json_isdigit(*uc))
277*48c779cdSXin LI 			break;
278*48c779cdSXin LI 		got = 1;
279*48c779cdSXin LI 	}
280*48c779cdSXin LI 	if (uc == ue)
281*48c779cdSXin LI 		goto out;
282*48c779cdSXin LI 	if (got && (*uc == 'e' || *uc == 'E')) {
283*48c779cdSXin LI 		uc++;
284*48c779cdSXin LI 		got = 0;
285*48c779cdSXin LI 		if (uc == ue)
286*48c779cdSXin LI 			goto out;
287*48c779cdSXin LI 		if (*uc == '+' || *uc == '-')
288*48c779cdSXin LI 			uc++;
289*48c779cdSXin LI 		for (; uc < ue; uc++) {
290*48c779cdSXin LI 			if (!json_isdigit(*uc))
291*48c779cdSXin LI 				break;
292*48c779cdSXin LI 			got = 1;
293*48c779cdSXin LI 		}
294*48c779cdSXin LI 	}
295*48c779cdSXin LI out:
296*48c779cdSXin LI 	if (!got)
297*48c779cdSXin LI 		DPRINTF("Bad number: ", uc, *ucp);
298*48c779cdSXin LI 	else
299*48c779cdSXin LI 		DPRINTF("Good number: ", uc, *ucp);
300*48c779cdSXin LI 	*ucp = uc;
301*48c779cdSXin LI 	return got;
302*48c779cdSXin LI }
303*48c779cdSXin LI 
304*48c779cdSXin LI static int
305*48c779cdSXin LI json_parse_const(const unsigned char **ucp, const unsigned char *ue,
306*48c779cdSXin LI     const char *str, size_t len)
307*48c779cdSXin LI {
308*48c779cdSXin LI 	const unsigned char *uc = *ucp;
309*48c779cdSXin LI 
310*48c779cdSXin LI 	DPRINTF("Parse const: ", uc, *ucp);
311*48c779cdSXin LI 	for (len--; uc < ue && --len;) {
312*48c779cdSXin LI 		if (*uc++ == *++str)
313*48c779cdSXin LI 			continue;
314*48c779cdSXin LI 	}
315*48c779cdSXin LI 	if (len)
316*48c779cdSXin LI 		DPRINTF("Bad const: ", uc, *ucp);
317*48c779cdSXin LI 	*ucp = uc;
318*48c779cdSXin LI 	return len == 0;
319*48c779cdSXin LI }
320*48c779cdSXin LI 
321*48c779cdSXin LI static int
322*48c779cdSXin LI json_parse(const unsigned char **ucp, const unsigned char *ue,
323*48c779cdSXin LI     size_t *st, size_t lvl)
324*48c779cdSXin LI {
325*48c779cdSXin LI 	const unsigned char *uc;
326*48c779cdSXin LI 	int rv = 0;
327*48c779cdSXin LI 	int t;
328*48c779cdSXin LI 
329*48c779cdSXin LI 	uc = json_skip_space(*ucp, ue);
330*48c779cdSXin LI 	if (uc == ue)
331*48c779cdSXin LI 		goto out;
332*48c779cdSXin LI 
333*48c779cdSXin LI 	// Avoid recursion
334*48c779cdSXin LI 	if (lvl > 20)
335*48c779cdSXin LI 		return 0;
336*48c779cdSXin LI #if JSON_COUNT
337*48c779cdSXin LI 	/* bail quickly if not counting */
338*48c779cdSXin LI 	if (lvl > 1 && (st[JSON_OBJECT] || st[JSON_ARRAYN]))
339*48c779cdSXin LI 		return 1;
340*48c779cdSXin LI #endif
341*48c779cdSXin LI 
342*48c779cdSXin LI 	DPRINTF("Parse general: ", uc, *ucp);
343*48c779cdSXin LI 	switch (*uc++) {
344*48c779cdSXin LI 	case '"':
345*48c779cdSXin LI 		rv = json_parse_string(&uc, ue);
346*48c779cdSXin LI 		t = JSON_STRING;
347*48c779cdSXin LI 		break;
348*48c779cdSXin LI 	case '[':
349*48c779cdSXin LI 		rv = json_parse_array(&uc, ue, st, lvl + 1);
350*48c779cdSXin LI 		t = JSON_ARRAY;
351*48c779cdSXin LI 		break;
352*48c779cdSXin LI 	case '{': /* '}' */
353*48c779cdSXin LI 		rv = json_parse_object(&uc, ue, st, lvl + 1);
354*48c779cdSXin LI 		t = JSON_OBJECT;
355*48c779cdSXin LI 		break;
356*48c779cdSXin LI 	case 't':
357*48c779cdSXin LI 		rv = json_parse_const(&uc, ue, "true", sizeof("true"));
358*48c779cdSXin LI 		t = JSON_CONSTANT;
359*48c779cdSXin LI 		break;
360*48c779cdSXin LI 	case 'f':
361*48c779cdSXin LI 		rv = json_parse_const(&uc, ue, "false", sizeof("false"));
362*48c779cdSXin LI 		t = JSON_CONSTANT;
363*48c779cdSXin LI 		break;
364*48c779cdSXin LI 	case 'n':
365*48c779cdSXin LI 		rv = json_parse_const(&uc, ue, "null", sizeof("null"));
366*48c779cdSXin LI 		t = JSON_CONSTANT;
367*48c779cdSXin LI 		break;
368*48c779cdSXin LI 	default:
369*48c779cdSXin LI 		--uc;
370*48c779cdSXin LI 		rv = json_parse_number(&uc, ue);
371*48c779cdSXin LI 		t = JSON_NUMBER;
372*48c779cdSXin LI 		break;
373*48c779cdSXin LI 	}
374*48c779cdSXin LI 	if (rv)
375*48c779cdSXin LI 		st[t]++;
376*48c779cdSXin LI 	uc = json_skip_space(uc, ue);
377*48c779cdSXin LI out:
378*48c779cdSXin LI 	*ucp = uc;
379*48c779cdSXin LI 	DPRINTF("End general: ", uc, *ucp);
380*48c779cdSXin LI 	if (lvl == 0)
381*48c779cdSXin LI 		return rv && (st[JSON_ARRAYN] || st[JSON_OBJECT]);
382*48c779cdSXin LI 	return rv;
383*48c779cdSXin LI }
384*48c779cdSXin LI 
385*48c779cdSXin LI #ifndef TEST
386*48c779cdSXin LI int
387*48c779cdSXin LI file_is_json(struct magic_set *ms, const struct buffer *b)
388*48c779cdSXin LI {
389*48c779cdSXin LI 	const unsigned char *uc = CAST(const unsigned char *, b->fbuf);
390*48c779cdSXin LI 	const unsigned char *ue = uc + b->flen;
391*48c779cdSXin LI 	size_t st[JSON_MAX];
392*48c779cdSXin LI 	int mime = ms->flags & MAGIC_MIME;
393*48c779cdSXin LI 
394*48c779cdSXin LI 
395*48c779cdSXin LI 	if ((ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION)) != 0)
396*48c779cdSXin LI 		return 0;
397*48c779cdSXin LI 
398*48c779cdSXin LI 	memset(st, 0, sizeof(st));
399*48c779cdSXin LI 
400*48c779cdSXin LI 	if (!json_parse(&uc, ue, st, 0))
401*48c779cdSXin LI 		return 0;
402*48c779cdSXin LI 
403*48c779cdSXin LI 	if (mime == MAGIC_MIME_ENCODING)
404*48c779cdSXin LI 		return 1;
405*48c779cdSXin LI 	if (mime) {
406*48c779cdSXin LI 		if (file_printf(ms, "application/json") == -1)
407*48c779cdSXin LI 			return -1;
408*48c779cdSXin LI 		return 1;
409*48c779cdSXin LI 	}
410*48c779cdSXin LI 	if (file_printf(ms, "JSON data") == -1)
411*48c779cdSXin LI 		return -1;
412*48c779cdSXin LI #if JSON_COUNT
413*48c779cdSXin LI #define P(n) st[n], st[n] > 1 ? "s" : ""
414*48c779cdSXin LI 	if (file_printf(ms, " (%" SIZE_T_FORMAT "u object%s, %" SIZE_T_FORMAT
415*48c779cdSXin LI 	    "u array%s, %" SIZE_T_FORMAT "u string%s, %" SIZE_T_FORMAT
416*48c779cdSXin LI 	    "u constant%s, %" SIZE_T_FORMAT "u number%s, %" SIZE_T_FORMAT
417*48c779cdSXin LI 	    "u >1array%s)",
418*48c779cdSXin LI 	    P(JSON_OBJECT), P(JSON_ARRAY), P(JSON_STRING), P(JSON_CONSTANT),
419*48c779cdSXin LI 	    P(JSON_NUMBER), P(JSON_ARRAYN))
420*48c779cdSXin LI 	    == -1)
421*48c779cdSXin LI 		return -1;
422*48c779cdSXin LI #endif
423*48c779cdSXin LI 	return 1;
424*48c779cdSXin LI }
425*48c779cdSXin LI 
426*48c779cdSXin LI #else
427*48c779cdSXin LI 
428*48c779cdSXin LI #include <sys/types.h>
429*48c779cdSXin LI #include <sys/stat.h>
430*48c779cdSXin LI #include <stdio.h>
431*48c779cdSXin LI #include <fcntl.h>
432*48c779cdSXin LI #include <unistd.h>
433*48c779cdSXin LI #include <stdlib.h>
434*48c779cdSXin LI #include <stdint.h>
435*48c779cdSXin LI #include <err.h>
436*48c779cdSXin LI 
437*48c779cdSXin LI int
438*48c779cdSXin LI main(int argc, char *argv[])
439*48c779cdSXin LI {
440*48c779cdSXin LI 	int fd, rv;
441*48c779cdSXin LI 	struct stat st;
442*48c779cdSXin LI 	unsigned char *p;
443*48c779cdSXin LI 	size_t stats[JSON_MAX];
444*48c779cdSXin LI 
445*48c779cdSXin LI 	if ((fd = open(argv[1], O_RDONLY)) == -1)
446*48c779cdSXin LI 		err(EXIT_FAILURE, "Can't open `%s'", argv[1]);
447*48c779cdSXin LI 
448*48c779cdSXin LI 	if (fstat(fd, &st) == -1)
449*48c779cdSXin LI 		err(EXIT_FAILURE, "Can't stat `%s'", argv[1]);
450*48c779cdSXin LI 
451*48c779cdSXin LI 	if ((p = malloc(st.st_size)) == NULL)
452*48c779cdSXin LI 		err(EXIT_FAILURE, "Can't allocate %jd bytes",
453*48c779cdSXin LI 		    (intmax_t)st.st_size);
454*48c779cdSXin LI 	if (read(fd, p, st.st_size) != st.st_size)
455*48c779cdSXin LI 		err(EXIT_FAILURE, "Can't read %jd bytes",
456*48c779cdSXin LI 		    (intmax_t)st.st_size);
457*48c779cdSXin LI 	memset(stats, 0, sizeof(stats));
458*48c779cdSXin LI 	printf("is json %d\n", json_parse((const unsigned char **)&p,
459*48c779cdSXin LI 	    p + st.st_size, stats, 0));
460*48c779cdSXin LI 	return 0;
461*48c779cdSXin LI }
462*48c779cdSXin LI #endif
463