dump.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. /*
  2. * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org>
  3. *
  4. * Jansson is free software; you can redistribute it and/or modify
  5. * it under the terms of the MIT license. See LICENSE for details.
  6. */
  7. #ifndef _GNU_SOURCE
  8. #define _GNU_SOURCE
  9. #endif
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <assert.h>
  14. #include "jansson.h"
  15. #include "jansson_private.h"
  16. #include "strbuffer.h"
  17. #include "utf.h"
  18. #define MAX_INTEGER_STR_LENGTH 100
  19. #define MAX_REAL_STR_LENGTH 100
  20. #define FLAGS_TO_INDENT(f) ((f) & 0x1F)
  21. #define FLAGS_TO_PRECISION(f) (((f) >> 11) & 0x1F)
  22. static int dump_to_strbuffer(const char *buffer, size_t size, void *data)
  23. {
  24. return strbuffer_append_bytes((strbuffer_t *)data, buffer, size);
  25. }
  26. static int dump_to_file(const char *buffer, size_t size, void *data)
  27. {
  28. FILE *dest = (FILE *)data;
  29. if(fwrite(buffer, size, 1, dest) != 1)
  30. return -1;
  31. return 0;
  32. }
  33. /* 32 spaces (the maximum indentation size) */
  34. static const char whitespace[] = " ";
  35. static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump, void *data)
  36. {
  37. if(FLAGS_TO_INDENT(flags) > 0)
  38. {
  39. unsigned int ws_count = FLAGS_TO_INDENT(flags), n_spaces = depth * ws_count;
  40. if(dump("\n", 1, data))
  41. return -1;
  42. while(n_spaces > 0)
  43. {
  44. int cur_n = n_spaces < sizeof whitespace - 1 ? n_spaces : sizeof whitespace - 1;
  45. if(dump(whitespace, cur_n, data))
  46. return -1;
  47. n_spaces -= cur_n;
  48. }
  49. }
  50. else if(space && !(flags & JSON_COMPACT))
  51. {
  52. return dump(" ", 1, data);
  53. }
  54. return 0;
  55. }
  56. static int dump_string(const char *str, size_t len, json_dump_callback_t dump, void *data, size_t flags)
  57. {
  58. const char *pos, *end, *lim;
  59. int32_t codepoint;
  60. if(dump("\"", 1, data))
  61. return -1;
  62. end = pos = str;
  63. lim = str + len;
  64. while(1)
  65. {
  66. const char *text;
  67. char seq[13];
  68. int length;
  69. while(end < lim)
  70. {
  71. end = utf8_iterate(pos, lim - pos, &codepoint);
  72. if(!end)
  73. return -1;
  74. /* mandatory escape or control char */
  75. if(codepoint == '\\' || codepoint == '"' || codepoint < 0x20)
  76. break;
  77. /* slash */
  78. if((flags & JSON_ESCAPE_SLASH) && codepoint == '/')
  79. break;
  80. /* non-ASCII */
  81. if((flags & JSON_ENSURE_ASCII) && codepoint > 0x7F)
  82. break;
  83. pos = end;
  84. }
  85. if(pos != str) {
  86. if(dump(str, pos - str, data))
  87. return -1;
  88. }
  89. if(end == pos)
  90. break;
  91. /* handle \, /, ", and control codes */
  92. length = 2;
  93. switch(codepoint)
  94. {
  95. case '\\': text = "\\\\"; break;
  96. case '\"': text = "\\\""; break;
  97. case '\b': text = "\\b"; break;
  98. case '\f': text = "\\f"; break;
  99. case '\n': text = "\\n"; break;
  100. case '\r': text = "\\r"; break;
  101. case '\t': text = "\\t"; break;
  102. case '/': text = "\\/"; break;
  103. default:
  104. {
  105. /* codepoint is in BMP */
  106. if(codepoint < 0x10000)
  107. {
  108. snprintf(seq, sizeof(seq), "\\u%04X", (unsigned int)codepoint);
  109. length = 6;
  110. }
  111. /* not in BMP -> construct a UTF-16 surrogate pair */
  112. else
  113. {
  114. int32_t first, last;
  115. codepoint -= 0x10000;
  116. first = 0xD800 | ((codepoint & 0xffc00) >> 10);
  117. last = 0xDC00 | (codepoint & 0x003ff);
  118. snprintf(seq, sizeof(seq), "\\u%04X\\u%04X", (unsigned int)first, (unsigned int)last);
  119. length = 12;
  120. }
  121. text = seq;
  122. break;
  123. }
  124. }
  125. if(dump(text, length, data))
  126. return -1;
  127. str = pos = end;
  128. }
  129. return dump("\"", 1, data);
  130. }
  131. static int compare_keys(const void *key1, const void *key2)
  132. {
  133. return strcmp(*(const char **)key1, *(const char **)key2);
  134. }
  135. static int do_dump(const json_t *json, size_t flags, int depth,
  136. json_dump_callback_t dump, void *data)
  137. {
  138. if(!json)
  139. return -1;
  140. switch(json_typeof(json)) {
  141. case JSON_NULL:
  142. return dump("null", 4, data);
  143. case JSON_TRUE:
  144. return dump("true", 4, data);
  145. case JSON_FALSE:
  146. return dump("false", 5, data);
  147. case JSON_INTEGER:
  148. {
  149. char buffer[MAX_INTEGER_STR_LENGTH];
  150. int size;
  151. size = snprintf(buffer, MAX_INTEGER_STR_LENGTH,
  152. "%" JSON_INTEGER_FORMAT,
  153. json_integer_value(json));
  154. if(size < 0 || size >= MAX_INTEGER_STR_LENGTH)
  155. return -1;
  156. return dump(buffer, size, data);
  157. }
  158. case JSON_REAL:
  159. {
  160. char buffer[MAX_REAL_STR_LENGTH];
  161. int size;
  162. double value = json_real_value(json);
  163. size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value,
  164. FLAGS_TO_PRECISION(flags));
  165. if(size < 0)
  166. return -1;
  167. return dump(buffer, size, data);
  168. }
  169. case JSON_STRING:
  170. return dump_string(json_string_value(json), json_string_length(json), dump, data, flags);
  171. case JSON_ARRAY:
  172. {
  173. size_t n;
  174. size_t i;
  175. json_array_t *array;
  176. /* detect circular references */
  177. array = json_to_array(json);
  178. if(array->visited)
  179. goto array_error;
  180. array->visited = 1;
  181. n = json_array_size(json);
  182. if(dump("[", 1, data))
  183. goto array_error;
  184. if(n == 0) {
  185. array->visited = 0;
  186. return dump("]", 1, data);
  187. }
  188. if(dump_indent(flags, depth + 1, 0, dump, data))
  189. goto array_error;
  190. for(i = 0; i < n; ++i) {
  191. if(do_dump(json_array_get(json, i), flags, depth + 1,
  192. dump, data))
  193. goto array_error;
  194. if(i < n - 1)
  195. {
  196. if(dump(",", 1, data) ||
  197. dump_indent(flags, depth + 1, 1, dump, data))
  198. goto array_error;
  199. }
  200. else
  201. {
  202. if(dump_indent(flags, depth, 0, dump, data))
  203. goto array_error;
  204. }
  205. }
  206. array->visited = 0;
  207. return dump("]", 1, data);
  208. array_error:
  209. array->visited = 0;
  210. return -1;
  211. }
  212. case JSON_OBJECT:
  213. {
  214. json_object_t *object;
  215. void *iter;
  216. const char *separator;
  217. int separator_length;
  218. if(flags & JSON_COMPACT) {
  219. separator = ":";
  220. separator_length = 1;
  221. }
  222. else {
  223. separator = ": ";
  224. separator_length = 2;
  225. }
  226. /* detect circular references */
  227. object = json_to_object(json);
  228. if(object->visited)
  229. goto object_error;
  230. object->visited = 1;
  231. iter = json_object_iter((json_t *)json);
  232. if(dump("{", 1, data))
  233. goto object_error;
  234. if(!iter) {
  235. object->visited = 0;
  236. return dump("}", 1, data);
  237. }
  238. if(dump_indent(flags, depth + 1, 0, dump, data))
  239. goto object_error;
  240. if(flags & JSON_SORT_KEYS)
  241. {
  242. const char **keys;
  243. size_t size, i;
  244. size = json_object_size(json);
  245. keys = jsonp_malloc(size * sizeof(const char *));
  246. if(!keys)
  247. goto object_error;
  248. i = 0;
  249. while(iter)
  250. {
  251. keys[i] = json_object_iter_key(iter);
  252. iter = json_object_iter_next((json_t *)json, iter);
  253. i++;
  254. }
  255. assert(i == size);
  256. qsort(keys, size, sizeof(const char *), compare_keys);
  257. for(i = 0; i < size; i++)
  258. {
  259. const char *key;
  260. json_t *value;
  261. key = keys[i];
  262. value = json_object_get(json, key);
  263. assert(value);
  264. dump_string(key, strlen(key), dump, data, flags);
  265. if(dump(separator, separator_length, data) ||
  266. do_dump(value, flags, depth + 1, dump, data))
  267. {
  268. jsonp_free(keys);
  269. goto object_error;
  270. }
  271. if(i < size - 1)
  272. {
  273. if(dump(",", 1, data) ||
  274. dump_indent(flags, depth + 1, 1, dump, data))
  275. {
  276. jsonp_free(keys);
  277. goto object_error;
  278. }
  279. }
  280. else
  281. {
  282. if(dump_indent(flags, depth, 0, dump, data))
  283. {
  284. jsonp_free(keys);
  285. goto object_error;
  286. }
  287. }
  288. }
  289. jsonp_free(keys);
  290. }
  291. else
  292. {
  293. /* Don't sort keys */
  294. while(iter)
  295. {
  296. void *next = json_object_iter_next((json_t *)json, iter);
  297. const char *key = json_object_iter_key(iter);
  298. dump_string(key, strlen(key), dump, data, flags);
  299. if(dump(separator, separator_length, data) ||
  300. do_dump(json_object_iter_value(iter), flags, depth + 1,
  301. dump, data))
  302. goto object_error;
  303. if(next)
  304. {
  305. if(dump(",", 1, data) ||
  306. dump_indent(flags, depth + 1, 1, dump, data))
  307. goto object_error;
  308. }
  309. else
  310. {
  311. if(dump_indent(flags, depth, 0, dump, data))
  312. goto object_error;
  313. }
  314. iter = next;
  315. }
  316. }
  317. object->visited = 0;
  318. return dump("}", 1, data);
  319. object_error:
  320. object->visited = 0;
  321. return -1;
  322. }
  323. default:
  324. /* not reached */
  325. return -1;
  326. }
  327. }
  328. char *json_dumps(const json_t *json, size_t flags)
  329. {
  330. strbuffer_t strbuff;
  331. char *result;
  332. if(strbuffer_init(&strbuff))
  333. return NULL;
  334. if(json_dump_callback(json, dump_to_strbuffer, (void *)&strbuff, flags))
  335. result = NULL;
  336. else
  337. result = jsonp_strdup(strbuffer_value(&strbuff));
  338. strbuffer_close(&strbuff);
  339. return result;
  340. }
  341. int json_dumpf(const json_t *json, FILE *output, size_t flags)
  342. {
  343. return json_dump_callback(json, dump_to_file, (void *)output, flags);
  344. }
  345. int json_dump_file(const json_t *json, const char *path, size_t flags)
  346. {
  347. int result;
  348. FILE *output = fopen(path, "w");
  349. if(!output)
  350. return -1;
  351. result = json_dumpf(json, output, flags);
  352. fclose(output);
  353. return result;
  354. }
  355. int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags)
  356. {
  357. if(!(flags & JSON_ENCODE_ANY)) {
  358. if(!json_is_array(json) && !json_is_object(json))
  359. return -1;
  360. }
  361. return do_dump(json, flags, 0, callback, data);
  362. }