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*898496eeSXin LI FILE_RCSID("@(#)$File: is_json.c,v 1.30 2022/09/27 19:12:40 christos Exp $")
3648c779cdSXin LI #endif
3748c779cdSXin LI
3848c779cdSXin LI #include "magic.h"
39a4d6d3b8SXin LI #else
40a4d6d3b8SXin LI #include <stdio.h>
41a4d6d3b8SXin LI #include <stddef.h>
4248c779cdSXin LI #endif
43a4d6d3b8SXin LI #include <string.h>
4448c779cdSXin LI
4548c779cdSXin LI #ifdef DEBUG
4648c779cdSXin LI #include <stdio.h>
4748c779cdSXin LI #define DPRINTF(a, b, c) \
48a4d6d3b8SXin LI printf("%*s%s [%.2x/%c] %.*s\n", (int)lvl, "", (a), *(b), *(b), \
49a4d6d3b8SXin LI (int)(b - c), (const char *)(c))
50a4d6d3b8SXin LI #define __file_debugused
5148c779cdSXin LI #else
5248c779cdSXin LI #define DPRINTF(a, b, c) do { } while (/*CONSTCOND*/0)
53a4d6d3b8SXin 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
json_isspace(const unsigned char uc)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
json_isdigit(unsigned char uc)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
json_isxdigit(unsigned char uc)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 *
json_skip_space(const unsigned char * uc,const unsigned char * ue)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
125a2dfb722SXin LI /*ARGSUSED*/
12648c779cdSXin LI static int
json_parse_string(const unsigned char ** ucp,const unsigned char * ue,size_t lvl __file_debugused)127a4d6d3b8SXin LI json_parse_string(const unsigned char **ucp, const unsigned char *ue,
128a4d6d3b8SXin LI size_t lvl __file_debugused)
12948c779cdSXin LI {
13048c779cdSXin LI const unsigned char *uc = *ucp;
13148c779cdSXin LI size_t i;
13248c779cdSXin LI
13348c779cdSXin LI DPRINTF("Parse string: ", uc, *ucp);
13448c779cdSXin LI while (uc < ue) {
13548c779cdSXin LI switch (*uc++) {
13648c779cdSXin LI case '\0':
13748c779cdSXin LI goto out;
13848c779cdSXin LI case '\\':
13948c779cdSXin LI if (uc == ue)
14048c779cdSXin LI goto out;
14148c779cdSXin LI switch (*uc++) {
14248c779cdSXin LI case '\0':
14348c779cdSXin LI goto out;
14448c779cdSXin LI case '"':
14548c779cdSXin LI case '\\':
14648c779cdSXin LI case '/':
14748c779cdSXin LI case 'b':
14848c779cdSXin LI case 'f':
14948c779cdSXin LI case 'n':
15048c779cdSXin LI case 'r':
15148c779cdSXin LI case 't':
15248c779cdSXin LI continue;
15348c779cdSXin LI case 'u':
15448c779cdSXin LI if (ue - uc < 4) {
15548c779cdSXin LI uc = ue;
15648c779cdSXin LI goto out;
15748c779cdSXin LI }
15848c779cdSXin LI for (i = 0; i < 4; i++)
15948c779cdSXin LI if (!json_isxdigit(*uc++))
16048c779cdSXin LI goto out;
16148c779cdSXin LI continue;
16248c779cdSXin LI default:
16348c779cdSXin LI goto out;
16448c779cdSXin LI }
16548c779cdSXin LI case '"':
1662726a701SXin LI DPRINTF("Good string: ", uc, *ucp);
167a4d6d3b8SXin LI *ucp = uc;
16848c779cdSXin LI return 1;
16948c779cdSXin LI default:
17048c779cdSXin LI continue;
17148c779cdSXin LI }
17248c779cdSXin LI }
17348c779cdSXin LI out:
17448c779cdSXin LI DPRINTF("Bad string: ", uc, *ucp);
17548c779cdSXin LI *ucp = uc;
17648c779cdSXin LI return 0;
17748c779cdSXin LI }
17848c779cdSXin LI
17948c779cdSXin LI static int
json_parse_array(const unsigned char ** ucp,const unsigned char * ue,size_t * st,size_t lvl)18048c779cdSXin LI json_parse_array(const unsigned char **ucp, const unsigned char *ue,
18148c779cdSXin LI size_t *st, size_t lvl)
18248c779cdSXin LI {
18348c779cdSXin LI const unsigned char *uc = *ucp;
18448c779cdSXin LI
18548c779cdSXin LI DPRINTF("Parse array: ", uc, *ucp);
18648c779cdSXin LI while (uc < ue) {
187a2dfb722SXin LI uc = json_skip_space(uc, ue);
188a2dfb722SXin LI if (uc == ue)
189a2dfb722SXin LI goto out;
1902726a701SXin LI if (*uc == ']')
1912726a701SXin LI goto done;
19248c779cdSXin LI if (!json_parse(&uc, ue, st, lvl + 1))
19348c779cdSXin LI goto out;
19448c779cdSXin LI if (uc == ue)
19548c779cdSXin LI goto out;
19648c779cdSXin LI switch (*uc) {
19748c779cdSXin LI case ',':
19848c779cdSXin LI uc++;
19948c779cdSXin LI continue;
20048c779cdSXin LI case ']':
2012726a701SXin LI done:
20248c779cdSXin LI st[JSON_ARRAYN]++;
2032726a701SXin LI DPRINTF("Good array: ", uc, *ucp);
204a4d6d3b8SXin LI *ucp = uc + 1;
20548c779cdSXin LI return 1;
20648c779cdSXin LI default:
20748c779cdSXin LI goto out;
20848c779cdSXin LI }
20948c779cdSXin LI }
21048c779cdSXin LI out:
21148c779cdSXin LI DPRINTF("Bad array: ", uc, *ucp);
21248c779cdSXin LI *ucp = uc;
21348c779cdSXin LI return 0;
21448c779cdSXin LI }
21548c779cdSXin LI
21648c779cdSXin LI static int
json_parse_object(const unsigned char ** ucp,const unsigned char * ue,size_t * st,size_t lvl)21748c779cdSXin LI json_parse_object(const unsigned char **ucp, const unsigned char *ue,
21848c779cdSXin LI size_t *st, size_t lvl)
21948c779cdSXin LI {
22048c779cdSXin LI const unsigned char *uc = *ucp;
22148c779cdSXin LI DPRINTF("Parse object: ", uc, *ucp);
22248c779cdSXin LI while (uc < ue) {
22348c779cdSXin LI uc = json_skip_space(uc, ue);
22448c779cdSXin LI if (uc == ue)
22548c779cdSXin LI goto out;
2262726a701SXin LI if (*uc == '}') {
2272726a701SXin LI uc++;
2282726a701SXin LI goto done;
2292726a701SXin LI }
23048c779cdSXin LI if (*uc++ != '"') {
23148c779cdSXin LI DPRINTF("not string", uc, *ucp);
23248c779cdSXin LI goto out;
23348c779cdSXin LI }
23448c779cdSXin LI DPRINTF("next field", uc, *ucp);
235a4d6d3b8SXin LI if (!json_parse_string(&uc, ue, lvl)) {
23648c779cdSXin LI DPRINTF("not string", uc, *ucp);
23748c779cdSXin LI goto out;
23848c779cdSXin LI }
23948c779cdSXin LI uc = json_skip_space(uc, ue);
24048c779cdSXin LI if (uc == ue)
24148c779cdSXin LI goto out;
24248c779cdSXin LI if (*uc++ != ':') {
24348c779cdSXin LI DPRINTF("not colon", uc, *ucp);
24448c779cdSXin LI goto out;
24548c779cdSXin LI }
24648c779cdSXin LI if (!json_parse(&uc, ue, st, lvl + 1)) {
24748c779cdSXin LI DPRINTF("not json", uc, *ucp);
24848c779cdSXin LI goto out;
24948c779cdSXin LI }
25048c779cdSXin LI if (uc == ue)
25148c779cdSXin LI goto out;
25248c779cdSXin LI switch (*uc++) {
25348c779cdSXin LI case ',':
25448c779cdSXin LI continue;
25548c779cdSXin LI case '}': /* { */
2562726a701SXin LI done:
25748c779cdSXin LI DPRINTF("Good object: ", uc, *ucp);
258a4d6d3b8SXin LI *ucp = uc;
25948c779cdSXin LI return 1;
26048c779cdSXin LI default:
26148c779cdSXin LI DPRINTF("not more", uc, *ucp);
262a4d6d3b8SXin LI *ucp = uc - 1;
26348c779cdSXin LI goto out;
26448c779cdSXin LI }
26548c779cdSXin LI }
26648c779cdSXin LI out:
26748c779cdSXin LI DPRINTF("Bad object: ", uc, *ucp);
26848c779cdSXin LI *ucp = uc;
26948c779cdSXin LI return 0;
27048c779cdSXin LI }
27148c779cdSXin LI
272a2dfb722SXin LI /*ARGSUSED*/
27348c779cdSXin LI static int
json_parse_number(const unsigned char ** ucp,const unsigned char * ue,size_t lvl __file_debugused)274a4d6d3b8SXin LI json_parse_number(const unsigned char **ucp, const unsigned char *ue,
275a4d6d3b8SXin LI size_t lvl __file_debugused)
27648c779cdSXin LI {
27748c779cdSXin LI const unsigned char *uc = *ucp;
27848c779cdSXin LI int got = 0;
27948c779cdSXin LI
28048c779cdSXin LI DPRINTF("Parse number: ", uc, *ucp);
28148c779cdSXin LI if (uc == ue)
28248c779cdSXin LI return 0;
28348c779cdSXin LI if (*uc == '-')
28448c779cdSXin LI uc++;
28548c779cdSXin LI
28648c779cdSXin LI for (; uc < ue; uc++) {
28748c779cdSXin LI if (!json_isdigit(*uc))
28848c779cdSXin LI break;
28948c779cdSXin LI got = 1;
29048c779cdSXin LI }
29148c779cdSXin LI if (uc == ue)
29248c779cdSXin LI goto out;
29348c779cdSXin LI if (*uc == '.')
29448c779cdSXin LI uc++;
29548c779cdSXin LI for (; uc < ue; uc++) {
29648c779cdSXin LI if (!json_isdigit(*uc))
29748c779cdSXin LI break;
29848c779cdSXin LI got = 1;
29948c779cdSXin LI }
30048c779cdSXin LI if (uc == ue)
30148c779cdSXin LI goto out;
30248c779cdSXin LI if (got && (*uc == 'e' || *uc == 'E')) {
30348c779cdSXin LI uc++;
30448c779cdSXin LI got = 0;
30548c779cdSXin LI if (uc == ue)
30648c779cdSXin LI goto out;
30748c779cdSXin LI if (*uc == '+' || *uc == '-')
30848c779cdSXin LI uc++;
30948c779cdSXin LI for (; uc < ue; uc++) {
31048c779cdSXin LI if (!json_isdigit(*uc))
31148c779cdSXin LI break;
31248c779cdSXin LI got = 1;
31348c779cdSXin LI }
31448c779cdSXin LI }
31548c779cdSXin LI out:
31648c779cdSXin LI if (!got)
31748c779cdSXin LI DPRINTF("Bad number: ", uc, *ucp);
31848c779cdSXin LI else
31948c779cdSXin LI DPRINTF("Good number: ", uc, *ucp);
32048c779cdSXin LI *ucp = uc;
32148c779cdSXin LI return got;
32248c779cdSXin LI }
32348c779cdSXin LI
324a2dfb722SXin LI /*ARGSUSED*/
32548c779cdSXin LI static int
json_parse_const(const unsigned char ** ucp,const unsigned char * ue,const char * str,size_t len,size_t lvl __file_debugused)32648c779cdSXin LI json_parse_const(const unsigned char **ucp, const unsigned char *ue,
327a4d6d3b8SXin LI const char *str, size_t len, size_t lvl __file_debugused)
32848c779cdSXin LI {
32948c779cdSXin LI const unsigned char *uc = *ucp;
33048c779cdSXin LI
33148c779cdSXin LI DPRINTF("Parse const: ", uc, *ucp);
332a2dfb722SXin LI *ucp += --len - 1;
333a2dfb722SXin LI if (*ucp > ue)
334a2dfb722SXin LI *ucp = ue;
335a2dfb722SXin LI for (; uc < ue && --len;) {
336a2dfb722SXin LI if (*uc++ != *++str) {
33748c779cdSXin LI DPRINTF("Bad const: ", uc, *ucp);
338a2dfb722SXin LI return 0;
339a2dfb722SXin LI }
340a2dfb722SXin LI }
341a2dfb722SXin LI DPRINTF("Good const: ", uc, *ucp);
342a2dfb722SXin LI return 1;
34348c779cdSXin LI }
34448c779cdSXin LI
34548c779cdSXin LI static int
json_parse(const unsigned char ** ucp,const unsigned char * ue,size_t * st,size_t lvl)34648c779cdSXin LI json_parse(const unsigned char **ucp, const unsigned char *ue,
34748c779cdSXin LI size_t *st, size_t lvl)
34848c779cdSXin LI {
349a2dfb722SXin LI const unsigned char *uc, *ouc;
35048c779cdSXin LI int rv = 0;
35148c779cdSXin LI int t;
35248c779cdSXin LI
353a2dfb722SXin LI ouc = uc = json_skip_space(*ucp, ue);
35448c779cdSXin LI if (uc == ue)
35548c779cdSXin LI goto out;
35648c779cdSXin LI
35748c779cdSXin LI // Avoid recursion
358a4d6d3b8SXin LI if (lvl > 500) {
359a4d6d3b8SXin LI DPRINTF("Too many levels", uc, *ucp);
36048c779cdSXin LI return 0;
361a4d6d3b8SXin LI }
36248c779cdSXin LI #if JSON_COUNT
36348c779cdSXin LI /* bail quickly if not counting */
36448c779cdSXin LI if (lvl > 1 && (st[JSON_OBJECT] || st[JSON_ARRAYN]))
36548c779cdSXin LI return 1;
36648c779cdSXin LI #endif
36748c779cdSXin LI
36848c779cdSXin LI DPRINTF("Parse general: ", uc, *ucp);
36948c779cdSXin LI switch (*uc++) {
37048c779cdSXin LI case '"':
371a4d6d3b8SXin LI rv = json_parse_string(&uc, ue, lvl + 1);
37248c779cdSXin LI t = JSON_STRING;
37348c779cdSXin LI break;
37448c779cdSXin LI case '[':
37548c779cdSXin LI rv = json_parse_array(&uc, ue, st, lvl + 1);
37648c779cdSXin LI t = JSON_ARRAY;
37748c779cdSXin LI break;
37848c779cdSXin LI case '{': /* '}' */
37948c779cdSXin LI rv = json_parse_object(&uc, ue, st, lvl + 1);
38048c779cdSXin LI t = JSON_OBJECT;
38148c779cdSXin LI break;
38248c779cdSXin LI case 't':
383a4d6d3b8SXin LI rv = json_parse_const(&uc, ue, "true", sizeof("true"), lvl + 1);
38448c779cdSXin LI t = JSON_CONSTANT;
38548c779cdSXin LI break;
38648c779cdSXin LI case 'f':
387a4d6d3b8SXin LI rv = json_parse_const(&uc, ue, "false", sizeof("false"),
388a4d6d3b8SXin LI lvl + 1);
38948c779cdSXin LI t = JSON_CONSTANT;
39048c779cdSXin LI break;
39148c779cdSXin LI case 'n':
392a4d6d3b8SXin LI rv = json_parse_const(&uc, ue, "null", sizeof("null"), lvl + 1);
39348c779cdSXin LI t = JSON_CONSTANT;
39448c779cdSXin LI break;
39548c779cdSXin LI default:
39648c779cdSXin LI --uc;
397a4d6d3b8SXin LI rv = json_parse_number(&uc, ue, lvl + 1);
39848c779cdSXin LI t = JSON_NUMBER;
39948c779cdSXin LI break;
40048c779cdSXin LI }
40148c779cdSXin LI if (rv)
40248c779cdSXin LI st[t]++;
40348c779cdSXin LI uc = json_skip_space(uc, ue);
40448c779cdSXin LI out:
40548c779cdSXin LI DPRINTF("End general: ", uc, *ucp);
406a4d6d3b8SXin LI *ucp = uc;
407a2dfb722SXin LI if (lvl == 0) {
408a2dfb722SXin LI if (!rv)
409a2dfb722SXin LI return 0;
410a2dfb722SXin LI if (uc == ue)
411a2dfb722SXin LI return (st[JSON_ARRAYN] || st[JSON_OBJECT]) ? 1 : 0;
412a2dfb722SXin LI if (*ouc == *uc && json_parse(&uc, ue, st, 1))
413a2dfb722SXin LI return (st[JSON_ARRAYN] || st[JSON_OBJECT]) ? 2 : 0;
414a2dfb722SXin LI else
415a2dfb722SXin LI return 0;
416a2dfb722SXin LI }
41748c779cdSXin LI return rv;
41848c779cdSXin LI }
41948c779cdSXin LI
42048c779cdSXin LI #ifndef TEST
42148c779cdSXin LI int
file_is_json(struct magic_set * ms,const struct buffer * b)42248c779cdSXin LI file_is_json(struct magic_set *ms, const struct buffer *b)
42348c779cdSXin LI {
42448c779cdSXin LI const unsigned char *uc = CAST(const unsigned char *, b->fbuf);
42548c779cdSXin LI const unsigned char *ue = uc + b->flen;
42648c779cdSXin LI size_t st[JSON_MAX];
42748c779cdSXin LI int mime = ms->flags & MAGIC_MIME;
428a2dfb722SXin LI int jt;
42948c779cdSXin LI
43048c779cdSXin LI
43148c779cdSXin LI if ((ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION)) != 0)
43248c779cdSXin LI return 0;
43348c779cdSXin LI
43448c779cdSXin LI memset(st, 0, sizeof(st));
43548c779cdSXin LI
436a2dfb722SXin LI if ((jt = json_parse(&uc, ue, st, 0)) == 0)
43748c779cdSXin LI return 0;
43848c779cdSXin LI
43948c779cdSXin LI if (mime == MAGIC_MIME_ENCODING)
44048c779cdSXin LI return 1;
44148c779cdSXin LI if (mime) {
442a2dfb722SXin LI if (file_printf(ms, "application/%s",
443*898496eeSXin LI jt == 1 ? "json" : "x-ndjson") == -1)
44448c779cdSXin LI return -1;
44548c779cdSXin LI return 1;
44648c779cdSXin LI }
447a2dfb722SXin LI if (file_printf(ms, "%sJSON text data",
448a2dfb722SXin LI jt == 1 ? "" : "New Line Delimited ") == -1)
44948c779cdSXin LI return -1;
45048c779cdSXin LI #if JSON_COUNT
45148c779cdSXin LI #define P(n) st[n], st[n] > 1 ? "s" : ""
45248c779cdSXin LI if (file_printf(ms, " (%" SIZE_T_FORMAT "u object%s, %" SIZE_T_FORMAT
45348c779cdSXin LI "u array%s, %" SIZE_T_FORMAT "u string%s, %" SIZE_T_FORMAT
45448c779cdSXin LI "u constant%s, %" SIZE_T_FORMAT "u number%s, %" SIZE_T_FORMAT
45548c779cdSXin LI "u >1array%s)",
45648c779cdSXin LI P(JSON_OBJECT), P(JSON_ARRAY), P(JSON_STRING), P(JSON_CONSTANT),
45748c779cdSXin LI P(JSON_NUMBER), P(JSON_ARRAYN))
45848c779cdSXin LI == -1)
45948c779cdSXin LI return -1;
46048c779cdSXin LI #endif
46148c779cdSXin LI return 1;
46248c779cdSXin LI }
46348c779cdSXin LI
46448c779cdSXin LI #else
46548c779cdSXin LI
46648c779cdSXin LI #include <sys/types.h>
46748c779cdSXin LI #include <sys/stat.h>
46848c779cdSXin LI #include <stdio.h>
46948c779cdSXin LI #include <fcntl.h>
47048c779cdSXin LI #include <unistd.h>
47148c779cdSXin LI #include <stdlib.h>
47248c779cdSXin LI #include <stdint.h>
47348c779cdSXin LI #include <err.h>
47448c779cdSXin LI
47548c779cdSXin LI int
main(int argc,char * argv[])47648c779cdSXin LI main(int argc, char *argv[])
47748c779cdSXin LI {
478*898496eeSXin LI int fd;
47948c779cdSXin LI struct stat st;
48048c779cdSXin LI unsigned char *p;
48148c779cdSXin LI size_t stats[JSON_MAX];
48248c779cdSXin LI
48348c779cdSXin LI if ((fd = open(argv[1], O_RDONLY)) == -1)
48448c779cdSXin LI err(EXIT_FAILURE, "Can't open `%s'", argv[1]);
48548c779cdSXin LI
48648c779cdSXin LI if (fstat(fd, &st) == -1)
48748c779cdSXin LI err(EXIT_FAILURE, "Can't stat `%s'", argv[1]);
48848c779cdSXin LI
489a4d6d3b8SXin LI if ((p = CAST(char *, malloc(st.st_size))) == NULL)
49048c779cdSXin LI err(EXIT_FAILURE, "Can't allocate %jd bytes",
49148c779cdSXin LI (intmax_t)st.st_size);
49248c779cdSXin LI if (read(fd, p, st.st_size) != st.st_size)
49348c779cdSXin LI err(EXIT_FAILURE, "Can't read %jd bytes",
49448c779cdSXin LI (intmax_t)st.st_size);
49548c779cdSXin LI memset(stats, 0, sizeof(stats));
49648c779cdSXin LI printf("is json %d\n", json_parse((const unsigned char **)&p,
49748c779cdSXin LI p + st.st_size, stats, 0));
49848c779cdSXin LI return 0;
49948c779cdSXin LI }
50048c779cdSXin LI #endif
501