"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.

    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 }