Statistics
| Branch: | Revision:

root / qjson.c @ a74cdab4

History | View | Annotate | Download (7.3 kB)

1 b4748b9b Anthony Liguori
/*
2 b4748b9b Anthony Liguori
 * QObject JSON integration
3 b4748b9b Anthony Liguori
 *
4 b4748b9b Anthony Liguori
 * Copyright IBM, Corp. 2009
5 b4748b9b Anthony Liguori
 *
6 b4748b9b Anthony Liguori
 * Authors:
7 b4748b9b Anthony Liguori
 *  Anthony Liguori   <aliguori@us.ibm.com>
8 b4748b9b Anthony Liguori
 *
9 b4748b9b Anthony Liguori
 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
10 b4748b9b Anthony Liguori
 * See the COPYING.LIB file in the top-level directory.
11 b4748b9b Anthony Liguori
 *
12 b4748b9b Anthony Liguori
 */
13 b4748b9b Anthony Liguori
14 b4748b9b Anthony Liguori
#include "json-lexer.h"
15 b4748b9b Anthony Liguori
#include "json-parser.h"
16 b4748b9b Anthony Liguori
#include "json-streamer.h"
17 b4748b9b Anthony Liguori
#include "qjson.h"
18 1fd825f7 Anthony Liguori
#include "qint.h"
19 1fd825f7 Anthony Liguori
#include "qlist.h"
20 1fd825f7 Anthony Liguori
#include "qbool.h"
21 1fd825f7 Anthony Liguori
#include "qfloat.h"
22 1fd825f7 Anthony Liguori
#include "qdict.h"
23 b4748b9b Anthony Liguori
24 b4748b9b Anthony Liguori
typedef struct JSONParsingState
25 b4748b9b Anthony Liguori
{
26 b4748b9b Anthony Liguori
    JSONMessageParser parser;
27 b4748b9b Anthony Liguori
    va_list *ap;
28 b4748b9b Anthony Liguori
    QObject *result;
29 b4748b9b Anthony Liguori
} JSONParsingState;
30 b4748b9b Anthony Liguori
31 b4748b9b Anthony Liguori
static void parse_json(JSONMessageParser *parser, QList *tokens)
32 b4748b9b Anthony Liguori
{
33 b4748b9b Anthony Liguori
    JSONParsingState *s = container_of(parser, JSONParsingState, parser);
34 b4748b9b Anthony Liguori
    s->result = json_parser_parse(tokens, s->ap);
35 b4748b9b Anthony Liguori
}
36 b4748b9b Anthony Liguori
37 8ff5a7d3 Luiz Capitulino
QObject *qobject_from_jsonv(const char *string, va_list *ap)
38 b4748b9b Anthony Liguori
{
39 b4748b9b Anthony Liguori
    JSONParsingState state = {};
40 b4748b9b Anthony Liguori
41 8ff5a7d3 Luiz Capitulino
    state.ap = ap;
42 8ff5a7d3 Luiz Capitulino
43 b4748b9b Anthony Liguori
    json_message_parser_init(&state.parser, parse_json);
44 b4748b9b Anthony Liguori
    json_message_parser_feed(&state.parser, string, strlen(string));
45 b4748b9b Anthony Liguori
    json_message_parser_flush(&state.parser);
46 b4748b9b Anthony Liguori
    json_message_parser_destroy(&state.parser);
47 b4748b9b Anthony Liguori
48 b4748b9b Anthony Liguori
    return state.result;
49 b4748b9b Anthony Liguori
}
50 b4748b9b Anthony Liguori
51 8ff5a7d3 Luiz Capitulino
QObject *qobject_from_json(const char *string)
52 8ff5a7d3 Luiz Capitulino
{
53 8ff5a7d3 Luiz Capitulino
    return qobject_from_jsonv(string, NULL);
54 8ff5a7d3 Luiz Capitulino
}
55 8ff5a7d3 Luiz Capitulino
56 668e3cac Luiz Capitulino
/*
57 668e3cac Luiz Capitulino
 * IMPORTANT: This function aborts on error, thus it must not
58 668e3cac Luiz Capitulino
 * be used with untrusted arguments.
59 668e3cac Luiz Capitulino
 */
60 b4748b9b Anthony Liguori
QObject *qobject_from_jsonf(const char *string, ...)
61 b4748b9b Anthony Liguori
{
62 8ff5a7d3 Luiz Capitulino
    QObject *obj;
63 b4748b9b Anthony Liguori
    va_list ap;
64 b4748b9b Anthony Liguori
65 b4748b9b Anthony Liguori
    va_start(ap, string);
66 8ff5a7d3 Luiz Capitulino
    obj = qobject_from_jsonv(string, &ap);
67 b4748b9b Anthony Liguori
    va_end(ap);
68 b4748b9b Anthony Liguori
69 668e3cac Luiz Capitulino
    assert(obj != NULL);
70 8ff5a7d3 Luiz Capitulino
    return obj;
71 b4748b9b Anthony Liguori
}
72 1fd825f7 Anthony Liguori
73 1fd825f7 Anthony Liguori
typedef struct ToJsonIterState
74 1fd825f7 Anthony Liguori
{
75 212b6008 Daniel P. Berrange
    int indent;
76 212b6008 Daniel P. Berrange
    int pretty;
77 1fd825f7 Anthony Liguori
    int count;
78 1fd825f7 Anthony Liguori
    QString *str;
79 1fd825f7 Anthony Liguori
} ToJsonIterState;
80 1fd825f7 Anthony Liguori
81 212b6008 Daniel P. Berrange
static void to_json(const QObject *obj, QString *str, int pretty, int indent);
82 1fd825f7 Anthony Liguori
83 1fd825f7 Anthony Liguori
static void to_json_dict_iter(const char *key, QObject *obj, void *opaque)
84 1fd825f7 Anthony Liguori
{
85 1fd825f7 Anthony Liguori
    ToJsonIterState *s = opaque;
86 1fd825f7 Anthony Liguori
    QString *qkey;
87 212b6008 Daniel P. Berrange
    int j;
88 1fd825f7 Anthony Liguori
89 212b6008 Daniel P. Berrange
    if (s->count)
90 1fd825f7 Anthony Liguori
        qstring_append(s->str, ", ");
91 212b6008 Daniel P. Berrange
92 212b6008 Daniel P. Berrange
    if (s->pretty) {
93 212b6008 Daniel P. Berrange
        qstring_append(s->str, "\n");
94 212b6008 Daniel P. Berrange
        for (j = 0 ; j < s->indent ; j++)
95 212b6008 Daniel P. Berrange
            qstring_append(s->str, "    ");
96 1fd825f7 Anthony Liguori
    }
97 1fd825f7 Anthony Liguori
98 1fd825f7 Anthony Liguori
    qkey = qstring_from_str(key);
99 212b6008 Daniel P. Berrange
    to_json(QOBJECT(qkey), s->str, s->pretty, s->indent);
100 1fd825f7 Anthony Liguori
    QDECREF(qkey);
101 1fd825f7 Anthony Liguori
102 1fd825f7 Anthony Liguori
    qstring_append(s->str, ": ");
103 212b6008 Daniel P. Berrange
    to_json(obj, s->str, s->pretty, s->indent);
104 1fd825f7 Anthony Liguori
    s->count++;
105 1fd825f7 Anthony Liguori
}
106 1fd825f7 Anthony Liguori
107 1fd825f7 Anthony Liguori
static void to_json_list_iter(QObject *obj, void *opaque)
108 1fd825f7 Anthony Liguori
{
109 1fd825f7 Anthony Liguori
    ToJsonIterState *s = opaque;
110 212b6008 Daniel P. Berrange
    int j;
111 1fd825f7 Anthony Liguori
112 212b6008 Daniel P. Berrange
    if (s->count)
113 1fd825f7 Anthony Liguori
        qstring_append(s->str, ", ");
114 212b6008 Daniel P. Berrange
115 212b6008 Daniel P. Berrange
    if (s->pretty) {
116 212b6008 Daniel P. Berrange
        qstring_append(s->str, "\n");
117 212b6008 Daniel P. Berrange
        for (j = 0 ; j < s->indent ; j++)
118 212b6008 Daniel P. Berrange
            qstring_append(s->str, "    ");
119 1fd825f7 Anthony Liguori
    }
120 1fd825f7 Anthony Liguori
121 212b6008 Daniel P. Berrange
    to_json(obj, s->str, s->pretty, s->indent);
122 1fd825f7 Anthony Liguori
    s->count++;
123 1fd825f7 Anthony Liguori
}
124 1fd825f7 Anthony Liguori
125 212b6008 Daniel P. Berrange
static void to_json(const QObject *obj, QString *str, int pretty, int indent)
126 1fd825f7 Anthony Liguori
{
127 1fd825f7 Anthony Liguori
    switch (qobject_type(obj)) {
128 1fd825f7 Anthony Liguori
    case QTYPE_QINT: {
129 1fd825f7 Anthony Liguori
        QInt *val = qobject_to_qint(obj);
130 1fd825f7 Anthony Liguori
        char buffer[1024];
131 1fd825f7 Anthony Liguori
132 1fd825f7 Anthony Liguori
        snprintf(buffer, sizeof(buffer), "%" PRId64, qint_get_int(val));
133 1fd825f7 Anthony Liguori
        qstring_append(str, buffer);
134 1fd825f7 Anthony Liguori
        break;
135 1fd825f7 Anthony Liguori
    }
136 1fd825f7 Anthony Liguori
    case QTYPE_QSTRING: {
137 1fd825f7 Anthony Liguori
        QString *val = qobject_to_qstring(obj);
138 1fd825f7 Anthony Liguori
        const char *ptr;
139 1fd825f7 Anthony Liguori
140 1fd825f7 Anthony Liguori
        ptr = qstring_get_str(val);
141 1fd825f7 Anthony Liguori
        qstring_append(str, "\"");
142 1fd825f7 Anthony Liguori
        while (*ptr) {
143 1fd825f7 Anthony Liguori
            if ((ptr[0] & 0xE0) == 0xE0 &&
144 1fd825f7 Anthony Liguori
                (ptr[1] & 0x80) && (ptr[2] & 0x80)) {
145 1fd825f7 Anthony Liguori
                uint16_t wchar;
146 1fd825f7 Anthony Liguori
                char escape[7];
147 1fd825f7 Anthony Liguori
148 1fd825f7 Anthony Liguori
                wchar  = (ptr[0] & 0x0F) << 12;
149 1fd825f7 Anthony Liguori
                wchar |= (ptr[1] & 0x3F) << 6;
150 1fd825f7 Anthony Liguori
                wchar |= (ptr[2] & 0x3F);
151 1fd825f7 Anthony Liguori
                ptr += 2;
152 1fd825f7 Anthony Liguori
153 1fd825f7 Anthony Liguori
                snprintf(escape, sizeof(escape), "\\u%04X", wchar);
154 1fd825f7 Anthony Liguori
                qstring_append(str, escape);
155 1fd825f7 Anthony Liguori
            } else if ((ptr[0] & 0xE0) == 0xC0 && (ptr[1] & 0x80)) {
156 1fd825f7 Anthony Liguori
                uint16_t wchar;
157 1fd825f7 Anthony Liguori
                char escape[7];
158 1fd825f7 Anthony Liguori
159 1fd825f7 Anthony Liguori
                wchar  = (ptr[0] & 0x1F) << 6;
160 1fd825f7 Anthony Liguori
                wchar |= (ptr[1] & 0x3F);
161 1fd825f7 Anthony Liguori
                ptr++;
162 1fd825f7 Anthony Liguori
163 1fd825f7 Anthony Liguori
                snprintf(escape, sizeof(escape), "\\u%04X", wchar);
164 1fd825f7 Anthony Liguori
                qstring_append(str, escape);
165 1fd825f7 Anthony Liguori
            } else switch (ptr[0]) {
166 1fd825f7 Anthony Liguori
                case '\"':
167 1fd825f7 Anthony Liguori
                    qstring_append(str, "\\\"");
168 1fd825f7 Anthony Liguori
                    break;
169 1fd825f7 Anthony Liguori
                case '\\':
170 1fd825f7 Anthony Liguori
                    qstring_append(str, "\\\\");
171 1fd825f7 Anthony Liguori
                    break;
172 1fd825f7 Anthony Liguori
                case '\b':
173 1fd825f7 Anthony Liguori
                    qstring_append(str, "\\b");
174 1fd825f7 Anthony Liguori
                    break;
175 bd032695 Luiz Capitulino
                case '\f':
176 bd032695 Luiz Capitulino
                    qstring_append(str, "\\f");
177 bd032695 Luiz Capitulino
                    break;
178 1fd825f7 Anthony Liguori
                case '\n':
179 1fd825f7 Anthony Liguori
                    qstring_append(str, "\\n");
180 1fd825f7 Anthony Liguori
                    break;
181 1fd825f7 Anthony Liguori
                case '\r':
182 1fd825f7 Anthony Liguori
                    qstring_append(str, "\\r");
183 1fd825f7 Anthony Liguori
                    break;
184 1fd825f7 Anthony Liguori
                case '\t':
185 1fd825f7 Anthony Liguori
                    qstring_append(str, "\\t");
186 1fd825f7 Anthony Liguori
                    break;
187 1fd825f7 Anthony Liguori
                default: {
188 ff06ea21 Anthony Liguori
                    if (ptr[0] <= 0x1F) {
189 ff06ea21 Anthony Liguori
                        char escape[7];
190 ff06ea21 Anthony Liguori
                        snprintf(escape, sizeof(escape), "\\u%04X", ptr[0]);
191 ff06ea21 Anthony Liguori
                        qstring_append(str, escape);
192 ff06ea21 Anthony Liguori
                    } else {
193 ff06ea21 Anthony Liguori
                        char buf[2] = { ptr[0], 0 };
194 ff06ea21 Anthony Liguori
                        qstring_append(str, buf);
195 ff06ea21 Anthony Liguori
                    }
196 1fd825f7 Anthony Liguori
                    break;
197 1fd825f7 Anthony Liguori
                }
198 1fd825f7 Anthony Liguori
                }
199 1fd825f7 Anthony Liguori
            ptr++;
200 1fd825f7 Anthony Liguori
        }
201 1fd825f7 Anthony Liguori
        qstring_append(str, "\"");
202 1fd825f7 Anthony Liguori
        break;
203 1fd825f7 Anthony Liguori
    }
204 1fd825f7 Anthony Liguori
    case QTYPE_QDICT: {
205 1fd825f7 Anthony Liguori
        ToJsonIterState s;
206 1fd825f7 Anthony Liguori
        QDict *val = qobject_to_qdict(obj);
207 1fd825f7 Anthony Liguori
208 1fd825f7 Anthony Liguori
        s.count = 0;
209 1fd825f7 Anthony Liguori
        s.str = str;
210 212b6008 Daniel P. Berrange
        s.indent = indent + 1;
211 212b6008 Daniel P. Berrange
        s.pretty = pretty;
212 1fd825f7 Anthony Liguori
        qstring_append(str, "{");
213 1fd825f7 Anthony Liguori
        qdict_iter(val, to_json_dict_iter, &s);
214 212b6008 Daniel P. Berrange
        if (pretty) {
215 212b6008 Daniel P. Berrange
            int j;
216 212b6008 Daniel P. Berrange
            qstring_append(str, "\n");
217 212b6008 Daniel P. Berrange
            for (j = 0 ; j < indent ; j++)
218 212b6008 Daniel P. Berrange
                qstring_append(str, "    ");
219 212b6008 Daniel P. Berrange
        }
220 1fd825f7 Anthony Liguori
        qstring_append(str, "}");
221 1fd825f7 Anthony Liguori
        break;
222 1fd825f7 Anthony Liguori
    }
223 1fd825f7 Anthony Liguori
    case QTYPE_QLIST: {
224 1fd825f7 Anthony Liguori
        ToJsonIterState s;
225 1fd825f7 Anthony Liguori
        QList *val = qobject_to_qlist(obj);
226 1fd825f7 Anthony Liguori
227 1fd825f7 Anthony Liguori
        s.count = 0;
228 1fd825f7 Anthony Liguori
        s.str = str;
229 212b6008 Daniel P. Berrange
        s.indent = indent + 1;
230 212b6008 Daniel P. Berrange
        s.pretty = pretty;
231 1fd825f7 Anthony Liguori
        qstring_append(str, "[");
232 1fd825f7 Anthony Liguori
        qlist_iter(val, (void *)to_json_list_iter, &s);
233 212b6008 Daniel P. Berrange
        if (pretty) {
234 212b6008 Daniel P. Berrange
            int j;
235 212b6008 Daniel P. Berrange
            qstring_append(str, "\n");
236 212b6008 Daniel P. Berrange
            for (j = 0 ; j < indent ; j++)
237 212b6008 Daniel P. Berrange
                qstring_append(str, "    ");
238 212b6008 Daniel P. Berrange
        }
239 1fd825f7 Anthony Liguori
        qstring_append(str, "]");
240 1fd825f7 Anthony Liguori
        break;
241 1fd825f7 Anthony Liguori
    }
242 1fd825f7 Anthony Liguori
    case QTYPE_QFLOAT: {
243 1fd825f7 Anthony Liguori
        QFloat *val = qobject_to_qfloat(obj);
244 1fd825f7 Anthony Liguori
        char buffer[1024];
245 1fd825f7 Anthony Liguori
        int len;
246 1fd825f7 Anthony Liguori
247 1fd825f7 Anthony Liguori
        len = snprintf(buffer, sizeof(buffer), "%f", qfloat_get_double(val));
248 1fd825f7 Anthony Liguori
        while (len > 0 && buffer[len - 1] == '0') {
249 1fd825f7 Anthony Liguori
            len--;
250 1fd825f7 Anthony Liguori
        }
251 1fd825f7 Anthony Liguori
252 1fd825f7 Anthony Liguori
        if (len && buffer[len - 1] == '.') {
253 1fd825f7 Anthony Liguori
            buffer[len - 1] = 0;
254 1fd825f7 Anthony Liguori
        } else {
255 1fd825f7 Anthony Liguori
            buffer[len] = 0;
256 1fd825f7 Anthony Liguori
        }
257 1fd825f7 Anthony Liguori
        
258 1fd825f7 Anthony Liguori
        qstring_append(str, buffer);
259 1fd825f7 Anthony Liguori
        break;
260 1fd825f7 Anthony Liguori
    }
261 1fd825f7 Anthony Liguori
    case QTYPE_QBOOL: {
262 1fd825f7 Anthony Liguori
        QBool *val = qobject_to_qbool(obj);
263 1fd825f7 Anthony Liguori
264 1fd825f7 Anthony Liguori
        if (qbool_get_int(val)) {
265 1fd825f7 Anthony Liguori
            qstring_append(str, "true");
266 1fd825f7 Anthony Liguori
        } else {
267 1fd825f7 Anthony Liguori
            qstring_append(str, "false");
268 1fd825f7 Anthony Liguori
        }
269 1fd825f7 Anthony Liguori
        break;
270 1fd825f7 Anthony Liguori
    }
271 9f9daf9a Luiz Capitulino
    case QTYPE_QERROR:
272 9f9daf9a Luiz Capitulino
        /* XXX: should QError be emitted? */
273 1fd825f7 Anthony Liguori
    case QTYPE_NONE:
274 1fd825f7 Anthony Liguori
        break;
275 1fd825f7 Anthony Liguori
    }
276 1fd825f7 Anthony Liguori
}
277 1fd825f7 Anthony Liguori
278 1fd825f7 Anthony Liguori
QString *qobject_to_json(const QObject *obj)
279 1fd825f7 Anthony Liguori
{
280 1fd825f7 Anthony Liguori
    QString *str = qstring_new();
281 1fd825f7 Anthony Liguori
282 212b6008 Daniel P. Berrange
    to_json(obj, str, 0, 0);
283 212b6008 Daniel P. Berrange
284 212b6008 Daniel P. Berrange
    return str;
285 212b6008 Daniel P. Berrange
}
286 212b6008 Daniel P. Berrange
287 212b6008 Daniel P. Berrange
QString *qobject_to_json_pretty(const QObject *obj)
288 212b6008 Daniel P. Berrange
{
289 212b6008 Daniel P. Berrange
    QString *str = qstring_new();
290 212b6008 Daniel P. Berrange
291 212b6008 Daniel P. Berrange
    to_json(obj, str, 1, 0);
292 1fd825f7 Anthony Liguori
293 1fd825f7 Anthony Liguori
    return str;
294 1fd825f7 Anthony Liguori
}