qemu/qobject/qjson.c
<<
>>
Prefs
   1/*
   2 * QObject JSON integration
   3 *
   4 * Copyright IBM, Corp. 2009
   5 *
   6 * Authors:
   7 *  Anthony Liguori   <aliguori@us.ibm.com>
   8 *
   9 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  10 * See the COPYING.LIB file in the top-level directory.
  11 *
  12 */
  13
  14#include "qemu/osdep.h"
  15#include "qapi/error.h"
  16#include "qapi/qmp/json-lexer.h"
  17#include "qapi/qmp/json-parser.h"
  18#include "qapi/qmp/json-streamer.h"
  19#include "qapi/qmp/qjson.h"
  20#include "qapi/qmp/types.h"
  21#include "qemu/unicode.h"
  22
  23typedef struct JSONParsingState
  24{
  25    JSONMessageParser parser;
  26    va_list *ap;
  27    QObject *result;
  28    Error *err;
  29} JSONParsingState;
  30
  31static void parse_json(JSONMessageParser *parser, GQueue *tokens)
  32{
  33    JSONParsingState *s = container_of(parser, JSONParsingState, parser);
  34
  35    s->result = json_parser_parse_err(tokens, s->ap, &s->err);
  36}
  37
  38QObject *qobject_from_jsonv(const char *string, va_list *ap, Error **errp)
  39{
  40    JSONParsingState state = {};
  41
  42    state.ap = ap;
  43
  44    json_message_parser_init(&state.parser, parse_json);
  45    json_message_parser_feed(&state.parser, string, strlen(string));
  46    json_message_parser_flush(&state.parser);
  47    json_message_parser_destroy(&state.parser);
  48
  49    error_propagate(errp, state.err);
  50    return state.result;
  51}
  52
  53QObject *qobject_from_json(const char *string, Error **errp)
  54{
  55    return qobject_from_jsonv(string, NULL, errp);
  56}
  57
  58/*
  59 * IMPORTANT: This function aborts on error, thus it must not
  60 * be used with untrusted arguments.
  61 */
  62QObject *qobject_from_jsonf(const char *string, ...)
  63{
  64    QObject *obj;
  65    va_list ap;
  66
  67    va_start(ap, string);
  68    obj = qobject_from_jsonv(string, &ap, &error_abort);
  69    va_end(ap);
  70
  71    assert(obj != NULL);
  72    return obj;
  73}
  74
  75typedef struct ToJsonIterState
  76{
  77    int indent;
  78    int pretty;
  79    int count;
  80    QString *str;
  81} ToJsonIterState;
  82
  83static void to_json(const QObject *obj, QString *str, int pretty, int indent);
  84
  85static void to_json_dict_iter(const char *key, QObject *obj, void *opaque)
  86{
  87    ToJsonIterState *s = opaque;
  88    QString *qkey;
  89    int j;
  90
  91    if (s->count) {
  92        qstring_append(s->str, s->pretty ? "," : ", ");
  93    }
  94
  95    if (s->pretty) {
  96        qstring_append(s->str, "\n");
  97        for (j = 0 ; j < s->indent ; j++)
  98            qstring_append(s->str, "    ");
  99    }
 100
 101    qkey = qstring_from_str(key);
 102    to_json(QOBJECT(qkey), s->str, s->pretty, s->indent);
 103    QDECREF(qkey);
 104
 105    qstring_append(s->str, ": ");
 106    to_json(obj, s->str, s->pretty, s->indent);
 107    s->count++;
 108}
 109
 110static void to_json_list_iter(QObject *obj, void *opaque)
 111{
 112    ToJsonIterState *s = opaque;
 113    int j;
 114
 115    if (s->count) {
 116        qstring_append(s->str, s->pretty ? "," : ", ");
 117    }
 118
 119    if (s->pretty) {
 120        qstring_append(s->str, "\n");
 121        for (j = 0 ; j < s->indent ; j++)
 122            qstring_append(s->str, "    ");
 123    }
 124
 125    to_json(obj, s->str, s->pretty, s->indent);
 126    s->count++;
 127}
 128
 129static void to_json(const QObject *obj, QString *str, int pretty, int indent)
 130{
 131    switch (qobject_type(obj)) {
 132    case QTYPE_QNULL:
 133        qstring_append(str, "null");
 134        break;
 135    case QTYPE_QNUM: {
 136        QNum *val = qobject_to_qnum(obj);
 137        char *buffer = qnum_to_string(val);
 138        qstring_append(str, buffer);
 139        g_free(buffer);
 140        break;
 141    }
 142    case QTYPE_QSTRING: {
 143        QString *val = qobject_to_qstring(obj);
 144        const char *ptr;
 145        int cp;
 146        char buf[16];
 147        char *end;
 148
 149        ptr = qstring_get_str(val);
 150        qstring_append(str, "\"");
 151
 152        for (; *ptr; ptr = end) {
 153            cp = mod_utf8_codepoint(ptr, 6, &end);
 154            switch (cp) {
 155            case '\"':
 156                qstring_append(str, "\\\"");
 157                break;
 158            case '\\':
 159                qstring_append(str, "\\\\");
 160                break;
 161            case '\b':
 162                qstring_append(str, "\\b");
 163                break;
 164            case '\f':
 165                qstring_append(str, "\\f");
 166                break;
 167            case '\n':
 168                qstring_append(str, "\\n");
 169                break;
 170            case '\r':
 171                qstring_append(str, "\\r");
 172                break;
 173            case '\t':
 174                qstring_append(str, "\\t");
 175                break;
 176            default:
 177                if (cp < 0) {
 178                    cp = 0xFFFD; /* replacement character */
 179                }
 180                if (cp > 0xFFFF) {
 181                    /* beyond BMP; need a surrogate pair */
 182                    snprintf(buf, sizeof(buf), "\\u%04X\\u%04X",
 183                             0xD800 + ((cp - 0x10000) >> 10),
 184                             0xDC00 + ((cp - 0x10000) & 0x3FF));
 185                } else if (cp < 0x20 || cp >= 0x7F) {
 186                    snprintf(buf, sizeof(buf), "\\u%04X", cp);
 187                } else {
 188                    buf[0] = cp;
 189                    buf[1] = 0;
 190                }
 191                qstring_append(str, buf);
 192            }
 193        };
 194
 195        qstring_append(str, "\"");
 196        break;
 197    }
 198    case QTYPE_QDICT: {
 199        ToJsonIterState s;
 200        QDict *val = qobject_to_qdict(obj);
 201
 202        s.count = 0;
 203        s.str = str;
 204        s.indent = indent + 1;
 205        s.pretty = pretty;
 206        qstring_append(str, "{");
 207        qdict_iter(val, to_json_dict_iter, &s);
 208        if (pretty) {
 209            int j;
 210            qstring_append(str, "\n");
 211            for (j = 0 ; j < indent ; j++)
 212                qstring_append(str, "    ");
 213        }
 214        qstring_append(str, "}");
 215        break;
 216    }
 217    case QTYPE_QLIST: {
 218        ToJsonIterState s;
 219        QList *val = qobject_to_qlist(obj);
 220
 221        s.count = 0;
 222        s.str = str;
 223        s.indent = indent + 1;
 224        s.pretty = pretty;
 225        qstring_append(str, "[");
 226        qlist_iter(val, (void *)to_json_list_iter, &s);
 227        if (pretty) {
 228            int j;
 229            qstring_append(str, "\n");
 230            for (j = 0 ; j < indent ; j++)
 231                qstring_append(str, "    ");
 232        }
 233        qstring_append(str, "]");
 234        break;
 235    }
 236    case QTYPE_QBOOL: {
 237        QBool *val = qobject_to_qbool(obj);
 238
 239        if (qbool_get_bool(val)) {
 240            qstring_append(str, "true");
 241        } else {
 242            qstring_append(str, "false");
 243        }
 244        break;
 245    }
 246    default:
 247        abort();
 248    }
 249}
 250
 251QString *qobject_to_json(const QObject *obj)
 252{
 253    QString *str = qstring_new();
 254
 255    to_json(obj, str, 0, 0);
 256
 257    return str;
 258}
 259
 260QString *qobject_to_json_pretty(const QObject *obj)
 261{
 262    QString *str = qstring_new();
 263
 264    to_json(obj, str, 1, 0);
 265
 266    return str;
 267}
 268