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