Statistics
| Branch: | Revision:

root / qjson.c @ a10f9f4f

History | View | Annotate | Download (6.1 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 1fd825f7 Anthony Liguori
    int count;
76 1fd825f7 Anthony Liguori
    QString *str;
77 1fd825f7 Anthony Liguori
} ToJsonIterState;
78 1fd825f7 Anthony Liguori
79 1fd825f7 Anthony Liguori
static void to_json(const QObject *obj, QString *str);
80 1fd825f7 Anthony Liguori
81 1fd825f7 Anthony Liguori
static void to_json_dict_iter(const char *key, QObject *obj, void *opaque)
82 1fd825f7 Anthony Liguori
{
83 1fd825f7 Anthony Liguori
    ToJsonIterState *s = opaque;
84 1fd825f7 Anthony Liguori
    QString *qkey;
85 1fd825f7 Anthony Liguori
86 1fd825f7 Anthony Liguori
    if (s->count) {
87 1fd825f7 Anthony Liguori
        qstring_append(s->str, ", ");
88 1fd825f7 Anthony Liguori
    }
89 1fd825f7 Anthony Liguori
90 1fd825f7 Anthony Liguori
    qkey = qstring_from_str(key);
91 1fd825f7 Anthony Liguori
    to_json(QOBJECT(qkey), s->str);
92 1fd825f7 Anthony Liguori
    QDECREF(qkey);
93 1fd825f7 Anthony Liguori
94 1fd825f7 Anthony Liguori
    qstring_append(s->str, ": ");
95 1fd825f7 Anthony Liguori
    to_json(obj, s->str);
96 1fd825f7 Anthony Liguori
    s->count++;
97 1fd825f7 Anthony Liguori
}
98 1fd825f7 Anthony Liguori
99 1fd825f7 Anthony Liguori
static void to_json_list_iter(QObject *obj, void *opaque)
100 1fd825f7 Anthony Liguori
{
101 1fd825f7 Anthony Liguori
    ToJsonIterState *s = opaque;
102 1fd825f7 Anthony Liguori
103 1fd825f7 Anthony Liguori
    if (s->count) {
104 1fd825f7 Anthony Liguori
        qstring_append(s->str, ", ");
105 1fd825f7 Anthony Liguori
    }
106 1fd825f7 Anthony Liguori
107 1fd825f7 Anthony Liguori
    to_json(obj, s->str);
108 1fd825f7 Anthony Liguori
    s->count++;
109 1fd825f7 Anthony Liguori
}
110 1fd825f7 Anthony Liguori
111 1fd825f7 Anthony Liguori
static void to_json(const QObject *obj, QString *str)
112 1fd825f7 Anthony Liguori
{
113 1fd825f7 Anthony Liguori
    switch (qobject_type(obj)) {
114 1fd825f7 Anthony Liguori
    case QTYPE_QINT: {
115 1fd825f7 Anthony Liguori
        QInt *val = qobject_to_qint(obj);
116 1fd825f7 Anthony Liguori
        char buffer[1024];
117 1fd825f7 Anthony Liguori
118 1fd825f7 Anthony Liguori
        snprintf(buffer, sizeof(buffer), "%" PRId64, qint_get_int(val));
119 1fd825f7 Anthony Liguori
        qstring_append(str, buffer);
120 1fd825f7 Anthony Liguori
        break;
121 1fd825f7 Anthony Liguori
    }
122 1fd825f7 Anthony Liguori
    case QTYPE_QSTRING: {
123 1fd825f7 Anthony Liguori
        QString *val = qobject_to_qstring(obj);
124 1fd825f7 Anthony Liguori
        const char *ptr;
125 1fd825f7 Anthony Liguori
126 1fd825f7 Anthony Liguori
        ptr = qstring_get_str(val);
127 1fd825f7 Anthony Liguori
        qstring_append(str, "\"");
128 1fd825f7 Anthony Liguori
        while (*ptr) {
129 1fd825f7 Anthony Liguori
            if ((ptr[0] & 0xE0) == 0xE0 &&
130 1fd825f7 Anthony Liguori
                (ptr[1] & 0x80) && (ptr[2] & 0x80)) {
131 1fd825f7 Anthony Liguori
                uint16_t wchar;
132 1fd825f7 Anthony Liguori
                char escape[7];
133 1fd825f7 Anthony Liguori
134 1fd825f7 Anthony Liguori
                wchar  = (ptr[0] & 0x0F) << 12;
135 1fd825f7 Anthony Liguori
                wchar |= (ptr[1] & 0x3F) << 6;
136 1fd825f7 Anthony Liguori
                wchar |= (ptr[2] & 0x3F);
137 1fd825f7 Anthony Liguori
                ptr += 2;
138 1fd825f7 Anthony Liguori
139 1fd825f7 Anthony Liguori
                snprintf(escape, sizeof(escape), "\\u%04X", wchar);
140 1fd825f7 Anthony Liguori
                qstring_append(str, escape);
141 1fd825f7 Anthony Liguori
            } else if ((ptr[0] & 0xE0) == 0xC0 && (ptr[1] & 0x80)) {
142 1fd825f7 Anthony Liguori
                uint16_t wchar;
143 1fd825f7 Anthony Liguori
                char escape[7];
144 1fd825f7 Anthony Liguori
145 1fd825f7 Anthony Liguori
                wchar  = (ptr[0] & 0x1F) << 6;
146 1fd825f7 Anthony Liguori
                wchar |= (ptr[1] & 0x3F);
147 1fd825f7 Anthony Liguori
                ptr++;
148 1fd825f7 Anthony Liguori
149 1fd825f7 Anthony Liguori
                snprintf(escape, sizeof(escape), "\\u%04X", wchar);
150 1fd825f7 Anthony Liguori
                qstring_append(str, escape);
151 1fd825f7 Anthony Liguori
            } else switch (ptr[0]) {
152 1fd825f7 Anthony Liguori
                case '\"':
153 1fd825f7 Anthony Liguori
                    qstring_append(str, "\\\"");
154 1fd825f7 Anthony Liguori
                    break;
155 1fd825f7 Anthony Liguori
                case '\\':
156 1fd825f7 Anthony Liguori
                    qstring_append(str, "\\\\");
157 1fd825f7 Anthony Liguori
                    break;
158 1fd825f7 Anthony Liguori
                case '\b':
159 1fd825f7 Anthony Liguori
                    qstring_append(str, "\\b");
160 1fd825f7 Anthony Liguori
                    break;
161 1fd825f7 Anthony Liguori
                case '\n':
162 1fd825f7 Anthony Liguori
                    qstring_append(str, "\\n");
163 1fd825f7 Anthony Liguori
                    break;
164 1fd825f7 Anthony Liguori
                case '\r':
165 1fd825f7 Anthony Liguori
                    qstring_append(str, "\\r");
166 1fd825f7 Anthony Liguori
                    break;
167 1fd825f7 Anthony Liguori
                case '\t':
168 1fd825f7 Anthony Liguori
                    qstring_append(str, "\\t");
169 1fd825f7 Anthony Liguori
                    break;
170 1fd825f7 Anthony Liguori
                default: {
171 ff06ea21 Anthony Liguori
                    if (ptr[0] <= 0x1F) {
172 ff06ea21 Anthony Liguori
                        char escape[7];
173 ff06ea21 Anthony Liguori
                        snprintf(escape, sizeof(escape), "\\u%04X", ptr[0]);
174 ff06ea21 Anthony Liguori
                        qstring_append(str, escape);
175 ff06ea21 Anthony Liguori
                    } else {
176 ff06ea21 Anthony Liguori
                        char buf[2] = { ptr[0], 0 };
177 ff06ea21 Anthony Liguori
                        qstring_append(str, buf);
178 ff06ea21 Anthony Liguori
                    }
179 1fd825f7 Anthony Liguori
                    break;
180 1fd825f7 Anthony Liguori
                }
181 1fd825f7 Anthony Liguori
                }
182 1fd825f7 Anthony Liguori
            ptr++;
183 1fd825f7 Anthony Liguori
        }
184 1fd825f7 Anthony Liguori
        qstring_append(str, "\"");
185 1fd825f7 Anthony Liguori
        break;
186 1fd825f7 Anthony Liguori
    }
187 1fd825f7 Anthony Liguori
    case QTYPE_QDICT: {
188 1fd825f7 Anthony Liguori
        ToJsonIterState s;
189 1fd825f7 Anthony Liguori
        QDict *val = qobject_to_qdict(obj);
190 1fd825f7 Anthony Liguori
191 1fd825f7 Anthony Liguori
        s.count = 0;
192 1fd825f7 Anthony Liguori
        s.str = str;
193 1fd825f7 Anthony Liguori
        qstring_append(str, "{");
194 1fd825f7 Anthony Liguori
        qdict_iter(val, to_json_dict_iter, &s);
195 1fd825f7 Anthony Liguori
        qstring_append(str, "}");
196 1fd825f7 Anthony Liguori
        break;
197 1fd825f7 Anthony Liguori
    }
198 1fd825f7 Anthony Liguori
    case QTYPE_QLIST: {
199 1fd825f7 Anthony Liguori
        ToJsonIterState s;
200 1fd825f7 Anthony Liguori
        QList *val = qobject_to_qlist(obj);
201 1fd825f7 Anthony Liguori
202 1fd825f7 Anthony Liguori
        s.count = 0;
203 1fd825f7 Anthony Liguori
        s.str = str;
204 1fd825f7 Anthony Liguori
        qstring_append(str, "[");
205 1fd825f7 Anthony Liguori
        qlist_iter(val, (void *)to_json_list_iter, &s);
206 1fd825f7 Anthony Liguori
        qstring_append(str, "]");
207 1fd825f7 Anthony Liguori
        break;
208 1fd825f7 Anthony Liguori
    }
209 1fd825f7 Anthony Liguori
    case QTYPE_QFLOAT: {
210 1fd825f7 Anthony Liguori
        QFloat *val = qobject_to_qfloat(obj);
211 1fd825f7 Anthony Liguori
        char buffer[1024];
212 1fd825f7 Anthony Liguori
        int len;
213 1fd825f7 Anthony Liguori
214 1fd825f7 Anthony Liguori
        len = snprintf(buffer, sizeof(buffer), "%f", qfloat_get_double(val));
215 1fd825f7 Anthony Liguori
        while (len > 0 && buffer[len - 1] == '0') {
216 1fd825f7 Anthony Liguori
            len--;
217 1fd825f7 Anthony Liguori
        }
218 1fd825f7 Anthony Liguori
219 1fd825f7 Anthony Liguori
        if (len && buffer[len - 1] == '.') {
220 1fd825f7 Anthony Liguori
            buffer[len - 1] = 0;
221 1fd825f7 Anthony Liguori
        } else {
222 1fd825f7 Anthony Liguori
            buffer[len] = 0;
223 1fd825f7 Anthony Liguori
        }
224 1fd825f7 Anthony Liguori
        
225 1fd825f7 Anthony Liguori
        qstring_append(str, buffer);
226 1fd825f7 Anthony Liguori
        break;
227 1fd825f7 Anthony Liguori
    }
228 1fd825f7 Anthony Liguori
    case QTYPE_QBOOL: {
229 1fd825f7 Anthony Liguori
        QBool *val = qobject_to_qbool(obj);
230 1fd825f7 Anthony Liguori
231 1fd825f7 Anthony Liguori
        if (qbool_get_int(val)) {
232 1fd825f7 Anthony Liguori
            qstring_append(str, "true");
233 1fd825f7 Anthony Liguori
        } else {
234 1fd825f7 Anthony Liguori
            qstring_append(str, "false");
235 1fd825f7 Anthony Liguori
        }
236 1fd825f7 Anthony Liguori
        break;
237 1fd825f7 Anthony Liguori
    }
238 9f9daf9a Luiz Capitulino
    case QTYPE_QERROR:
239 9f9daf9a Luiz Capitulino
        /* XXX: should QError be emitted? */
240 1fd825f7 Anthony Liguori
    case QTYPE_NONE:
241 1fd825f7 Anthony Liguori
        break;
242 1fd825f7 Anthony Liguori
    }
243 1fd825f7 Anthony Liguori
}
244 1fd825f7 Anthony Liguori
245 1fd825f7 Anthony Liguori
QString *qobject_to_json(const QObject *obj)
246 1fd825f7 Anthony Liguori
{
247 1fd825f7 Anthony Liguori
    QString *str = qstring_new();
248 1fd825f7 Anthony Liguori
249 1fd825f7 Anthony Liguori
    to_json(obj, str);
250 1fd825f7 Anthony Liguori
251 1fd825f7 Anthony Liguori
    return str;
252 1fd825f7 Anthony Liguori
}