/* * Copyright (c) 2009 Petri Lehtinen * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include "jansson.h" #include "strbuffer.h" typedef int (*dump_func) (const char *buffer, int size, void *data); struct string { char *buffer; int length; int size; }; static int dump_to_strbuffer (const char *buffer, int size, void *data) { return strbuffer_append_bytes ((strbuffer_t *) data, buffer, size); } static int dump_to_file (const char *buffer, int size, void *data) { FILE *dest = (FILE *) data; if (fwrite (buffer, size, 1, dest) != 1) return -1; return 0; } /* 256 spaces (the maximum indentation size) */ static char whitespace[] = " "; static int dump_indent (uint32_t flags, int depth, dump_func dump, void *data) { if (JSON_INDENT (flags) > 0) { int i, ws_count = JSON_INDENT (flags); if (dump ("\n", 1, data)) return -1; for (i = 0; i < depth; i++) { if (dump (whitespace, ws_count, data)) return -1; } } return 0; } static int dump_string (const char *str, dump_func dump, void *data) { const char *end; if (dump ("\"", 1, data)) return -1; end = str; while (1) { const char *text; char seq[7]; int length; while (*end && *end != '\\' && *end != '"' && (*end < 0 || *end > 0x1F)) end++; if (end != str) { if (dump (str, end - str, data)) return -1; } if (!*end) break; /* handle \, ", and control codes */ length = 2; switch (*end) { case '\\': text = "\\\\"; break; case '\"': text = "\\\""; break; case '\b': text = "\\b"; break; case '\f': text = "\\f"; break; case '\n': text = "\\n"; break; case '\r': text = "\\r"; break; case '\t': text = "\\t"; break; default: { sprintf (seq, "\\u00%02x", *end); text = seq; length = 6; break; } } if (dump (text, length, data)) return -1; end++; str = end; } return dump ("\"", 1, data); } static int do_dump (const json_t * json, uint32_t flags, int depth, dump_func dump, void *data) { switch (json_typeof (json)) { case JSON_NULL: return dump ("null", 4, data); case JSON_TRUE: return dump ("true", 4, data); case JSON_FALSE: return dump ("false", 5, data); case JSON_INTEGER: { char *buffer; int size, ret; size = asprintf (&buffer, "%d", json_integer_value (json)); if (size == -1) return -1; ret = dump (buffer, size, data); g_free (buffer); return ret; } case JSON_REAL: { char *buffer; int size, ret; size = asprintf (&buffer, "%.17f", json_real_value (json)); if (size == -1) return -1; ret = dump (buffer, size, data); g_free (buffer); return ret; } case JSON_STRING: return dump_string (json_string_value (json), dump, data); case JSON_ARRAY: { int i; int n = json_array_size (json); if (dump ("[", 1, data)) return -1; if (n == 0) return dump ("]", 1, data); if (dump_indent (flags, depth + 1, dump, data)) return -1; for (i = 0; i < n; ++i) { if (do_dump (json_array_get (json, i), flags, depth + 1, dump, data)) return -1; if (i < n - 1) { if (dump (",", 1, data) || dump_indent (flags, depth + 1, dump, data)) return -1; } else { if (dump_indent (flags, depth, dump, data)) return -1; } } return dump ("]", 1, data); } case JSON_OBJECT: { void *iter = json_object_iter ((json_t *) json); if (dump ("{", 1, data)) return -1; if (!iter) return dump ("}", 1, data); if (dump_indent (flags, depth + 1, dump, data)) return -1; while (iter) { void *next = json_object_iter_next ((json_t *) json, iter); dump_string (json_object_iter_key (iter), dump, data); if (dump (": ", 2, data) || do_dump (json_object_iter_value (iter), flags, depth + 1, dump, data)) return -1; if (next) { if (dump (",", 1, data) || dump_indent (flags, depth + 1, dump, data)) return -1; } else { if (dump_indent (flags, depth, dump, data)) return -1; } iter = next; } return dump ("}", 1, data); } default: /* not reached */ return -1; } } char * json_dumps (const json_t * json, uint32_t flags) { strbuffer_t strbuff; char *result; if (!json_is_array (json) && !json_is_object (json)) return NULL; if (strbuffer_init (&strbuff)) return NULL; if (do_dump (json, flags, 0, dump_to_strbuffer, (void *)&strbuff)) return NULL; if (dump_to_strbuffer ("\n", 1, (void *)&strbuff)) return NULL; result = strdup (strbuffer_value (&strbuff)); strbuffer_close (&strbuff); return result; } int json_dumpf (const json_t * json, FILE * output, uint32_t flags) { if (!json_is_array (json) && !json_is_object (json)) return -1; if (do_dump (json, flags, 0, dump_to_file, (void *)output)) return -1; return dump_to_file ("\n", 1, (void *)output); } int json_dump_file (const json_t * json, const char *path, uint32_t flags) { int result; FILE *output = fopen (path, "w"); if (!output) return -1; result = json_dumpf (json, output, flags); fclose (output); return result; }