1*ddb17682Schristos /* $NetBSD: is_json.c,v 1.6 2023/08/18 19:00:11 christos Exp $ */
2006f8008Schristos
3006f8008Schristos /*-
4006f8008Schristos * Copyright (c) 2018 Christos Zoulas
5006f8008Schristos * All rights reserved.
6006f8008Schristos *
7006f8008Schristos * Redistribution and use in source and binary forms, with or without
8006f8008Schristos * modification, are permitted provided that the following conditions
9006f8008Schristos * are met:
10006f8008Schristos * 1. Redistributions of source code must retain the above copyright
11006f8008Schristos * notice, this list of conditions and the following disclaimer.
12006f8008Schristos * 2. Redistributions in binary form must reproduce the above copyright
13006f8008Schristos * notice, this list of conditions and the following disclaimer in the
14006f8008Schristos * documentation and/or other materials provided with the distribution.
15006f8008Schristos *
16006f8008Schristos * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17006f8008Schristos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18006f8008Schristos * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19006f8008Schristos * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20006f8008Schristos * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21006f8008Schristos * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22006f8008Schristos * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23006f8008Schristos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24006f8008Schristos * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25006f8008Schristos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26006f8008Schristos * POSSIBILITY OF SUCH DAMAGE.
27006f8008Schristos */
28006f8008Schristos
29006f8008Schristos /*
30006f8008Schristos * Parse JSON object serialization format (RFC-7159)
31006f8008Schristos */
32006f8008Schristos
33006f8008Schristos #ifndef TEST
34006f8008Schristos #include "file.h"
35006f8008Schristos
36006f8008Schristos #ifndef lint
37006f8008Schristos #if 0
38*ddb17682Schristos FILE_RCSID("@(#)$File: is_json.c,v 1.30 2022/09/27 19:12:40 christos Exp $")
39006f8008Schristos #else
40*ddb17682Schristos __RCSID("$NetBSD: is_json.c,v 1.6 2023/08/18 19:00:11 christos Exp $");
41006f8008Schristos #endif
42006f8008Schristos #endif
43006f8008Schristos
44006f8008Schristos #include "magic.h"
451d4cb158Schristos #else
461d4cb158Schristos #include <stdio.h>
471d4cb158Schristos #include <stddef.h>
48006f8008Schristos #endif
491d4cb158Schristos #include <string.h>
50006f8008Schristos
51006f8008Schristos #ifdef DEBUG
52006f8008Schristos #include <stdio.h>
53006f8008Schristos #define DPRINTF(a, b, c) \
541d4cb158Schristos printf("%*s%s [%.2x/%c] %.*s\n", (int)lvl, "", (a), *(b), *(b), \
551d4cb158Schristos (int)(b - c), (const char *)(c))
561d4cb158Schristos #define __file_debugused
57006f8008Schristos #else
58bdab9e2dSchristos #define DPRINTF(a, b, c) do { } while (/*CONSTCOND*/0)
591d4cb158Schristos #define __file_debugused __attribute__((__unused__))
60006f8008Schristos #endif
61006f8008Schristos
62006f8008Schristos #define JSON_ARRAY 0
63006f8008Schristos #define JSON_CONSTANT 1
64006f8008Schristos #define JSON_NUMBER 2
65006f8008Schristos #define JSON_OBJECT 3
66006f8008Schristos #define JSON_STRING 4
67d0c65b7bSchristos #define JSON_ARRAYN 5
68d0c65b7bSchristos #define JSON_MAX 6
69006f8008Schristos
70006f8008Schristos /*
71006f8008Schristos * if JSON_COUNT != 0:
72006f8008Schristos * count all the objects, require that we have the whole data file
73006f8008Schristos * otherwise:
74006f8008Schristos * stop if we find an object or an array
75006f8008Schristos */
76006f8008Schristos #ifndef JSON_COUNT
77006f8008Schristos #define JSON_COUNT 0
78006f8008Schristos #endif
79006f8008Schristos
80006f8008Schristos static int json_parse(const unsigned char **, const unsigned char *, size_t *,
81006f8008Schristos size_t);
82006f8008Schristos
83006f8008Schristos static int
json_isspace(const unsigned char uc)84006f8008Schristos json_isspace(const unsigned char uc)
85006f8008Schristos {
86006f8008Schristos switch (uc) {
87006f8008Schristos case ' ':
88006f8008Schristos case '\n':
89006f8008Schristos case '\r':
90006f8008Schristos case '\t':
91006f8008Schristos return 1;
92006f8008Schristos default:
93006f8008Schristos return 0;
94006f8008Schristos }
95006f8008Schristos }
96006f8008Schristos
97006f8008Schristos static int
json_isdigit(unsigned char uc)98006f8008Schristos json_isdigit(unsigned char uc)
99006f8008Schristos {
100006f8008Schristos switch (uc) {
101006f8008Schristos case '0': case '1': case '2': case '3': case '4':
102006f8008Schristos case '5': case '6': case '7': case '8': case '9':
103006f8008Schristos return 1;
104006f8008Schristos default:
105006f8008Schristos return 0;
106006f8008Schristos }
107006f8008Schristos }
108006f8008Schristos
109006f8008Schristos static int
json_isxdigit(unsigned char uc)110006f8008Schristos json_isxdigit(unsigned char uc)
111006f8008Schristos {
112006f8008Schristos if (json_isdigit(uc))
113006f8008Schristos return 1;
114006f8008Schristos switch (uc) {
115006f8008Schristos case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
116006f8008Schristos case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
117006f8008Schristos return 1;
118006f8008Schristos default:
119006f8008Schristos return 0;
120006f8008Schristos }
121006f8008Schristos }
122006f8008Schristos
123006f8008Schristos static const unsigned char *
json_skip_space(const unsigned char * uc,const unsigned char * ue)124006f8008Schristos json_skip_space(const unsigned char *uc, const unsigned char *ue)
125006f8008Schristos {
126006f8008Schristos while (uc < ue && json_isspace(*uc))
127006f8008Schristos uc++;
128006f8008Schristos return uc;
129006f8008Schristos }
130006f8008Schristos
1311d4cb158Schristos /*ARGSUSED*/
132006f8008Schristos static int
json_parse_string(const unsigned char ** ucp,const unsigned char * ue,size_t lvl __file_debugused)1331d4cb158Schristos json_parse_string(const unsigned char **ucp, const unsigned char *ue,
1341d4cb158Schristos size_t lvl __file_debugused)
135006f8008Schristos {
136006f8008Schristos const unsigned char *uc = *ucp;
137006f8008Schristos size_t i;
138006f8008Schristos
139006f8008Schristos DPRINTF("Parse string: ", uc, *ucp);
140006f8008Schristos while (uc < ue) {
141006f8008Schristos switch (*uc++) {
142006f8008Schristos case '\0':
143006f8008Schristos goto out;
144006f8008Schristos case '\\':
145006f8008Schristos if (uc == ue)
146006f8008Schristos goto out;
147006f8008Schristos switch (*uc++) {
148006f8008Schristos case '\0':
149006f8008Schristos goto out;
150006f8008Schristos case '"':
151006f8008Schristos case '\\':
152006f8008Schristos case '/':
153006f8008Schristos case 'b':
154006f8008Schristos case 'f':
155006f8008Schristos case 'n':
156006f8008Schristos case 'r':
157006f8008Schristos case 't':
158006f8008Schristos continue;
159006f8008Schristos case 'u':
160006f8008Schristos if (ue - uc < 4) {
161006f8008Schristos uc = ue;
162006f8008Schristos goto out;
163006f8008Schristos }
164006f8008Schristos for (i = 0; i < 4; i++)
165006f8008Schristos if (!json_isxdigit(*uc++))
166006f8008Schristos goto out;
167006f8008Schristos continue;
168006f8008Schristos default:
169006f8008Schristos goto out;
170006f8008Schristos }
171006f8008Schristos case '"':
17229faeba7Schristos DPRINTF("Good string: ", uc, *ucp);
1731d4cb158Schristos *ucp = uc;
174006f8008Schristos return 1;
175006f8008Schristos default:
176006f8008Schristos continue;
177006f8008Schristos }
178006f8008Schristos }
179006f8008Schristos out:
180006f8008Schristos DPRINTF("Bad string: ", uc, *ucp);
181006f8008Schristos *ucp = uc;
182006f8008Schristos return 0;
183006f8008Schristos }
184006f8008Schristos
185006f8008Schristos static int
json_parse_array(const unsigned char ** ucp,const unsigned char * ue,size_t * st,size_t lvl)186006f8008Schristos json_parse_array(const unsigned char **ucp, const unsigned char *ue,
187006f8008Schristos size_t *st, size_t lvl)
188006f8008Schristos {
189006f8008Schristos const unsigned char *uc = *ucp;
190006f8008Schristos
191006f8008Schristos DPRINTF("Parse array: ", uc, *ucp);
192006f8008Schristos while (uc < ue) {
1931d4cb158Schristos uc = json_skip_space(uc, ue);
1941d4cb158Schristos if (uc == ue)
1951d4cb158Schristos goto out;
19629faeba7Schristos if (*uc == ']')
19729faeba7Schristos goto done;
198006f8008Schristos if (!json_parse(&uc, ue, st, lvl + 1))
199006f8008Schristos goto out;
200006f8008Schristos if (uc == ue)
201006f8008Schristos goto out;
202006f8008Schristos switch (*uc) {
203006f8008Schristos case ',':
204006f8008Schristos uc++;
205006f8008Schristos continue;
206006f8008Schristos case ']':
20729faeba7Schristos done:
208d0c65b7bSchristos st[JSON_ARRAYN]++;
20929faeba7Schristos DPRINTF("Good array: ", uc, *ucp);
2101d4cb158Schristos *ucp = uc + 1;
211006f8008Schristos return 1;
212006f8008Schristos default:
213006f8008Schristos goto out;
214006f8008Schristos }
215006f8008Schristos }
216006f8008Schristos out:
217006f8008Schristos DPRINTF("Bad array: ", uc, *ucp);
218006f8008Schristos *ucp = uc;
219006f8008Schristos return 0;
220006f8008Schristos }
221006f8008Schristos
222006f8008Schristos static int
json_parse_object(const unsigned char ** ucp,const unsigned char * ue,size_t * st,size_t lvl)223006f8008Schristos json_parse_object(const unsigned char **ucp, const unsigned char *ue,
224006f8008Schristos size_t *st, size_t lvl)
225006f8008Schristos {
226006f8008Schristos const unsigned char *uc = *ucp;
227006f8008Schristos DPRINTF("Parse object: ", uc, *ucp);
228006f8008Schristos while (uc < ue) {
229006f8008Schristos uc = json_skip_space(uc, ue);
230006f8008Schristos if (uc == ue)
231006f8008Schristos goto out;
23229faeba7Schristos if (*uc == '}') {
23329faeba7Schristos uc++;
23429faeba7Schristos goto done;
23529faeba7Schristos }
236006f8008Schristos if (*uc++ != '"') {
237006f8008Schristos DPRINTF("not string", uc, *ucp);
238006f8008Schristos goto out;
239006f8008Schristos }
240006f8008Schristos DPRINTF("next field", uc, *ucp);
2411d4cb158Schristos if (!json_parse_string(&uc, ue, lvl)) {
242006f8008Schristos DPRINTF("not string", uc, *ucp);
243006f8008Schristos goto out;
244006f8008Schristos }
245006f8008Schristos uc = json_skip_space(uc, ue);
246006f8008Schristos if (uc == ue)
247006f8008Schristos goto out;
248006f8008Schristos if (*uc++ != ':') {
249006f8008Schristos DPRINTF("not colon", uc, *ucp);
250006f8008Schristos goto out;
251006f8008Schristos }
252006f8008Schristos if (!json_parse(&uc, ue, st, lvl + 1)) {
253006f8008Schristos DPRINTF("not json", uc, *ucp);
254006f8008Schristos goto out;
255006f8008Schristos }
256006f8008Schristos if (uc == ue)
257006f8008Schristos goto out;
258006f8008Schristos switch (*uc++) {
259006f8008Schristos case ',':
260006f8008Schristos continue;
261006f8008Schristos case '}': /* { */
26229faeba7Schristos done:
263006f8008Schristos DPRINTF("Good object: ", uc, *ucp);
2641d4cb158Schristos *ucp = uc;
265006f8008Schristos return 1;
266006f8008Schristos default:
267006f8008Schristos DPRINTF("not more", uc, *ucp);
2681d4cb158Schristos *ucp = uc - 1;
269006f8008Schristos goto out;
270006f8008Schristos }
271006f8008Schristos }
272006f8008Schristos out:
273006f8008Schristos DPRINTF("Bad object: ", uc, *ucp);
274006f8008Schristos *ucp = uc;
275006f8008Schristos return 0;
276006f8008Schristos }
277006f8008Schristos
2781d4cb158Schristos /*ARGSUSED*/
279006f8008Schristos static int
json_parse_number(const unsigned char ** ucp,const unsigned char * ue,size_t lvl __file_debugused)2801d4cb158Schristos json_parse_number(const unsigned char **ucp, const unsigned char *ue,
2811d4cb158Schristos size_t lvl __file_debugused)
282006f8008Schristos {
283006f8008Schristos const unsigned char *uc = *ucp;
284006f8008Schristos int got = 0;
285006f8008Schristos
286006f8008Schristos DPRINTF("Parse number: ", uc, *ucp);
287006f8008Schristos if (uc == ue)
288006f8008Schristos return 0;
289006f8008Schristos if (*uc == '-')
290006f8008Schristos uc++;
291006f8008Schristos
292006f8008Schristos for (; uc < ue; uc++) {
293006f8008Schristos if (!json_isdigit(*uc))
294006f8008Schristos break;
295006f8008Schristos got = 1;
296006f8008Schristos }
297006f8008Schristos if (uc == ue)
298006f8008Schristos goto out;
299006f8008Schristos if (*uc == '.')
300006f8008Schristos uc++;
301006f8008Schristos for (; uc < ue; uc++) {
302006f8008Schristos if (!json_isdigit(*uc))
303006f8008Schristos break;
304006f8008Schristos got = 1;
305006f8008Schristos }
306006f8008Schristos if (uc == ue)
307006f8008Schristos goto out;
308006f8008Schristos if (got && (*uc == 'e' || *uc == 'E')) {
309006f8008Schristos uc++;
310006f8008Schristos got = 0;
311006f8008Schristos if (uc == ue)
312006f8008Schristos goto out;
313006f8008Schristos if (*uc == '+' || *uc == '-')
314006f8008Schristos uc++;
315006f8008Schristos for (; uc < ue; uc++) {
316006f8008Schristos if (!json_isdigit(*uc))
317006f8008Schristos break;
318006f8008Schristos got = 1;
319006f8008Schristos }
320006f8008Schristos }
321006f8008Schristos out:
322006f8008Schristos if (!got)
323006f8008Schristos DPRINTF("Bad number: ", uc, *ucp);
324006f8008Schristos else
325006f8008Schristos DPRINTF("Good number: ", uc, *ucp);
326006f8008Schristos *ucp = uc;
327006f8008Schristos return got;
328006f8008Schristos }
329006f8008Schristos
3301d4cb158Schristos /*ARGSUSED*/
331006f8008Schristos static int
json_parse_const(const unsigned char ** ucp,const unsigned char * ue,const char * str,size_t len,size_t lvl __file_debugused)332006f8008Schristos json_parse_const(const unsigned char **ucp, const unsigned char *ue,
3331d4cb158Schristos const char *str, size_t len, size_t lvl __file_debugused)
334006f8008Schristos {
335006f8008Schristos const unsigned char *uc = *ucp;
336006f8008Schristos
337006f8008Schristos DPRINTF("Parse const: ", uc, *ucp);
3381d4cb158Schristos *ucp += --len - 1;
3391d4cb158Schristos if (*ucp > ue)
3401d4cb158Schristos *ucp = ue;
3411d4cb158Schristos for (; uc < ue && --len;) {
3421d4cb158Schristos if (*uc++ != *++str) {
343006f8008Schristos DPRINTF("Bad const: ", uc, *ucp);
3441d4cb158Schristos return 0;
3451d4cb158Schristos }
3461d4cb158Schristos }
3471d4cb158Schristos DPRINTF("Good const: ", uc, *ucp);
3481d4cb158Schristos return 1;
349006f8008Schristos }
350006f8008Schristos
351006f8008Schristos static int
json_parse(const unsigned char ** ucp,const unsigned char * ue,size_t * st,size_t lvl)352006f8008Schristos json_parse(const unsigned char **ucp, const unsigned char *ue,
353006f8008Schristos size_t *st, size_t lvl)
354006f8008Schristos {
3551d4cb158Schristos const unsigned char *uc, *ouc;
356006f8008Schristos int rv = 0;
357006f8008Schristos int t;
358006f8008Schristos
3591d4cb158Schristos ouc = uc = json_skip_space(*ucp, ue);
360006f8008Schristos if (uc == ue)
361006f8008Schristos goto out;
362006f8008Schristos
363006f8008Schristos // Avoid recursion
3641d4cb158Schristos if (lvl > 500) {
3651d4cb158Schristos DPRINTF("Too many levels", uc, *ucp);
366006f8008Schristos return 0;
3671d4cb158Schristos }
368006f8008Schristos #if JSON_COUNT
369006f8008Schristos /* bail quickly if not counting */
370d0c65b7bSchristos if (lvl > 1 && (st[JSON_OBJECT] || st[JSON_ARRAYN]))
371006f8008Schristos return 1;
372006f8008Schristos #endif
373006f8008Schristos
374006f8008Schristos DPRINTF("Parse general: ", uc, *ucp);
375006f8008Schristos switch (*uc++) {
376006f8008Schristos case '"':
3771d4cb158Schristos rv = json_parse_string(&uc, ue, lvl + 1);
378006f8008Schristos t = JSON_STRING;
379006f8008Schristos break;
380006f8008Schristos case '[':
381006f8008Schristos rv = json_parse_array(&uc, ue, st, lvl + 1);
382006f8008Schristos t = JSON_ARRAY;
383006f8008Schristos break;
384006f8008Schristos case '{': /* '}' */
385006f8008Schristos rv = json_parse_object(&uc, ue, st, lvl + 1);
386006f8008Schristos t = JSON_OBJECT;
387006f8008Schristos break;
388006f8008Schristos case 't':
3891d4cb158Schristos rv = json_parse_const(&uc, ue, "true", sizeof("true"), lvl + 1);
390006f8008Schristos t = JSON_CONSTANT;
391006f8008Schristos break;
392006f8008Schristos case 'f':
3931d4cb158Schristos rv = json_parse_const(&uc, ue, "false", sizeof("false"),
3941d4cb158Schristos lvl + 1);
395006f8008Schristos t = JSON_CONSTANT;
396006f8008Schristos break;
397006f8008Schristos case 'n':
3981d4cb158Schristos rv = json_parse_const(&uc, ue, "null", sizeof("null"), lvl + 1);
399006f8008Schristos t = JSON_CONSTANT;
400006f8008Schristos break;
401006f8008Schristos default:
402006f8008Schristos --uc;
4031d4cb158Schristos rv = json_parse_number(&uc, ue, lvl + 1);
404006f8008Schristos t = JSON_NUMBER;
405006f8008Schristos break;
406006f8008Schristos }
407006f8008Schristos if (rv)
408006f8008Schristos st[t]++;
409006f8008Schristos uc = json_skip_space(uc, ue);
410006f8008Schristos out:
411006f8008Schristos DPRINTF("End general: ", uc, *ucp);
4121d4cb158Schristos *ucp = uc;
4131d4cb158Schristos if (lvl == 0) {
4141d4cb158Schristos if (!rv)
4151d4cb158Schristos return 0;
4161d4cb158Schristos if (uc == ue)
4171d4cb158Schristos return (st[JSON_ARRAYN] || st[JSON_OBJECT]) ? 1 : 0;
4181d4cb158Schristos if (*ouc == *uc && json_parse(&uc, ue, st, 1))
4191d4cb158Schristos return (st[JSON_ARRAYN] || st[JSON_OBJECT]) ? 2 : 0;
4201d4cb158Schristos else
4211d4cb158Schristos return 0;
4221d4cb158Schristos }
423006f8008Schristos return rv;
424006f8008Schristos }
425006f8008Schristos
426006f8008Schristos #ifndef TEST
427006f8008Schristos int
file_is_json(struct magic_set * ms,const struct buffer * b)428006f8008Schristos file_is_json(struct magic_set *ms, const struct buffer *b)
429006f8008Schristos {
430006f8008Schristos const unsigned char *uc = CAST(const unsigned char *, b->fbuf);
431006f8008Schristos const unsigned char *ue = uc + b->flen;
432006f8008Schristos size_t st[JSON_MAX];
433006f8008Schristos int mime = ms->flags & MAGIC_MIME;
4341d4cb158Schristos int jt;
435006f8008Schristos
436006f8008Schristos
437006f8008Schristos if ((ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION)) != 0)
438006f8008Schristos return 0;
439006f8008Schristos
440006f8008Schristos memset(st, 0, sizeof(st));
441006f8008Schristos
4421d4cb158Schristos if ((jt = json_parse(&uc, ue, st, 0)) == 0)
443006f8008Schristos return 0;
444006f8008Schristos
445006f8008Schristos if (mime == MAGIC_MIME_ENCODING)
446006f8008Schristos return 1;
447006f8008Schristos if (mime) {
4481d4cb158Schristos if (file_printf(ms, "application/%s",
449*ddb17682Schristos jt == 1 ? "json" : "x-ndjson") == -1)
450006f8008Schristos return -1;
451006f8008Schristos return 1;
452006f8008Schristos }
4531d4cb158Schristos if (file_printf(ms, "%sJSON text data",
4541d4cb158Schristos jt == 1 ? "" : "New Line Delimited ") == -1)
455006f8008Schristos return -1;
456006f8008Schristos #if JSON_COUNT
457006f8008Schristos #define P(n) st[n], st[n] > 1 ? "s" : ""
458006f8008Schristos if (file_printf(ms, " (%" SIZE_T_FORMAT "u object%s, %" SIZE_T_FORMAT
459006f8008Schristos "u array%s, %" SIZE_T_FORMAT "u string%s, %" SIZE_T_FORMAT
460d0c65b7bSchristos "u constant%s, %" SIZE_T_FORMAT "u number%s, %" SIZE_T_FORMAT
461d0c65b7bSchristos "u >1array%s)",
462d0c65b7bSchristos P(JSON_OBJECT), P(JSON_ARRAY), P(JSON_STRING), P(JSON_CONSTANT),
463d0c65b7bSchristos P(JSON_NUMBER), P(JSON_ARRAYN))
464006f8008Schristos == -1)
465006f8008Schristos return -1;
466006f8008Schristos #endif
467006f8008Schristos return 1;
468006f8008Schristos }
469006f8008Schristos
470006f8008Schristos #else
471006f8008Schristos
472006f8008Schristos #include <sys/types.h>
473006f8008Schristos #include <sys/stat.h>
474006f8008Schristos #include <stdio.h>
475006f8008Schristos #include <fcntl.h>
476006f8008Schristos #include <unistd.h>
477006f8008Schristos #include <stdlib.h>
478006f8008Schristos #include <stdint.h>
479006f8008Schristos #include <err.h>
480006f8008Schristos
481006f8008Schristos int
main(int argc,char * argv[])482006f8008Schristos main(int argc, char *argv[])
483006f8008Schristos {
4841d4cb158Schristos int fd;
485006f8008Schristos struct stat st;
486006f8008Schristos unsigned char *p;
487006f8008Schristos size_t stats[JSON_MAX];
488006f8008Schristos
489006f8008Schristos if ((fd = open(argv[1], O_RDONLY)) == -1)
490006f8008Schristos err(EXIT_FAILURE, "Can't open `%s'", argv[1]);
491006f8008Schristos
492006f8008Schristos if (fstat(fd, &st) == -1)
493006f8008Schristos err(EXIT_FAILURE, "Can't stat `%s'", argv[1]);
494006f8008Schristos
4951d4cb158Schristos if ((p = CAST(char *, malloc(st.st_size))) == NULL)
496006f8008Schristos err(EXIT_FAILURE, "Can't allocate %jd bytes",
497006f8008Schristos (intmax_t)st.st_size);
498006f8008Schristos if (read(fd, p, st.st_size) != st.st_size)
499006f8008Schristos err(EXIT_FAILURE, "Can't read %jd bytes",
500006f8008Schristos (intmax_t)st.st_size);
501006f8008Schristos memset(stats, 0, sizeof(stats));
502006f8008Schristos printf("is json %d\n", json_parse((const unsigned char **)&p,
503006f8008Schristos p + st.st_size, stats, 0));
504006f8008Schristos return 0;
505006f8008Schristos }
506006f8008Schristos #endif
507