"Fossies" - the Fresh Open Source Software Archive

Member "jansson-2.14/src/dump.c" (26 Jan 2021, 13990 Bytes) of package /linux/www/jansson-2.14.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "dump.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.13.1_vs_2.14.

    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 
    8 #ifndef _GNU_SOURCE
    9 #define _GNU_SOURCE
   10 #endif
   11 
   12 #include "jansson_private.h"
   13 
   14 #include <assert.h>
   15 #include <stdio.h>
   16 #include <stdlib.h>
   17 #include <string.h>
   18 #ifdef HAVE_UNISTD_H
   19 #include <unistd.h>
   20 #endif
   21 
   22 #include "jansson.h"
   23 #include "strbuffer.h"
   24 #include "utf.h"
   25 
   26 #define MAX_INTEGER_STR_LENGTH 100
   27 #define MAX_REAL_STR_LENGTH    100
   28 
   29 #define FLAGS_TO_INDENT(f)    ((f)&0x1F)
   30 #define FLAGS_TO_PRECISION(f) (((f) >> 11) & 0x1F)
   31 
   32 struct buffer {
   33     const size_t size;
   34     size_t used;
   35     char *data;
   36 };
   37 
   38 static int dump_to_strbuffer(const char *buffer, size_t size, void *data) {
   39     return strbuffer_append_bytes((strbuffer_t *)data, buffer, size);
   40 }
   41 
   42 static int dump_to_buffer(const char *buffer, size_t size, void *data) {
   43     struct buffer *buf = (struct buffer *)data;
   44 
   45     if (buf->used + size <= buf->size)
   46         memcpy(&buf->data[buf->used], buffer, size);
   47 
   48     buf->used += size;
   49     return 0;
   50 }
   51 
   52 static int dump_to_file(const char *buffer, size_t size, void *data) {
   53     FILE *dest = (FILE *)data;
   54     if (fwrite(buffer, size, 1, dest) != 1)
   55         return -1;
   56     return 0;
   57 }
   58 
   59 static int dump_to_fd(const char *buffer, size_t size, void *data) {
   60 #ifdef HAVE_UNISTD_H
   61     int *dest = (int *)data;
   62     if (write(*dest, buffer, size) == (ssize_t)size)
   63         return 0;
   64 #endif
   65     return -1;
   66 }
   67 
   68 /* 32 spaces (the maximum indentation size) */
   69 static const char whitespace[] = "                                ";
   70 
   71 static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump,
   72                        void *data) {
   73     if (FLAGS_TO_INDENT(flags) > 0) {
   74         unsigned int ws_count = FLAGS_TO_INDENT(flags), n_spaces = depth * ws_count;
   75 
   76         if (dump("\n", 1, data))
   77             return -1;
   78 
   79         while (n_spaces > 0) {
   80             int cur_n =
   81                 n_spaces < sizeof whitespace - 1 ? n_spaces : sizeof whitespace - 1;
   82 
   83             if (dump(whitespace, cur_n, data))
   84                 return -1;
   85 
   86             n_spaces -= cur_n;
   87         }
   88     } else if (space && !(flags & JSON_COMPACT)) {
   89         return dump(" ", 1, data);
   90     }
   91     return 0;
   92 }
   93 
   94 static int dump_string(const char *str, size_t len, json_dump_callback_t dump, void *data,
   95                        size_t flags) {
   96     const char *pos, *end, *lim;
   97     int32_t codepoint = 0;
   98 
   99     if (dump("\"", 1, data))
  100         return -1;
  101 
  102     end = pos = str;
  103     lim = str + len;
  104     while (1) {
  105         const char *text;
  106         char seq[13];
  107         int length;
  108 
  109         while (end < lim) {
  110             end = utf8_iterate(pos, lim - pos, &codepoint);
  111             if (!end)
  112                 return -1;
  113 
  114             /* mandatory escape or control char */
  115             if (codepoint == '\\' || codepoint == '"' || codepoint < 0x20)
  116                 break;
  117 
  118             /* slash */
  119             if ((flags & JSON_ESCAPE_SLASH) && codepoint == '/')
  120                 break;
  121 
  122             /* non-ASCII */
  123             if ((flags & JSON_ENSURE_ASCII) && codepoint > 0x7F)
  124                 break;
  125 
  126             pos = end;
  127         }
  128 
  129         if (pos != str) {
  130             if (dump(str, pos - str, data))
  131                 return -1;
  132         }
  133 
  134         if (end == pos)
  135             break;
  136 
  137         /* handle \, /, ", and control codes */
  138         length = 2;
  139         switch (codepoint) {
  140             case '\\':
  141                 text = "\\\\";
  142                 break;
  143             case '\"':
  144                 text = "\\\"";
  145                 break;
  146             case '\b':
  147                 text = "\\b";
  148                 break;
  149             case '\f':
  150                 text = "\\f";
  151                 break;
  152             case '\n':
  153                 text = "\\n";
  154                 break;
  155             case '\r':
  156                 text = "\\r";
  157                 break;
  158             case '\t':
  159                 text = "\\t";
  160                 break;
  161             case '/':
  162                 text = "\\/";
  163                 break;
  164             default: {
  165                 /* codepoint is in BMP */
  166                 if (codepoint < 0x10000) {
  167                     snprintf(seq, sizeof(seq), "\\u%04X", (unsigned int)codepoint);
  168                     length = 6;
  169                 }
  170 
  171                 /* not in BMP -> construct a UTF-16 surrogate pair */
  172                 else {
  173                     int32_t first, last;
  174 
  175                     codepoint -= 0x10000;
  176                     first = 0xD800 | ((codepoint & 0xffc00) >> 10);
  177                     last = 0xDC00 | (codepoint & 0x003ff);
  178 
  179                     snprintf(seq, sizeof(seq), "\\u%04X\\u%04X", (unsigned int)first,
  180                              (unsigned int)last);
  181                     length = 12;
  182                 }
  183 
  184                 text = seq;
  185                 break;
  186             }
  187         }
  188 
  189         if (dump(text, length, data))
  190             return -1;
  191 
  192         str = pos = end;
  193     }
  194 
  195     return dump("\"", 1, data);
  196 }
  197 
  198 struct key_len {
  199     const char *key;
  200     int len;
  201 };
  202 
  203 static int compare_keys(const void *key1, const void *key2) {
  204     const struct key_len *k1 = key1;
  205     const struct key_len *k2 = key2;
  206     const size_t min_size = k1->len < k2->len ? k1->len : k2->len;
  207     int res = memcmp(k1->key, k2->key, min_size);
  208 
  209     if (res)
  210         return res;
  211 
  212     return k1->len - k2->len;
  213 }
  214 
  215 static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *parents,
  216                    json_dump_callback_t dump, void *data) {
  217     int embed = flags & JSON_EMBED;
  218 
  219     flags &= ~JSON_EMBED;
  220 
  221     if (!json)
  222         return -1;
  223 
  224     switch (json_typeof(json)) {
  225         case JSON_NULL:
  226             return dump("null", 4, data);
  227 
  228         case JSON_TRUE:
  229             return dump("true", 4, data);
  230 
  231         case JSON_FALSE:
  232             return dump("false", 5, data);
  233 
  234         case JSON_INTEGER: {
  235             char buffer[MAX_INTEGER_STR_LENGTH];
  236             int size;
  237 
  238             size = snprintf(buffer, MAX_INTEGER_STR_LENGTH, "%" JSON_INTEGER_FORMAT,
  239                             json_integer_value(json));
  240             if (size < 0 || size >= MAX_INTEGER_STR_LENGTH)
  241                 return -1;
  242 
  243             return dump(buffer, size, data);
  244         }
  245 
  246         case JSON_REAL: {
  247             char buffer[MAX_REAL_STR_LENGTH];
  248             int size;
  249             double value = json_real_value(json);
  250 
  251             size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value,
  252                                 FLAGS_TO_PRECISION(flags));
  253             if (size < 0)
  254                 return -1;
  255 
  256             return dump(buffer, size, data);
  257         }
  258 
  259         case JSON_STRING:
  260             return dump_string(json_string_value(json), json_string_length(json), dump,
  261                                data, flags);
  262 
  263         case JSON_ARRAY: {
  264             size_t n;
  265             size_t i;
  266             /* Space for "0x", double the sizeof a pointer for the hex and a
  267              * terminator. */
  268             char key[2 + (sizeof(json) * 2) + 1];
  269             size_t key_len;
  270 
  271             /* detect circular references */
  272             if (jsonp_loop_check(parents, json, key, sizeof(key), &key_len))
  273                 return -1;
  274 
  275             n = json_array_size(json);
  276 
  277             if (!embed && dump("[", 1, data))
  278                 return -1;
  279             if (n == 0) {
  280                 hashtable_del(parents, key, key_len);
  281                 return embed ? 0 : dump("]", 1, data);
  282             }
  283             if (dump_indent(flags, depth + 1, 0, dump, data))
  284                 return -1;
  285 
  286             for (i = 0; i < n; ++i) {
  287                 if (do_dump(json_array_get(json, i), flags, depth + 1, parents, dump,
  288                             data))
  289                     return -1;
  290 
  291                 if (i < n - 1) {
  292                     if (dump(",", 1, data) ||
  293                         dump_indent(flags, depth + 1, 1, dump, data))
  294                         return -1;
  295                 } else {
  296                     if (dump_indent(flags, depth, 0, dump, data))
  297                         return -1;
  298                 }
  299             }
  300 
  301             hashtable_del(parents, key, key_len);
  302             return embed ? 0 : dump("]", 1, data);
  303         }
  304 
  305         case JSON_OBJECT: {
  306             void *iter;
  307             const char *separator;
  308             int separator_length;
  309             char loop_key[LOOP_KEY_LEN];
  310             size_t loop_key_len;
  311 
  312             if (flags & JSON_COMPACT) {
  313                 separator = ":";
  314                 separator_length = 1;
  315             } else {
  316                 separator = ": ";
  317                 separator_length = 2;
  318             }
  319 
  320             /* detect circular references */
  321             if (jsonp_loop_check(parents, json, loop_key, sizeof(loop_key),
  322                                  &loop_key_len))
  323                 return -1;
  324 
  325             iter = json_object_iter((json_t *)json);
  326 
  327             if (!embed && dump("{", 1, data))
  328                 return -1;
  329             if (!iter) {
  330                 hashtable_del(parents, loop_key, loop_key_len);
  331                 return embed ? 0 : dump("}", 1, data);
  332             }
  333             if (dump_indent(flags, depth + 1, 0, dump, data))
  334                 return -1;
  335 
  336             if (flags & JSON_SORT_KEYS) {
  337                 struct key_len *keys;
  338                 size_t size, i;
  339 
  340                 size = json_object_size(json);
  341                 keys = jsonp_malloc(size * sizeof(struct key_len));
  342                 if (!keys)
  343                     return -1;
  344 
  345                 i = 0;
  346                 while (iter) {
  347                     struct key_len *keylen = &keys[i];
  348 
  349                     keylen->key = json_object_iter_key(iter);
  350                     keylen->len = json_object_iter_key_len(iter);
  351 
  352                     iter = json_object_iter_next((json_t *)json, iter);
  353                     i++;
  354                 }
  355                 assert(i == size);
  356 
  357                 qsort(keys, size, sizeof(struct key_len), compare_keys);
  358 
  359                 for (i = 0; i < size; i++) {
  360                     const struct key_len *key;
  361                     json_t *value;
  362 
  363                     key = &keys[i];
  364                     value = json_object_getn(json, key->key, key->len);
  365                     assert(value);
  366 
  367                     dump_string(key->key, key->len, dump, data, flags);
  368                     if (dump(separator, separator_length, data) ||
  369                         do_dump(value, flags, depth + 1, parents, dump, data)) {
  370                         jsonp_free(keys);
  371                         return -1;
  372                     }
  373 
  374                     if (i < size - 1) {
  375                         if (dump(",", 1, data) ||
  376                             dump_indent(flags, depth + 1, 1, dump, data)) {
  377                             jsonp_free(keys);
  378                             return -1;
  379                         }
  380                     } else {
  381                         if (dump_indent(flags, depth, 0, dump, data)) {
  382                             jsonp_free(keys);
  383                             return -1;
  384                         }
  385                     }
  386                 }
  387 
  388                 jsonp_free(keys);
  389             } else {
  390                 /* Don't sort keys */
  391 
  392                 while (iter) {
  393                     void *next = json_object_iter_next((json_t *)json, iter);
  394                     const char *key = json_object_iter_key(iter);
  395                     const size_t key_len = json_object_iter_key_len(iter);
  396 
  397                     dump_string(key, key_len, dump, data, flags);
  398                     if (dump(separator, separator_length, data) ||
  399                         do_dump(json_object_iter_value(iter), flags, depth + 1, parents,
  400                                 dump, data))
  401                         return -1;
  402 
  403                     if (next) {
  404                         if (dump(",", 1, data) ||
  405                             dump_indent(flags, depth + 1, 1, dump, data))
  406                             return -1;
  407                     } else {
  408                         if (dump_indent(flags, depth, 0, dump, data))
  409                             return -1;
  410                     }
  411 
  412                     iter = next;
  413                 }
  414             }
  415 
  416             hashtable_del(parents, loop_key, loop_key_len);
  417             return embed ? 0 : dump("}", 1, data);
  418         }
  419 
  420         default:
  421             /* not reached */
  422             return -1;
  423     }
  424 }
  425 
  426 char *json_dumps(const json_t *json, size_t flags) {
  427     strbuffer_t strbuff;
  428     char *result;
  429 
  430     if (strbuffer_init(&strbuff))
  431         return NULL;
  432 
  433     if (json_dump_callback(json, dump_to_strbuffer, (void *)&strbuff, flags))
  434         result = NULL;
  435     else
  436         result = jsonp_strdup(strbuffer_value(&strbuff));
  437 
  438     strbuffer_close(&strbuff);
  439     return result;
  440 }
  441 
  442 size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags) {
  443     struct buffer buf = {size, 0, buffer};
  444 
  445     if (json_dump_callback(json, dump_to_buffer, (void *)&buf, flags))
  446         return 0;
  447 
  448     return buf.used;
  449 }
  450 
  451 int json_dumpf(const json_t *json, FILE *output, size_t flags) {
  452     return json_dump_callback(json, dump_to_file, (void *)output, flags);
  453 }
  454 
  455 int json_dumpfd(const json_t *json, int output, size_t flags) {
  456     return json_dump_callback(json, dump_to_fd, (void *)&output, flags);
  457 }
  458 
  459 int json_dump_file(const json_t *json, const char *path, size_t flags) {
  460     int result;
  461 
  462     FILE *output = fopen(path, "w");
  463     if (!output)
  464         return -1;
  465 
  466     result = json_dumpf(json, output, flags);
  467 
  468     if (fclose(output) != 0)
  469         return -1;
  470 
  471     return result;
  472 }
  473 
  474 int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data,
  475                        size_t flags) {
  476     int res;
  477     hashtable_t parents_set;
  478 
  479     if (!(flags & JSON_ENCODE_ANY)) {
  480         if (!json_is_array(json) && !json_is_object(json))
  481             return -1;
  482     }
  483 
  484     if (hashtable_init(&parents_set))
  485         return -1;
  486     res = do_dump(json, flags, 0, &parents_set, callback, data);
  487     hashtable_close(&parents_set);
  488 
  489     return res;
  490 }