source: trunk/debian/packages/libubox/trunk/blobmsg_json.c @ 857

Last change on this file since 857 was 857, checked in by amain, 4 years ago

libubox: initial import / part 4

File size: 7.6 KB
Line 
1/*
2 * Copyright (C) 2010-2012 Felix Fietkau <nbd@openwrt.org>
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16#include <inttypes.h>
17#include "blobmsg.h"
18#include "blobmsg_json.h"
19
20#ifdef JSONC
21        #include <json.h>
22#else
23        #include <json/json.h>
24#endif
25
26bool blobmsg_add_object(struct blob_buf *b, json_object *obj)
27{
28        json_object_object_foreach(obj, key, val) {
29                if (!blobmsg_add_json_element(b, key, val))
30                        return false;
31        }
32        return true;
33}
34
35static bool blobmsg_add_array(struct blob_buf *b, struct array_list *a)
36{
37        int i, len;
38
39        for (i = 0, len = array_list_length(a); i < len; i++) {
40                if (!blobmsg_add_json_element(b, NULL, array_list_get_idx(a, i)))
41                        return false;
42        }
43
44        return true;
45}
46
47bool blobmsg_add_json_element(struct blob_buf *b, const char *name, json_object *obj)
48{
49        bool ret = true;
50        void *c;
51
52        switch (json_object_get_type(obj)) {
53        case json_type_object:
54                c = blobmsg_open_table(b, name);
55                ret = blobmsg_add_object(b, obj);
56                blobmsg_close_table(b, c);
57                break;
58        case json_type_array:
59                c = blobmsg_open_array(b, name);
60                ret = blobmsg_add_array(b, json_object_get_array(obj));
61                blobmsg_close_array(b, c);
62                break;
63        case json_type_string:
64                blobmsg_add_string(b, name, json_object_get_string(obj));
65                break;
66        case json_type_boolean:
67                blobmsg_add_u8(b, name, json_object_get_boolean(obj));
68                break;
69        case json_type_int:
70                blobmsg_add_u32(b, name, json_object_get_int(obj));
71                break;
72        case json_type_null:
73                blobmsg_add_field(b, BLOBMSG_TYPE_UNSPEC, name, NULL, 0);
74                break;
75        default:
76                return false;
77        }
78        return ret;
79}
80
81static bool __blobmsg_add_json(struct blob_buf *b, json_object *obj)
82{
83        bool ret = false;
84
85        if (!obj)
86                return false;
87
88        if (json_object_get_type(obj) != json_type_object)
89                goto out;
90
91        ret = blobmsg_add_object(b, obj);
92
93out:
94        json_object_put(obj);
95        return ret;
96}
97
98bool blobmsg_add_json_from_file(struct blob_buf *b, const char *file)
99{
100        return __blobmsg_add_json(b, json_object_from_file(file));
101}
102
103bool blobmsg_add_json_from_string(struct blob_buf *b, const char *str)
104{
105        return __blobmsg_add_json(b, json_tokener_parse(str));
106}
107
108
109struct strbuf {
110        int len;
111        int pos;
112        char *buf;
113
114        blobmsg_json_format_t custom_format;
115        void *priv;
116        bool indent;
117        int indent_level;
118};
119
120static bool blobmsg_puts(struct strbuf *s, const char *c, int len)
121{
122        size_t new_len;
123        char *new_buf;
124
125        if (len <= 0)
126                return true;
127
128        if (s->pos + len >= s->len) {
129                new_len = s->len + 16 + len;
130                new_buf = realloc(s->buf, new_len);
131                if (!new_buf)
132                        return false;
133
134                s->len = new_len;
135                s->buf = new_buf;
136        }
137
138        memcpy(s->buf + s->pos, c, len);
139        s->pos += len;
140        return true;
141}
142
143static void add_separator(struct strbuf *s)
144{
145        const char *indent_chars = "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
146        int len;
147
148        if (!s->indent)
149                return;
150
151        len = s->indent_level + 1;
152        if (len > strlen(indent_chars))
153                len = strlen(indent_chars);
154
155        blobmsg_puts(s, indent_chars, len);
156}
157
158
159static void blobmsg_format_string(struct strbuf *s, const char *str)
160{
161        const unsigned char *p, *last, *end;
162        char buf[8] = "\\u00";
163
164        end = (unsigned char *) str + strlen(str);
165        blobmsg_puts(s, "\"", 1);
166        for (p = (unsigned char *) str, last = p; *p; p++) {
167                char escape = '\0';
168                int len;
169
170                switch(*p) {
171                case '\b':
172                        escape = 'b';
173                        break;
174                case '\n':
175                        escape = 'n';
176                        break;
177                case '\t':
178                        escape = 't';
179                        break;
180                case '\r':
181                        escape = 'r';
182                        break;
183                case '"':
184                case '\\':
185                case '/':
186                        escape = *p;
187                        break;
188                default:
189                        if (*p < ' ')
190                                escape = 'u';
191                        break;
192                }
193
194                if (!escape)
195                        continue;
196
197                if (p > last)
198                        blobmsg_puts(s, (char *) last, p - last);
199                last = p + 1;
200                buf[1] = escape;
201
202                if (escape == 'u') {
203                        sprintf(buf + 4, "%02x", (unsigned char) *p);
204                        len = 6;
205                } else {
206                        len = 2;
207                }
208                blobmsg_puts(s, buf, len);
209        }
210
211        blobmsg_puts(s, (char *) last, end - last);
212        blobmsg_puts(s, "\"", 1);
213}
214
215static void blobmsg_format_json_list(struct strbuf *s, struct blob_attr *attr, int len, bool array);
216
217static void blobmsg_format_element(struct strbuf *s, struct blob_attr *attr, bool without_name, bool head)
218{
219        const char *data_str;
220        char buf[32];
221        void *data;
222        int len;
223
224        if (!blobmsg_check_attr(attr, false))
225                return;
226
227        if (!without_name && blobmsg_name(attr)[0]) {
228                blobmsg_format_string(s, blobmsg_name(attr));
229                blobmsg_puts(s, ": ", s->indent ? 2 : 1);
230        }
231
232        data = blobmsg_data(attr);
233        len = blobmsg_data_len(attr);
234
235        if (!head && s->custom_format) {
236                data_str = s->custom_format(s->priv, attr);
237                if (data_str)
238                        goto out;
239        }
240
241        data_str = buf;
242        switch(blob_id(attr)) {
243        case BLOBMSG_TYPE_UNSPEC:
244                sprintf(buf, "null");
245                break;
246        case BLOBMSG_TYPE_BOOL:
247                sprintf(buf, "%s", *(uint8_t *)data ? "true" : "false");
248                break;
249        case BLOBMSG_TYPE_INT16:
250                sprintf(buf, "%d", be16_to_cpu(*(uint16_t *)data));
251                break;
252        case BLOBMSG_TYPE_INT32:
253                sprintf(buf, "%d", (int32_t) be32_to_cpu(*(uint32_t *)data));
254                break;
255        case BLOBMSG_TYPE_INT64:
256                sprintf(buf, "%" PRId64, (int64_t) be64_to_cpu(*(uint64_t *)data));
257                break;
258        case BLOBMSG_TYPE_STRING:
259                blobmsg_format_string(s, data);
260                return;
261        case BLOBMSG_TYPE_ARRAY:
262                blobmsg_format_json_list(s, data, len, true);
263                return;
264        case BLOBMSG_TYPE_TABLE:
265                blobmsg_format_json_list(s, data, len, false);
266                return;
267        }
268
269out:
270        blobmsg_puts(s, data_str, strlen(data_str));
271}
272
273static void blobmsg_format_json_list(struct strbuf *s, struct blob_attr *attr, int len, bool array)
274{
275        struct blob_attr *pos;
276        bool first = true;
277        int rem = len;
278
279        blobmsg_puts(s, (array ? "[" : "{" ), 1);
280        s->indent_level++;
281        add_separator(s);
282        __blob_for_each_attr(pos, attr, rem) {
283                if (!first) {
284                        blobmsg_puts(s, ",", 1);
285                        add_separator(s);
286                }
287
288                blobmsg_format_element(s, pos, array, false);
289                first = false;
290        }
291        s->indent_level--;
292        add_separator(s);
293        blobmsg_puts(s, (array ? "]" : "}"), 1);
294}
295
296static void setup_strbuf(struct strbuf *s, struct blob_attr *attr, blobmsg_json_format_t cb, void *priv, int indent)
297{
298        s->len = blob_len(attr);
299        s->buf = malloc(s->len);
300        s->pos = 0;
301        s->custom_format = cb;
302        s->priv = priv;
303        s->indent = false;
304
305        if (indent >= 0) {
306                s->indent = true;
307                s->indent_level = indent;
308        }
309}
310
311char *blobmsg_format_json_with_cb(struct blob_attr *attr, bool list, blobmsg_json_format_t cb, void *priv, int indent)
312{
313        struct strbuf s;
314        bool array;
315        char *ret;
316
317        setup_strbuf(&s, attr, cb, priv, indent);
318        if (!s.buf)
319                return NULL;
320
321        array = blob_is_extended(attr) &&
322                blobmsg_type(attr) == BLOBMSG_TYPE_ARRAY;
323
324        if (list)
325                blobmsg_format_json_list(&s, blobmsg_data(attr), blobmsg_data_len(attr), array);
326        else
327                blobmsg_format_element(&s, attr, false, false);
328
329        if (!s.len) {
330                free(s.buf);
331                return NULL;
332        }
333
334        ret = realloc(s.buf, s.pos + 1);
335        if (!ret) {
336                free(s.buf);
337                return NULL;
338        }
339
340        ret[s.pos] = 0;
341
342        return ret;
343}
344
345char *blobmsg_format_json_value_with_cb(struct blob_attr *attr, blobmsg_json_format_t cb, void *priv, int indent)
346{
347        struct strbuf s;
348        char *ret;
349
350        setup_strbuf(&s, attr, cb, priv, indent);
351        if (!s.buf)
352                return NULL;
353
354        blobmsg_format_element(&s, attr, true, false);
355
356        if (!s.len) {
357                free(s.buf);
358                return NULL;
359        }
360
361        ret = realloc(s.buf, s.pos + 1);
362        if (!ret) {
363                free(s.buf);
364                return NULL;
365        }
366
367        ret[s.pos] = 0;
368
369        return ret;
370}
Note: See TracBrowser for help on using the repository browser.