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