• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/libubox/blobmsg_json.c

  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 #include <json.h>
 21 
 22 bool blobmsg_add_object(struct blob_buf *b, json_object *obj)
 23 {
 24         json_object_object_foreach(obj, key, val) {
 25                 if (!blobmsg_add_json_element(b, key, val))
 26                         return false;
 27         }
 28         return true;
 29 }
 30 
 31 static bool blobmsg_add_array(struct blob_buf *b, struct array_list *a)
 32 {
 33         int i, len;
 34 
 35         for (i = 0, len = array_list_length(a); i < len; i++) {
 36                 if (!blobmsg_add_json_element(b, NULL, array_list_get_idx(a, i)))
 37                         return false;
 38         }
 39 
 40         return true;
 41 }
 42 
 43 bool blobmsg_add_json_element(struct blob_buf *b, const char *name, json_object *obj)
 44 {
 45         bool ret = true;
 46         void *c;
 47 
 48         switch (json_object_get_type(obj)) {
 49         case json_type_object:
 50                 c = blobmsg_open_table(b, name);
 51                 ret = blobmsg_add_object(b, obj);
 52                 blobmsg_close_table(b, c);
 53                 break;
 54         case json_type_array:
 55                 c = blobmsg_open_array(b, name);
 56                 ret = blobmsg_add_array(b, json_object_get_array(obj));
 57                 blobmsg_close_array(b, c);
 58                 break;
 59         case json_type_string:
 60                 blobmsg_add_string(b, name, json_object_get_string(obj));
 61                 break;
 62         case json_type_boolean:
 63                 blobmsg_add_u8(b, name, json_object_get_boolean(obj));
 64                 break;
 65         case json_type_int: {
 66                 int64_t i64 = json_object_get_int64(obj);
 67                 if (i64 >= INT32_MIN && i64 <= INT32_MAX) {
 68                         blobmsg_add_u32(b, name, (uint32_t)i64);
 69                 } else {
 70                         blobmsg_add_u64(b, name, (uint64_t)i64);
 71                 }
 72                 break;
 73         }
 74         case json_type_double:
 75                 blobmsg_add_double(b, name, json_object_get_double(obj));
 76                 break;
 77         case json_type_null:
 78                 blobmsg_add_field(b, BLOBMSG_TYPE_UNSPEC, name, NULL, 0);
 79                 break;
 80         default:
 81                 return false;
 82         }
 83         return ret;
 84 }
 85 
 86 static bool __blobmsg_add_json(struct blob_buf *b, json_object *obj)
 87 {
 88         bool ret = false;
 89 
 90         if (!obj)
 91                 return false;
 92 
 93         if (json_object_get_type(obj) != json_type_object)
 94                 goto out;
 95 
 96         ret = blobmsg_add_object(b, obj);
 97 
 98 out:
 99         json_object_put(obj);
100         return ret;
101 }
102 
103 bool blobmsg_add_json_from_file(struct blob_buf *b, const char *file)
104 {
105         return __blobmsg_add_json(b, json_object_from_file(file));
106 }
107 
108 bool blobmsg_add_json_from_string(struct blob_buf *b, const char *str)
109 {
110         return __blobmsg_add_json(b, json_tokener_parse(str));
111 }
112 
113 
114 struct strbuf {
115         int len;
116         int pos;
117         char *buf;
118 
119         blobmsg_json_format_t custom_format;
120         void *priv;
121         bool indent;
122         int indent_level;
123 };
124 
125 static bool blobmsg_puts(struct strbuf *s, const char *c, int len)
126 {
127         size_t new_len;
128         char *new_buf;
129 
130         if (len <= 0)
131                 return true;
132 
133         if (s->pos + len >= s->len) {
134                 new_len = s->len + 16 + len;
135                 new_buf = realloc(s->buf, new_len);
136                 if (!new_buf)
137                         return false;
138 
139                 s->len = new_len;
140                 s->buf = new_buf;
141         }
142 
143         memcpy(s->buf + s->pos, c, len);
144         s->pos += len;
145         return true;
146 }
147 
148 static void add_separator(struct strbuf *s)
149 {
150         const char indent_chars[] = "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
151         size_t len;
152 
153         if (!s->indent)
154                 return;
155 
156         len = s->indent_level + 1;
157         if (len > sizeof(indent_chars) - 1)
158                 len = sizeof(indent_chars) - 1;
159 
160         blobmsg_puts(s, indent_chars, len);
161 }
162 
163 
164 static void blobmsg_format_string(struct strbuf *s, const char *str)
165 {
166         const unsigned char *p, *last, *end;
167         char buf[8] = "\\u00";
168 
169         end = (unsigned char *) str + strlen(str);
170         blobmsg_puts(s, "\"", 1);
171         for (p = (unsigned char *) str, last = p; *p; p++) {
172                 char escape = '\0';
173                 int len;
174 
175                 switch(*p) {
176                 case '\b':
177                         escape = 'b';
178                         break;
179                 case '\n':
180                         escape = 'n';
181                         break;
182                 case '\t':
183                         escape = 't';
184                         break;
185                 case '\r':
186                         escape = 'r';
187                         break;
188                 case '"':
189                 case '\\':
190                         escape = *p;
191                         break;
192                 default:
193                         if (*p < ' ')
194                                 escape = 'u';
195                         break;
196                 }
197 
198                 if (!escape)
199                         continue;
200 
201                 if (p > last)
202                         blobmsg_puts(s, (char *) last, p - last);
203                 last = p + 1;
204                 buf[1] = escape;
205 
206                 if (escape == 'u') {
207                         snprintf(buf + 4, sizeof(buf) - 4, "%02x", (unsigned char) *p);
208                         len = 6;
209                 } else {
210                         len = 2;
211                 }
212                 blobmsg_puts(s, buf, len);
213         }
214 
215         blobmsg_puts(s, (char *) last, end - last);
216         blobmsg_puts(s, "\"", 1);
217 }
218 
219 static void blobmsg_format_json_list(struct strbuf *s, struct blob_attr *attr, int len, bool array);
220 
221 static void blobmsg_format_element(struct strbuf *s, struct blob_attr *attr, bool without_name, bool head)
222 {
223         const char *data_str;
224         char buf[317];
225         void *data;
226         int len;
227 
228         if (!blobmsg_check_attr(attr, false))
229                 return;
230 
231         if (!without_name && blobmsg_name(attr)[0]) {
232                 blobmsg_format_string(s, blobmsg_name(attr));
233                 blobmsg_puts(s, ": ", s->indent ? 2 : 1);
234         }
235 
236         data = blobmsg_data(attr);
237         len = blobmsg_data_len(attr);
238 
239         if (!head && s->custom_format) {
240                 data_str = s->custom_format(s->priv, attr);
241                 if (data_str)
242                         goto out;
243         }
244 
245         data_str = buf;
246         switch(blob_id(attr)) {
247         case BLOBMSG_TYPE_UNSPEC:
248                 snprintf(buf, sizeof(buf), "null");
249                 break;
250         case BLOBMSG_TYPE_BOOL:
251                 snprintf(buf, sizeof(buf), "%s", *(uint8_t *)data ? "true" : "false");
252                 break;
253         case BLOBMSG_TYPE_INT16:
254                 snprintf(buf, sizeof(buf), "%" PRId16, (int16_t) be16_to_cpu(*(uint16_t *)data));
255                 break;
256         case BLOBMSG_TYPE_INT32:
257                 snprintf(buf, sizeof(buf), "%" PRId32, (int32_t) be32_to_cpu(*(uint32_t *)data));
258                 break;
259         case BLOBMSG_TYPE_INT64:
260                 snprintf(buf, sizeof(buf), "%" PRId64, (int64_t) be64_to_cpu(*(uint64_t *)data));
261                 break;
262         case BLOBMSG_TYPE_DOUBLE:
263                 snprintf(buf, sizeof(buf), "%lf", blobmsg_get_double(attr));
264                 break;
265         case BLOBMSG_TYPE_STRING:
266                 blobmsg_format_string(s, data);
267                 return;
268         case BLOBMSG_TYPE_ARRAY:
269                 blobmsg_format_json_list(s, data, len, true);
270                 return;
271         case BLOBMSG_TYPE_TABLE:
272                 blobmsg_format_json_list(s, data, len, false);
273                 return;
274         }
275 
276 out:
277         blobmsg_puts(s, data_str, strlen(data_str));
278 }
279 
280 static void blobmsg_format_json_list(struct strbuf *s, struct blob_attr *attr, int len, bool array)
281 {
282         struct blob_attr *pos;
283         bool first = true;
284         size_t rem = len;
285 
286         blobmsg_puts(s, (array ? "[" : "{" ), 1);
287         s->indent_level++;
288         add_separator(s);
289         __blob_for_each_attr(pos, attr, rem) {
290                 if (!first) {
291                         blobmsg_puts(s, ",", 1);
292                         add_separator(s);
293                 }
294 
295                 blobmsg_format_element(s, pos, array, false);
296                 first = false;
297         }
298         s->indent_level--;
299         add_separator(s);
300         blobmsg_puts(s, (array ? "]" : "}"), 1);
301 }
302 
303 static void setup_strbuf(struct strbuf *s, struct blob_attr *attr, blobmsg_json_format_t cb, void *priv, int indent)
304 {
305         s->len = blob_len(attr);
306         s->buf = malloc(s->len);
307         s->pos = 0;
308         s->custom_format = cb;
309         s->priv = priv;
310         s->indent = false;
311 
312         if (indent >= 0) {
313                 s->indent = true;
314                 s->indent_level = indent;
315         }
316 }
317 
318 char *blobmsg_format_json_with_cb(struct blob_attr *attr, bool list, blobmsg_json_format_t cb, void *priv, int indent)
319 {
320         struct strbuf s = {0};
321         bool array;
322         char *ret;
323 
324         setup_strbuf(&s, attr, cb, priv, indent);
325         if (!s.buf)
326                 return NULL;
327 
328         array = blob_is_extended(attr) &&
329                 blobmsg_type(attr) == BLOBMSG_TYPE_ARRAY;
330 
331         if (list)
332                 blobmsg_format_json_list(&s, blobmsg_data(attr), blobmsg_data_len(attr), array);
333         else
334                 blobmsg_format_element(&s, attr, false, false);
335 
336         if (!s.len) {
337                 free(s.buf);
338                 return NULL;
339         }
340 
341         ret = realloc(s.buf, s.pos + 1);
342         if (!ret) {
343                 free(s.buf);
344                 return NULL;
345         }
346 
347         ret[s.pos] = 0;
348 
349         return ret;
350 }
351 
352 char *blobmsg_format_json_value_with_cb(struct blob_attr *attr, blobmsg_json_format_t cb, void *priv, int indent)
353 {
354         struct strbuf s = {0};
355         char *ret;
356 
357         setup_strbuf(&s, attr, cb, priv, indent);
358         if (!s.buf)
359                 return NULL;
360 
361         blobmsg_format_element(&s, attr, true, false);
362 
363         if (!s.len) {
364                 free(s.buf);
365                 return NULL;
366         }
367 
368         ret = realloc(s.buf, s.pos + 1);
369         if (!ret) {
370                 free(s.buf);
371                 return NULL;
372         }
373 
374         ret[s.pos] = 0;
375 
376         return ret;
377 }
378 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt