jsonlint.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. /*
  2. * Copyright (C) 2009-2011 Vincent Hanquez <vincent@snarc.org>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU Lesser General Public License as published
  6. * by the Free Software Foundation; version 2.1 or version 3.0 only.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * SPDX-License-Identifier: GPL-3.0+
  14. * License-Filename: LICENSE
  15. */
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <assert.h>
  20. #include <locale.h>
  21. #include <getopt.h>
  22. #include <errno.h>
  23. #include "json.h"
  24. char *indent_string = NULL;
  25. char *string_of_errors[] =
  26. {
  27. [JSON_ERROR_NO_MEMORY] = "out of memory",
  28. [JSON_ERROR_BAD_CHAR] = "bad character",
  29. [JSON_ERROR_POP_EMPTY] = "stack empty",
  30. [JSON_ERROR_POP_UNEXPECTED_MODE] = "pop unexpected mode",
  31. [JSON_ERROR_NESTING_LIMIT] = "nesting limit",
  32. [JSON_ERROR_DATA_LIMIT] = "data limit",
  33. [JSON_ERROR_COMMENT_NOT_ALLOWED] = "comment not allowed by config",
  34. [JSON_ERROR_UNEXPECTED_CHAR] = "unexpected char",
  35. [JSON_ERROR_UNICODE_MISSING_LOW_SURROGATE] = "missing unicode low surrogate",
  36. [JSON_ERROR_UNICODE_UNEXPECTED_LOW_SURROGATE] = "unexpected unicode low surrogate",
  37. [JSON_ERROR_COMMA_OUT_OF_STRUCTURE] = "error comma out of structure",
  38. [JSON_ERROR_CALLBACK] = "error in a callback",
  39. [JSON_ERROR_UTF8] = "utf8 validation error"
  40. };
  41. static int printchannel(void *userdata, const char *data, uint32_t length)
  42. {
  43. FILE *channel = userdata;
  44. int ret;
  45. ret = fwrite(data, length, 1, channel);
  46. if (ret != length)
  47. return 1;
  48. return 0;
  49. }
  50. static int prettyprint(void *userdata, int type, const char *data, uint32_t length)
  51. {
  52. json_printer *printer = userdata;
  53. return json_print_pretty(printer, type, data, length);
  54. }
  55. FILE *open_filename(const char *filename, const char *opt, int is_input)
  56. {
  57. FILE *input;
  58. if (strcmp(filename, "-") == 0)
  59. input = (is_input) ? stdin : stdout;
  60. else {
  61. input = fopen(filename, opt);
  62. if (!input) {
  63. fprintf(stderr, "error: cannot open %s: %s", filename, strerror(errno));
  64. return NULL;
  65. }
  66. }
  67. return input;
  68. }
  69. void close_filename(const char *filename, FILE *file)
  70. {
  71. if (strcmp(filename, "-") != 0)
  72. fclose(file);
  73. }
  74. int process_file(json_parser *parser, FILE *input, int *retlines, int *retcols)
  75. {
  76. char buffer[4096];
  77. int ret = 0;
  78. int32_t read;
  79. int lines, col, i;
  80. lines = 1;
  81. col = 0;
  82. while (1) {
  83. uint32_t processed;
  84. read = fread(buffer, 1, 4096, input);
  85. if (read <= 0)
  86. break;
  87. ret = json_parser_string(parser, buffer, read, &processed);
  88. for (i = 0; i < processed; i++) {
  89. if (buffer[i] == '\n') { col = 0; lines++; } else col++;
  90. }
  91. if (ret)
  92. break;
  93. }
  94. if (retlines) *retlines = lines;
  95. if (retcols) *retcols = col;
  96. return ret;
  97. }
  98. static int do_verify(json_config *config, const char *filename)
  99. {
  100. FILE *input;
  101. json_parser parser;
  102. int ret;
  103. input = open_filename(filename, "r", 1);
  104. if (!input)
  105. return 2;
  106. /* initialize the parser structure. we don't need a callback in verify */
  107. ret = json_parser_init(&parser, config, NULL, NULL);
  108. if (ret) {
  109. fprintf(stderr, "error: initializing parser failed (code=%d): %s\n", ret, string_of_errors[ret]);
  110. return ret;
  111. }
  112. ret = process_file(&parser, input, NULL, NULL);
  113. if (ret)
  114. return 1;
  115. ret = json_parser_is_done(&parser);
  116. if (!ret)
  117. return 1;
  118. close_filename(filename, input);
  119. return 0;
  120. }
  121. static int do_parse(json_config *config, const char *filename)
  122. {
  123. FILE *input;
  124. json_parser parser;
  125. int ret;
  126. int col, lines;
  127. input = open_filename(filename, "r", 1);
  128. if (!input)
  129. return 2;
  130. /* initialize the parser structure. we don't need a callback in verify */
  131. ret = json_parser_init(&parser, config, NULL, NULL);
  132. if (ret) {
  133. fprintf(stderr, "error: initializing parser failed (code=%d): %s\n", ret, string_of_errors[ret]);
  134. return ret;
  135. }
  136. ret = process_file(&parser, input, &lines, &col);
  137. if (ret) {
  138. fprintf(stderr, "line %d, col %d: [code=%d] %s\n",
  139. lines, col, ret, string_of_errors[ret]);
  140. return 1;
  141. }
  142. ret = json_parser_is_done(&parser);
  143. if (!ret) {
  144. fprintf(stderr, "syntax error\n");
  145. return 1;
  146. }
  147. close_filename(filename, input);
  148. return 0;
  149. }
  150. static int do_format(json_config *config, const char *filename, const char *outputfile)
  151. {
  152. FILE *input, *output;
  153. json_parser parser;
  154. json_printer printer;
  155. int ret;
  156. int col, lines;
  157. input = open_filename(filename, "r", 1);
  158. if (!input)
  159. return 2;
  160. output = open_filename(outputfile, "a+", 0);
  161. if (!output)
  162. return 2;
  163. /* initialize printer and parser structures */
  164. ret = json_print_init(&printer, printchannel, stdout);
  165. if (ret) {
  166. fprintf(stderr, "error: initializing printer failed: [code=%d] %s\n", ret, string_of_errors[ret]);
  167. return ret;
  168. }
  169. if (indent_string)
  170. printer.indentstr = indent_string;
  171. ret = json_parser_init(&parser, config, &prettyprint, &printer);
  172. if (ret) {
  173. fprintf(stderr, "error: initializing parser failed: [code=%d] %s\n", ret, string_of_errors[ret]);
  174. return ret;
  175. }
  176. ret = process_file(&parser, input, &lines, &col);
  177. if (ret) {
  178. fprintf(stderr, "line %d, col %d: [code=%d] %s\n",
  179. lines, col, ret, string_of_errors[ret]);
  180. return 1;
  181. }
  182. ret = json_parser_is_done(&parser);
  183. if (!ret) {
  184. fprintf(stderr, "syntax error\n");
  185. return 1;
  186. }
  187. /* cleanup */
  188. json_parser_free(&parser);
  189. json_print_free(&printer);
  190. fwrite("\n", 1, 1, stdout);
  191. close_filename(filename, input);
  192. return 0;
  193. }
  194. struct json_val_elem {
  195. char *key;
  196. uint32_t key_length;
  197. struct json_val *val;
  198. };
  199. typedef struct json_val {
  200. int type;
  201. int length;
  202. union {
  203. char *data;
  204. struct json_val **array;
  205. struct json_val_elem **object;
  206. } u;
  207. } json_val_t;
  208. static void *tree_create_structure(int nesting, int is_object)
  209. {
  210. json_val_t *v = malloc(sizeof(json_val_t));
  211. if (v) {
  212. /* instead of defining a new enum type, we abuse the
  213. * meaning of the json enum type for array and object */
  214. if (is_object) {
  215. v->type = JSON_OBJECT_BEGIN;
  216. v->u.object = NULL;
  217. } else {
  218. v->type = JSON_ARRAY_BEGIN;
  219. v->u.array = NULL;
  220. }
  221. v->length = 0;
  222. }
  223. return v;
  224. }
  225. static char *memalloc_copy_length(const char *src, uint32_t n)
  226. {
  227. char *dest;
  228. dest = calloc(n + 1, sizeof(char));
  229. if (dest)
  230. memcpy(dest, src, n);
  231. return dest;
  232. }
  233. static void *tree_create_data(int type, const char *data, uint32_t length)
  234. {
  235. json_val_t *v;
  236. v = malloc(sizeof(json_val_t));
  237. if (v) {
  238. v->type = type;
  239. v->length = length;
  240. v->u.data = memalloc_copy_length(data, length);
  241. if (!v->u.data) {
  242. free(v);
  243. return NULL;
  244. }
  245. }
  246. return v;
  247. }
  248. static int tree_append(void *structure, char *key, uint32_t key_length, void *obj)
  249. {
  250. json_val_t *parent = structure;
  251. if (key) {
  252. struct json_val_elem *objelem;
  253. if (parent->length == 0) {
  254. parent->u.object = calloc(1 + 1, sizeof(json_val_t *)); /* +1 for null */
  255. if (!parent->u.object)
  256. return 1;
  257. } else {
  258. uint32_t newsize = parent->length + 1 + 1; /* +1 for null */
  259. void *newptr;
  260. newptr = realloc(parent->u.object, newsize * sizeof(json_val_t *));
  261. if (!newptr)
  262. return -1;
  263. parent->u.object = newptr;
  264. }
  265. objelem = malloc(sizeof(struct json_val_elem));
  266. if (!objelem)
  267. return -1;
  268. objelem->key = memalloc_copy_length(key, key_length);
  269. objelem->key_length = key_length;
  270. objelem->val = obj;
  271. parent->u.object[parent->length++] = objelem;
  272. parent->u.object[parent->length] = NULL;
  273. } else {
  274. if (parent->length == 0) {
  275. parent->u.array = calloc(1 + 1, sizeof(json_val_t *)); /* +1 for null */
  276. if (!parent->u.array)
  277. return 1;
  278. } else {
  279. uint32_t newsize = parent->length + 1 + 1; /* +1 for null */
  280. void *newptr;
  281. newptr = realloc(parent->u.object, newsize * sizeof(json_val_t *));
  282. if (!newptr)
  283. return -1;
  284. parent->u.array = newptr;
  285. }
  286. parent->u.array[parent->length++] = obj;
  287. parent->u.array[parent->length] = NULL;
  288. }
  289. return 0;
  290. }
  291. static int do_tree(json_config *config, const char *filename, json_val_t **root_structure)
  292. {
  293. FILE *input;
  294. json_parser parser;
  295. json_parser_dom dom;
  296. int ret;
  297. int col, lines;
  298. input = open_filename(filename, "r", 1);
  299. if (!input)
  300. return 2;
  301. ret = json_parser_dom_init(&dom, tree_create_structure, tree_create_data, tree_append);
  302. if (ret) {
  303. fprintf(stderr, "error: initializing helper failed: [code=%d] %s\n", ret, string_of_errors[ret]);
  304. return ret;
  305. }
  306. ret = json_parser_init(&parser, config, json_parser_dom_callback, &dom);
  307. if (ret) {
  308. fprintf(stderr, "error: initializing parser failed: [code=%d] %s\n", ret, string_of_errors[ret]);
  309. return ret;
  310. }
  311. ret = process_file(&parser, input, &lines, &col);
  312. if (ret) {
  313. fprintf(stderr, "line %d, col %d: [code=%d] %s\n",
  314. lines, col, ret, string_of_errors[ret]);
  315. return 1;
  316. }
  317. ret = json_parser_is_done(&parser);
  318. if (!ret) {
  319. fprintf(stderr, "syntax error\n");
  320. return 1;
  321. }
  322. if (root_structure)
  323. *root_structure = dom.root_structure;
  324. /* cleanup */
  325. json_parser_free(&parser);
  326. close_filename(filename, input);
  327. return 0;
  328. }
  329. static int print_tree_iter(json_val_t *element, FILE *output)
  330. {
  331. int i;
  332. if (!element) {
  333. fprintf(stderr, "error: no element in print tree\n");
  334. return -1;
  335. }
  336. switch (element->type) {
  337. case JSON_OBJECT_BEGIN:
  338. fprintf(output, "object begin (%d element)\n", element->length);
  339. for (i = 0; i < element->length; i++) {
  340. fprintf(output, "key: %s\n", element->u.object[i]->key);
  341. print_tree_iter(element->u.object[i]->val, output);
  342. }
  343. fprintf(output, "object end\n");
  344. break;
  345. case JSON_ARRAY_BEGIN:
  346. fprintf(output, "array begin\n");
  347. for (i = 0; i < element->length; i++) {
  348. print_tree_iter(element->u.array[i], output);
  349. }
  350. fprintf(output, "array end\n");
  351. break;
  352. case JSON_FALSE:
  353. case JSON_TRUE:
  354. case JSON_NULL:
  355. fprintf(output, "constant\n");
  356. break;
  357. case JSON_INT:
  358. fprintf(output, "integer: %s\n", element->u.data);
  359. break;
  360. case JSON_STRING:
  361. fprintf(output, "string: %s\n", element->u.data);
  362. break;
  363. case JSON_FLOAT:
  364. fprintf(output, "float: %s\n", element->u.data);
  365. break;
  366. default:
  367. break;
  368. }
  369. return 0;
  370. }
  371. static int print_tree(json_val_t *root_structure, char *outputfile)
  372. {
  373. FILE *output;
  374. output = open_filename(outputfile, "a+", 0);
  375. if (!output)
  376. return 2;
  377. print_tree_iter(root_structure, output);
  378. close_filename(outputfile, output);
  379. return 0;
  380. }
  381. int usage(const char *argv0)
  382. {
  383. printf("usage: %s [options] JSON-FILE(s)...\n", argv0);
  384. printf("\t--no-comments : disallow C and YAML comments in json file (default to both on)\n");
  385. printf("\t--no-yaml-comments : disallow YAML comment (default to on)\n");
  386. printf("\t--no-c-comments : disallow C comment (default to on)\n");
  387. printf("\t--format : pretty print the json file to stdout (unless -o specified)\n");
  388. printf("\t--verify : quietly verified if the json file is valid. exit 0 if valid, 1 if not\n");
  389. printf("\t--benchmark : quietly iterate multiples times over valid json files\n");
  390. printf("\t--max-nesting : limit the number of nesting in structure (default to no limit)\n");
  391. printf("\t--max-data : limit the number of characters of data (string/int/float) (default to no limit)\n");
  392. printf("\t--indent-string : set the string to use for indenting one level (default to 1 tab)\n");
  393. printf("\t--tree : build a tree (DOM)\n");
  394. printf("\t-o : output to a specific file instead of stdout\n");
  395. exit(0);
  396. }
  397. int main(int argc, char **argv)
  398. {
  399. int format = 0, verify = 0, use_tree = 0, benchmarks = 0;
  400. int ret = 0, i;
  401. json_config config;
  402. char *output = "-";
  403. memset(&config, 0, sizeof(json_config));
  404. config.max_nesting = 0;
  405. config.max_data = 0;
  406. config.allow_c_comments = 1;
  407. config.allow_yaml_comments = 1;
  408. while (1) {
  409. int option_index;
  410. struct option long_options[] = {
  411. { "no-comments", 0, 0, 0 },
  412. { "no-yaml-comments", 0, 0, 0 },
  413. { "no-c-comments", 0, 0, 0 },
  414. { "format", 0, 0, 0 },
  415. { "verify", 0, 0, 0 },
  416. { "benchmark", 1, 0, 0 },
  417. { "help", 0, 0, 0 },
  418. { "max-nesting", 1, 0, 0 },
  419. { "max-data", 1, 0, 0 },
  420. { "indent-string", 1, 0, 0 },
  421. { "tree", 0, 0, 0 },
  422. { 0 },
  423. };
  424. int c = getopt_long(argc, argv, "o:", long_options, &option_index);
  425. if (c == -1)
  426. break;
  427. switch (c) {
  428. case 0: {
  429. const char *name = long_options[option_index].name;
  430. if (strcmp(name, "help") == 0)
  431. usage(argv[0]);
  432. else if (strcmp(name, "no-c-comments") == 0)
  433. config.allow_c_comments = 0;
  434. else if (strcmp(name, "no-yaml-comments") == 0)
  435. config.allow_yaml_comments = 0;
  436. else if (strcmp(name, "no-comments") == 0)
  437. config.allow_c_comments = config.allow_yaml_comments = 0;
  438. else if (strcmp(name, "format") == 0)
  439. format = 1;
  440. else if (strcmp(name, "verify") == 0)
  441. verify = 1;
  442. else if (strcmp(name, "max-nesting") == 0)
  443. config.max_nesting = atoi(optarg);
  444. else if (strcmp(name, "benchmark") == 0)
  445. benchmarks = atoi(optarg);
  446. else if (strcmp(name, "max-data") == 0)
  447. config.max_data = atoi(optarg);
  448. else if (strcmp(name, "indent-string") == 0)
  449. indent_string = strdup(optarg);
  450. else if (strcmp(name, "tree") == 0)
  451. use_tree = 1;
  452. break;
  453. }
  454. case 'o':
  455. output = strdup(optarg);
  456. break;
  457. default:
  458. break;
  459. }
  460. }
  461. if (!output)
  462. output = "-";
  463. if (optind >= argc)
  464. usage(argv[0]);
  465. if (benchmarks > 0) {
  466. for (i = 0; i < benchmarks; i++) {
  467. if (use_tree) {
  468. json_val_t *root_structure;
  469. ret = do_tree(&config, argv[optind], &root_structure);
  470. } else {
  471. ret = do_verify(&config, argv[optind]);
  472. }
  473. if (ret)
  474. exit(ret);
  475. }
  476. exit(0);
  477. }
  478. for (i = optind; i < argc; i++) {
  479. if (use_tree) {
  480. json_val_t *root_structure;
  481. ret = do_tree(&config, argv[i], &root_structure);
  482. if (ret)
  483. exit(ret);
  484. if (!verify)
  485. print_tree(root_structure, output);
  486. } else {
  487. if (format)
  488. ret = do_format(&config, argv[i], output);
  489. else if (verify)
  490. ret = do_verify(&config, argv[i]);
  491. else
  492. ret = do_parse(&config, argv[i]);
  493. }
  494. if (ret)
  495. exit(ret);
  496. }
  497. return ret;
  498. }