cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

json-writer.c (6646B)


      1/*
      2 * JSON Writer
      3 *
      4 * Copyright IBM, Corp. 2009
      5 * Copyright (c) 2010-2020 Red Hat Inc.
      6 *
      7 * Authors:
      8 *  Anthony Liguori   <aliguori@us.ibm.com>
      9 *  Markus Armbruster <armbru@redhat.com>
     10 *
     11 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
     12 * See the COPYING.LIB file in the top-level directory.
     13 *
     14 */
     15
     16#include "qemu/osdep.h"
     17#include "qapi/qmp/json-writer.h"
     18#include "qemu/unicode.h"
     19
     20struct JSONWriter {
     21    bool pretty;
     22    bool need_comma;
     23    GString *contents;
     24    GByteArray *container_is_array;
     25};
     26
     27JSONWriter *json_writer_new(bool pretty)
     28{
     29    JSONWriter *writer = g_new(JSONWriter, 1);
     30
     31    writer->pretty = pretty;
     32    writer->need_comma = false;
     33    writer->contents = g_string_new(NULL);
     34    writer->container_is_array = g_byte_array_new();
     35    return writer;
     36}
     37
     38const char *json_writer_get(JSONWriter *writer)
     39{
     40    g_assert(!writer->container_is_array->len);
     41    return writer->contents->str;
     42}
     43
     44GString *json_writer_get_and_free(JSONWriter *writer)
     45{
     46    GString *contents = writer->contents;
     47
     48    writer->contents = NULL;
     49    g_byte_array_free(writer->container_is_array, true);
     50    g_free(writer);
     51    return contents;
     52}
     53
     54void json_writer_free(JSONWriter *writer)
     55{
     56    if (writer) {
     57        g_string_free(json_writer_get_and_free(writer), true);
     58    }
     59}
     60
     61static void enter_container(JSONWriter *writer, bool is_array)
     62{
     63    unsigned depth = writer->container_is_array->len;
     64
     65    g_byte_array_set_size(writer->container_is_array, depth + 1);
     66    writer->container_is_array->data[depth] = is_array;
     67    writer->need_comma = false;
     68}
     69
     70static void leave_container(JSONWriter *writer, bool is_array)
     71{
     72    unsigned depth = writer->container_is_array->len;
     73
     74    assert(depth);
     75    assert(writer->container_is_array->data[depth - 1] == is_array);
     76    g_byte_array_set_size(writer->container_is_array, depth - 1);
     77    writer->need_comma = true;
     78}
     79
     80static bool in_object(JSONWriter *writer)
     81{
     82    unsigned depth = writer->container_is_array->len;
     83
     84    return depth && !writer->container_is_array->data[depth - 1];
     85}
     86
     87static void pretty_newline(JSONWriter *writer)
     88{
     89    if (writer->pretty) {
     90        g_string_append_printf(writer->contents, "\n%*s",
     91                               writer->container_is_array->len * 4, "");
     92    }
     93}
     94
     95static void pretty_newline_or_space(JSONWriter *writer)
     96{
     97    if (writer->pretty) {
     98        g_string_append_printf(writer->contents, "\n%*s",
     99                               writer->container_is_array->len * 4, "");
    100    } else {
    101        g_string_append_c(writer->contents, ' ');
    102    }
    103}
    104
    105static void quoted_str(JSONWriter *writer, const char *str)
    106{
    107    const char *ptr;
    108    char *end;
    109    int cp;
    110
    111    g_string_append_c(writer->contents, '"');
    112
    113    for (ptr = str; *ptr; ptr = end) {
    114        cp = mod_utf8_codepoint(ptr, 6, &end);
    115        switch (cp) {
    116        case '\"':
    117            g_string_append(writer->contents, "\\\"");
    118            break;
    119        case '\\':
    120            g_string_append(writer->contents, "\\\\");
    121            break;
    122        case '\b':
    123            g_string_append(writer->contents, "\\b");
    124            break;
    125        case '\f':
    126            g_string_append(writer->contents, "\\f");
    127            break;
    128        case '\n':
    129            g_string_append(writer->contents, "\\n");
    130            break;
    131        case '\r':
    132            g_string_append(writer->contents, "\\r");
    133            break;
    134        case '\t':
    135            g_string_append(writer->contents, "\\t");
    136            break;
    137        default:
    138            if (cp < 0) {
    139                cp = 0xFFFD; /* replacement character */
    140            }
    141            if (cp > 0xFFFF) {
    142                /* beyond BMP; need a surrogate pair */
    143                g_string_append_printf(writer->contents, "\\u%04X\\u%04X",
    144                                       0xD800 + ((cp - 0x10000) >> 10),
    145                                       0xDC00 + ((cp - 0x10000) & 0x3FF));
    146            } else if (cp < 0x20 || cp >= 0x7F) {
    147                g_string_append_printf(writer->contents, "\\u%04X", cp);
    148            } else {
    149                g_string_append_c(writer->contents, cp);
    150            }
    151        }
    152    };
    153
    154    g_string_append_c(writer->contents, '"');
    155}
    156
    157static void maybe_comma_name(JSONWriter *writer, const char *name)
    158{
    159    if (writer->need_comma) {
    160        g_string_append_c(writer->contents, ',');
    161        pretty_newline_or_space(writer);
    162    } else {
    163        if (writer->contents->len) {
    164            pretty_newline(writer);
    165        }
    166        writer->need_comma = true;
    167    }
    168
    169    if (in_object(writer)) {
    170        quoted_str(writer, name);
    171        g_string_append(writer->contents, ": ");
    172    }
    173}
    174
    175void json_writer_start_object(JSONWriter *writer, const char *name)
    176{
    177    maybe_comma_name(writer, name);
    178    g_string_append_c(writer->contents, '{');
    179    enter_container(writer, false);
    180}
    181
    182void json_writer_end_object(JSONWriter *writer)
    183{
    184    leave_container(writer, false);
    185    pretty_newline(writer);
    186    g_string_append_c(writer->contents, '}');
    187}
    188
    189void json_writer_start_array(JSONWriter *writer, const char *name)
    190{
    191    maybe_comma_name(writer, name);
    192    g_string_append_c(writer->contents, '[');
    193    enter_container(writer, true);
    194}
    195
    196void json_writer_end_array(JSONWriter *writer)
    197{
    198    leave_container(writer, true);
    199    pretty_newline(writer);
    200    g_string_append_c(writer->contents, ']');
    201}
    202
    203void json_writer_bool(JSONWriter *writer, const char *name, bool val)
    204{
    205    maybe_comma_name(writer, name);
    206    g_string_append(writer->contents, val ? "true" : "false");
    207}
    208
    209void json_writer_null(JSONWriter *writer, const char *name)
    210{
    211    maybe_comma_name(writer, name);
    212    g_string_append(writer->contents, "null");
    213}
    214
    215void json_writer_int64(JSONWriter *writer, const char *name, int64_t val)
    216{
    217    maybe_comma_name(writer, name);
    218    g_string_append_printf(writer->contents, "%" PRId64, val);
    219}
    220
    221void json_writer_uint64(JSONWriter *writer, const char *name, uint64_t val)
    222{
    223    maybe_comma_name(writer, name);
    224    g_string_append_printf(writer->contents, "%" PRIu64, val);
    225}
    226
    227void json_writer_double(JSONWriter *writer, const char *name, double val)
    228{
    229    maybe_comma_name(writer, name);
    230
    231    /*
    232     * FIXME: g_string_append_printf() is locale dependent; but JSON
    233     * requires numbers to be formatted as if in the C locale.
    234     * Dependence on C locale is a pervasive issue in QEMU.
    235     */
    236    /*
    237     * FIXME: This risks printing Inf or NaN, which are not valid
    238     * JSON values.
    239     */
    240    g_string_append_printf(writer->contents, "%.17g", val);
    241}
    242
    243void json_writer_str(JSONWriter *writer, const char *name, const char *str)
    244{
    245    maybe_comma_name(writer, name);
    246    quoted_str(writer, str);
    247}