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