yuezonghe | 824eb0c | 2024-06-27 02:32:26 -0700 | [diff] [blame] | 1 | #include <string.h> |
| 2 | #include <stdio.h> |
| 3 | #include <math.h> |
| 4 | #include <stdlib.h> |
| 5 | #include <float.h> |
| 6 | #include <limits.h> |
| 7 | #include <ctype.h> |
| 8 | #include "cjson.h" |
| 9 | |
| 10 | |
| 11 | static const char *parse_value(cJSON *item, const char *value); |
| 12 | static char *print_value(cJSON *item, int depth, int fmt); |
| 13 | static const char *parse_array(cJSON *item, const char *value); |
| 14 | static char *print_array(cJSON *item, int depth, int fmt); |
| 15 | static const char *parse_object(cJSON *item, const char *value); |
| 16 | static char *print_object(cJSON *item, int depth, int fmt); |
| 17 | |
| 18 | static const char *ep; |
| 19 | |
| 20 | static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; |
| 21 | |
| 22 | |
| 23 | const char *cJSON_GetErrorPtr(void) |
| 24 | { |
| 25 | return ep; |
| 26 | } |
| 27 | |
| 28 | static int cJSON_strcasecmp(const char *s1, const char *s2) |
| 29 | { |
| 30 | if (!s1) return (s1 == s2) ? 0 : 1; |
| 31 | if (!s2) return 1; |
| 32 | for (; tolower(*s1) == tolower(*s2); ++s1, ++s2) if (*s1 == 0) return 0; |
| 33 | return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); |
| 34 | } |
| 35 | |
| 36 | static void *(*cJSON_malloc)(size_t sz) = malloc; |
| 37 | static void (*cJSON_free)(void *ptr) = free; |
| 38 | |
| 39 | static const char *skip(const char *in) |
| 40 | { |
| 41 | while (in && *in && (unsigned char)*in <= 32) in++; |
| 42 | return in; |
| 43 | } |
| 44 | |
| 45 | static char* cJSON_strdup(const char* str) |
| 46 | { |
| 47 | size_t len; |
| 48 | char* str_cpy; |
| 49 | |
| 50 | len = strlen(str) + 1; |
| 51 | if (!(str_cpy = (char*)cJSON_malloc(len))) return 0; |
| 52 | memcpy(str_cpy, str, len); |
| 53 | return str_cpy; |
| 54 | } |
| 55 | |
| 56 | void cJSON_InitHooks(cJSON_Hooks* hooks) |
| 57 | { |
| 58 | if (!hooks) { /*hooks reset*/ |
| 59 | cJSON_malloc = malloc; |
| 60 | cJSON_free = free; |
| 61 | return; |
| 62 | } |
| 63 | |
| 64 | cJSON_malloc = (hooks->malloc_fn) ? hooks->malloc_fn : malloc; |
| 65 | cJSON_free = (hooks->free_fn) ? hooks->free_fn : free; |
| 66 | } |
| 67 | |
| 68 | static cJSON *cJSON_New_Item(void) |
| 69 | { |
| 70 | cJSON* inode = (cJSON*)cJSON_malloc(sizeof(cJSON)); |
| 71 | if (inode) memset(inode, 0, sizeof(cJSON)); |
| 72 | return inode; |
| 73 | } |
| 74 | |
| 75 | void cJSON_Delete(cJSON *c) |
| 76 | { |
| 77 | cJSON *next_node; |
| 78 | while (c) { |
| 79 | next_node = c->next; |
| 80 | if (!(c->type & cJSON_IsReference) && c->child) cJSON_Delete(c->child); |
| 81 | if (!(c->type & cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring); |
| 82 | if (c->string) cJSON_free(c->string); |
| 83 | cJSON_free(c); |
| 84 | c = next_node; |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | static const char *parse_number(cJSON *item, const char *num) |
| 89 | { |
| 90 | int subscale = 0, signsubscale = 1; |
| 91 | |
| 92 | double inum = 0, sign = 1, scale = 0; |
| 93 | |
| 94 | if (*num == '-') sign = -1, num++; |
| 95 | if (*num == '0') num++; |
| 96 | if (*num >= '1' && *num <= '9') do inum = (inum * 10.0) + (*num++ -'0'); |
| 97 | while (*num >= '0' && *num <= '9'); |
| 98 | if (*num == '.' && num[1] >= '0' && num[1] <= '9') { |
| 99 | num++; |
| 100 | do inum = (inum * 10.0) + (*num++ -'0'), scale--; |
| 101 | while (*num >= '0' && *num <= '9'); |
| 102 | } |
| 103 | if (*num == 'e' || *num == 'E') { |
| 104 | num++; |
| 105 | if (*num == '+') num++; |
| 106 | else if (*num == '-') signsubscale = -1, num++; |
| 107 | while (*num >= '0' && *num <= '9') subscale = (subscale * 10) + (*num++ - '0'); |
| 108 | } |
| 109 | |
| 110 | inum = sign * inum * pow(10.0, (scale + subscale * signsubscale)); |
| 111 | |
| 112 | item->valuedouble = inum; |
| 113 | item->valueint = (int)inum; |
| 114 | item->type = cJSON_Number; |
| 115 | return num; |
| 116 | } |
| 117 | |
| 118 | static char *print_number(cJSON *item) |
| 119 | { |
| 120 | double d = item->valuedouble; |
| 121 | |
| 122 | char *str; |
| 123 | |
| 124 | if (fabs(((double)item->valueint) - d) <= DBL_EPSILON && d <= INT_MAX && d >= INT_MIN) { |
| 125 | str = (char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */ |
| 126 | if (str) sprintf(str, "%d", item->valueint); |
| 127 | } else { |
| 128 | str = (char*)cJSON_malloc(64); |
| 129 | if (str) { |
| 130 | if (fabs(floor(d) - d) <= DBL_EPSILON && fabs(d) < 1.0e60)sprintf(str, "%.0f", d); |
| 131 | else if (fabs(d) < 1.0e-6 || fabs(d) > 1.0e9) sprintf(str, "%e", d); |
| 132 | else sprintf(str, "%f", d); |
| 133 | } |
| 134 | } |
| 135 | return str; |
| 136 | } |
| 137 | |
| 138 | static unsigned parse_hex4(const char *str) |
| 139 | { |
| 140 | unsigned hex = 0; |
| 141 | if (*str >= '0' && *str <= '9') |
| 142 | hex += (*str) - '0'; |
| 143 | else if (*str >= 'A' && *str <= 'F') |
| 144 | hex += 10 + (*str) - 'A'; |
| 145 | else if (*str >= 'a' && *str <= 'f') |
| 146 | hex += 10 + (*str) - 'a'; |
| 147 | else |
| 148 | return 0; |
| 149 | hex = hex << 4; |
| 150 | str++; |
| 151 | if (*str >= '0' && *str <= '9') |
| 152 | hex += (*str) - '0'; |
| 153 | else if (*str >= 'A' && *str <= 'F') |
| 154 | hex += 10 + (*str) - 'A'; |
| 155 | else if (*str >= 'a' && *str <= 'f') |
| 156 | hex += 10 + (*str) - 'a'; |
| 157 | else |
| 158 | return 0; |
| 159 | hex = hex << 4; |
| 160 | str++; |
| 161 | if (*str >= '0' && *str <= '9') |
| 162 | hex += (*str) - '0'; |
| 163 | else if (*str >= 'A' && *str <= 'F') |
| 164 | hex += 10 + (*str) - 'A'; |
| 165 | else if (*str >= 'a' && *str <= 'f') |
| 166 | hex += 10 + (*str) - 'a'; |
| 167 | else |
| 168 | return 0; |
| 169 | hex = hex << 4; |
| 170 | str++; |
| 171 | if (*str >= '0' && *str <= '9') |
| 172 | hex += (*str) - '0'; |
| 173 | else if (*str >= 'A' && *str <= 'F') |
| 174 | hex += 10 + (*str) - 'A'; |
| 175 | else if (*str >= 'a' && *str <= 'f') |
| 176 | hex += 10 + (*str) - 'a'; |
| 177 | else |
| 178 | return 0; |
| 179 | return hex; |
| 180 | } |
| 181 | |
| 182 | static const char *parse_string(cJSON *item, const char *str) |
| 183 | { |
| 184 | const char *pstr = str + 1; |
| 185 | char *pstr2; |
| 186 | char *out; |
| 187 | int len = 0; |
| 188 | unsigned uc, uc2; |
| 189 | if (*str != '\"') { |
| 190 | ep = str; /* not a string! */ |
| 191 | return 0; |
| 192 | } |
| 193 | |
| 194 | while (*pstr != '\"' && *pstr && ++len) if (*pstr++ == '\\') pstr++; /* Skip escaped quotes. */ |
| 195 | |
| 196 | out = (char*)cJSON_malloc(len + 1); /* This is how long we need for the string, roughly. */ |
| 197 | if (!out) return 0; |
| 198 | |
| 199 | pstr = str + 1; |
| 200 | pstr2 = out; |
| 201 | while (*pstr != '\"' && *pstr) { |
| 202 | if (*pstr != '\\') *pstr2++ = *pstr++; |
| 203 | else { |
| 204 | pstr++; |
| 205 | switch (*pstr) { |
| 206 | case 'b': |
| 207 | *pstr2++ = '\b'; |
| 208 | break; |
| 209 | case 'f': |
| 210 | *pstr2++ = '\f'; |
| 211 | break; |
| 212 | case 'n': |
| 213 | *pstr2++ = '\n'; |
| 214 | break; |
| 215 | case 'r': |
| 216 | *pstr2++ = '\r'; |
| 217 | break; |
| 218 | case 't': |
| 219 | *pstr2++ = '\t'; |
| 220 | break; |
| 221 | case 'u': |
| 222 | uc = parse_hex4(pstr + 1); |
| 223 | pstr += 4; |
| 224 | |
| 225 | if ((uc >= 0xDC00 && uc <= 0xDFFF) || uc == 0) |
| 226 | break; |
| 227 | |
| 228 | if (uc >= 0xD800 && uc <= 0xDBFF) { |
| 229 | if (pstr[1] != '\\' || pstr[2] != 'u') |
| 230 | break; |
| 231 | uc2 = parse_hex4(pstr + 3); |
| 232 | pstr += 6; |
| 233 | if (uc2 < 0xDC00 || uc2 > 0xDFFF) |
| 234 | break; |
| 235 | uc = 0x10000 + (((uc & 0x3FF) << 10) | (uc2 & 0x3FF)); |
| 236 | } |
| 237 | |
| 238 | len = 4; |
| 239 | if (uc < 0x80) len = 1; |
| 240 | else if (uc < 0x800) len = 2; |
| 241 | else if (uc < 0x10000) len = 3; |
| 242 | pstr2 += len; |
| 243 | |
| 244 | switch (len) { |
| 245 | case 4: |
| 246 | *--pstr2 = ((uc | 0x80) & 0xBF); |
| 247 | uc >>= 6; |
| 248 | case 3: |
| 249 | *--pstr2 = ((uc | 0x80) & 0xBF); |
| 250 | uc >>= 6; |
| 251 | case 2: |
| 252 | *--pstr2 = ((uc | 0x80) & 0xBF); |
| 253 | uc >>= 6; |
| 254 | case 1: |
| 255 | *--pstr2 = (uc | firstByteMark[len]); |
| 256 | } |
| 257 | pstr2 += len; |
| 258 | break; |
| 259 | default: |
| 260 | *pstr2++ = *pstr; |
| 261 | break; |
| 262 | } |
| 263 | pstr++; |
| 264 | } |
| 265 | } |
| 266 | *pstr2 = 0; |
| 267 | if (*pstr == '\"') pstr++; |
| 268 | item->valuestring = out; |
| 269 | item->type = cJSON_String; |
| 270 | return pstr; |
| 271 | } |
| 272 | |
| 273 | static char *print_string_ptr(const char *str) |
| 274 | { |
| 275 | const char *pstr; |
| 276 | char *pstr2, *out; |
| 277 | int len = 0; |
| 278 | unsigned char token; |
| 279 | |
| 280 | if (!str) return cJSON_strdup(""); |
| 281 | pstr = str; |
| 282 | while ((token = *pstr) && ++len) { |
| 283 | if (strchr("\"\\\b\f\n\r\t", token)) len++; |
| 284 | else if (token < 32) len += 5; |
| 285 | pstr++; |
| 286 | } |
| 287 | |
| 288 | out = (char*)cJSON_malloc(len + 3); |
| 289 | if (!out) return 0; |
| 290 | |
| 291 | pstr2 = out; |
| 292 | pstr = str; |
| 293 | *pstr2++ = '\"'; |
| 294 | while (*pstr) { |
| 295 | if ((unsigned char)*pstr > 31 && *pstr != '\"' && *pstr != '\\') *pstr2++ = *pstr++; |
| 296 | else { |
| 297 | *pstr2++ = '\\'; |
| 298 | switch (token = *pstr++) { |
| 299 | case '\\': |
| 300 | *pstr2++ = '\\'; |
| 301 | break; |
| 302 | case '\"': |
| 303 | *pstr2++ = '\"'; |
| 304 | break; |
| 305 | case '\b': |
| 306 | *pstr2++ = 'b'; |
| 307 | break; |
| 308 | case '\f': |
| 309 | *pstr2++ = 'f'; |
| 310 | break; |
| 311 | case '\n': |
| 312 | *pstr2++ = 'n'; |
| 313 | break; |
| 314 | case '\r': |
| 315 | *pstr2++ = 'r'; |
| 316 | break; |
| 317 | case '\t': |
| 318 | *pstr2++ = 't'; |
| 319 | break; |
| 320 | default: |
| 321 | sprintf(pstr2, "u%04x", token); |
| 322 | pstr2 += 5; |
| 323 | break; |
| 324 | } |
| 325 | } |
| 326 | } |
| 327 | *pstr2++ = '\"'; |
| 328 | *pstr2++ = 0; |
| 329 | return out; |
| 330 | } |
| 331 | |
| 332 | static char *print_string(cJSON *item) |
| 333 | { |
| 334 | return print_string_ptr(item->valuestring); |
| 335 | } |
| 336 | |
| 337 | cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated) |
| 338 | { |
| 339 | const char *str_end = 0; |
| 340 | cJSON *c = cJSON_New_Item(); |
| 341 | ep = 0; |
| 342 | if (!c) |
| 343 | return 0; |
| 344 | |
| 345 | str_end = parse_value(c, skip(value)); |
| 346 | if (!str_end) { |
| 347 | cJSON_Delete(c); |
| 348 | return 0; |
| 349 | } |
| 350 | |
| 351 | if (require_null_terminated) { |
| 352 | str_end = skip(str_end); |
| 353 | if (*str_end) { |
| 354 | cJSON_Delete(c); |
| 355 | ep = str_end; |
| 356 | return 0; |
| 357 | } |
| 358 | } |
| 359 | if (return_parse_end) *return_parse_end = str_end; |
| 360 | return c; |
| 361 | } |
| 362 | |
| 363 | cJSON *cJSON_Parse(const char *value) |
| 364 | { |
| 365 | return cJSON_ParseWithOpts(value, 0, 0); |
| 366 | } |
| 367 | char *cJSON_Print(cJSON *item) |
| 368 | { |
| 369 | return print_value(item, 0, 1); |
| 370 | } |
| 371 | char *cJSON_PrintUnformatted(cJSON *item) |
| 372 | { |
| 373 | return print_value(item, 0, 0); |
| 374 | } |
| 375 | |
| 376 | static const char *parse_value(cJSON *item, const char *value) |
| 377 | { |
| 378 | if (!value) |
| 379 | return 0; |
| 380 | if (!strncmp(value, "null", 4)) { |
| 381 | item->type = cJSON_NULL; |
| 382 | return value + 4; |
| 383 | } |
| 384 | if (!strncmp(value, "false", 5)) { |
| 385 | item->type = cJSON_False; |
| 386 | return value + 5; |
| 387 | } |
| 388 | if (!strncmp(value, "true", 4)) { |
| 389 | item->type = cJSON_True; |
| 390 | item->valueint = 1; |
| 391 | return value + 4; |
| 392 | } |
| 393 | if (*value == '\"') { |
| 394 | return parse_string(item, value); |
| 395 | } |
| 396 | if (*value == '-' || (*value >= '0' && *value <= '9')) { |
| 397 | return parse_number(item, value); |
| 398 | } |
| 399 | if (*value == '[') { |
| 400 | return parse_array(item, value); |
| 401 | } |
| 402 | if (*value == '{') { |
| 403 | return parse_object(item, value); |
| 404 | } |
| 405 | |
| 406 | ep = value; |
| 407 | return 0; |
| 408 | } |
| 409 | |
| 410 | static char *print_value(cJSON *item, int depth, int fmt) |
| 411 | { |
| 412 | char *item_value = 0; |
| 413 | if (!item) |
| 414 | return 0; |
| 415 | switch ((item->type) & 255) { |
| 416 | case cJSON_NULL: |
| 417 | item_value = cJSON_strdup("null"); |
| 418 | break; |
| 419 | case cJSON_False: |
| 420 | item_value = cJSON_strdup("false"); |
| 421 | break; |
| 422 | case cJSON_True: |
| 423 | item_value = cJSON_strdup("true"); |
| 424 | break; |
| 425 | case cJSON_Number: |
| 426 | item_value = print_number(item); |
| 427 | break; |
| 428 | case cJSON_String: |
| 429 | item_value = print_string(item); |
| 430 | break; |
| 431 | case cJSON_Array: |
| 432 | item_value = print_array(item, depth, fmt); |
| 433 | break; |
| 434 | case cJSON_Object: |
| 435 | item_value = print_object(item, depth, fmt); |
| 436 | break; |
| 437 | } |
| 438 | return item_value; |
| 439 | } |
| 440 | |
| 441 | |
| 442 | static const char *parse_array(cJSON *item, const char *value) |
| 443 | { |
| 444 | cJSON *child; |
| 445 | if (*value != '[') { |
| 446 | ep = value; |
| 447 | return 0; |
| 448 | } |
| 449 | |
| 450 | item->type = cJSON_Array; |
| 451 | value = skip(value + 1); |
| 452 | if (*value == ']') return value + 1; |
| 453 | |
| 454 | item->child = child = cJSON_New_Item(); |
| 455 | if (!item->child) return 0; |
| 456 | value = skip(parse_value(child, skip(value))); |
| 457 | if (!value) return 0; |
| 458 | |
| 459 | while (*value == ',') { |
| 460 | cJSON *new_item; |
| 461 | if (!(new_item = cJSON_New_Item())) |
| 462 | return 0; |
| 463 | child->next = new_item; |
| 464 | new_item->prev = child; |
| 465 | child = new_item; |
| 466 | value = skip(parse_value(child, skip(value + 1))); |
| 467 | if (!value) |
| 468 | return 0; |
| 469 | } |
| 470 | |
| 471 | if (*value == ']') |
| 472 | return value + 1; |
| 473 | ep = value; |
| 474 | return 0; |
| 475 | } |
| 476 | |
| 477 | static char *print_array(cJSON *item, int depth, int fmt) |
| 478 | { |
| 479 | char *oitem = 0, *pstr, *ret; |
| 480 | char **entries; |
| 481 | int len = 5; |
| 482 | int numentries = 0, i = 0, fail = 0; |
| 483 | cJSON *child = item->child; |
| 484 | |
| 485 | while (child) numentries++, child = child->next; |
| 486 | |
| 487 | if (!numentries) { |
| 488 | oitem = (char*)cJSON_malloc(3); |
| 489 | if (oitem) |
| 490 | strcpy(oitem, "[]"); |
| 491 | return oitem; |
| 492 | } |
| 493 | |
| 494 | entries = (char**)cJSON_malloc(numentries * sizeof(char*)); |
| 495 | if (!entries) return 0; |
| 496 | memset(entries, 0, numentries * sizeof(char*)); |
| 497 | |
| 498 | child = item->child; |
| 499 | while (child && !fail) { |
| 500 | ret = print_value(child, depth + 1, fmt); |
| 501 | entries[i++] = ret; |
| 502 | if (ret) len += strlen(ret) + 2 + (fmt ? 1 : 0); |
| 503 | else fail = 1; |
| 504 | child = child->next; |
| 505 | } |
| 506 | |
| 507 | |
| 508 | if (!fail) |
| 509 | oitem = (char*)cJSON_malloc(len); |
| 510 | |
| 511 | if (!oitem) |
| 512 | fail = 1; |
| 513 | |
| 514 | |
| 515 | if (fail) { |
| 516 | for (i = 0; i < numentries; i++) if (entries[i]) cJSON_free(entries[i]); |
| 517 | cJSON_free(entries); |
| 518 | return 0; |
| 519 | } |
| 520 | |
| 521 | |
| 522 | *oitem = '['; |
| 523 | pstr = oitem + 1; |
| 524 | *pstr = 0; |
| 525 | for (i = 0; i < numentries; i++) { |
| 526 | strcpy(pstr, entries[i]); |
| 527 | pstr += strlen(entries[i]); |
| 528 | if (i != numentries - 1) { |
| 529 | *pstr++ = ','; |
| 530 | if (fmt)*pstr++ = ' '; |
| 531 | *pstr = 0; |
| 532 | } |
| 533 | cJSON_free(entries[i]); |
| 534 | } |
| 535 | cJSON_free(entries); |
| 536 | *pstr++ = ']'; |
| 537 | *pstr++ = 0; |
| 538 | return oitem; |
| 539 | } |
| 540 | |
| 541 | static const char *parse_object(cJSON *item, const char *value) |
| 542 | { |
| 543 | cJSON *child; |
| 544 | if (*value != '{') { |
| 545 | ep = value; |
| 546 | return 0; |
| 547 | } |
| 548 | |
| 549 | item->type = cJSON_Object; |
| 550 | value = skip(value + 1); |
| 551 | if (*value == '}') return value + 1; |
| 552 | |
| 553 | item->child = child = cJSON_New_Item(); |
| 554 | if (!item->child) return 0; |
| 555 | value = skip(parse_string(child, skip(value))); |
| 556 | if (!value) return 0; |
| 557 | child->string = child->valuestring; |
| 558 | child->valuestring = 0; |
| 559 | if (*value != ':') { |
| 560 | ep = value; |
| 561 | return 0; |
| 562 | } |
| 563 | value = skip(parse_value(child, skip(value + 1))); |
| 564 | if (!value) return 0; |
| 565 | |
| 566 | while (*value == ',') { |
| 567 | cJSON *new_item; |
| 568 | if (!(new_item = cJSON_New_Item())) return 0; |
| 569 | child->next = new_item; |
| 570 | new_item->prev = child; |
| 571 | child = new_item; |
| 572 | value = skip(parse_string(child, skip(value + 1))); |
| 573 | if (!value) return 0; |
| 574 | child->string = child->valuestring; |
| 575 | child->valuestring = 0; |
| 576 | if (*value != ':') { |
| 577 | ep = value; |
| 578 | return 0; |
| 579 | } |
| 580 | value = skip(parse_value(child, skip(value + 1))); |
| 581 | if (!value) return 0; |
| 582 | } |
| 583 | |
| 584 | if (*value == '}') return value + 1; |
| 585 | ep = value; |
| 586 | return 0; |
| 587 | } |
| 588 | |
| 589 | static char *print_object(cJSON *item, int depth, int fmt) |
| 590 | { |
| 591 | char *oitem = 0, *pstr, *ret, *str; |
| 592 | char **entries = 0, **names = 0; |
| 593 | int len = 7, i = 0, j; |
| 594 | int numentries = 0, fail = 0; |
| 595 | cJSON *child = item->child; |
| 596 | |
| 597 | while (child) numentries++, child = child->next; |
| 598 | |
| 599 | if (!numentries) { |
| 600 | oitem = (char*)cJSON_malloc(fmt ? depth + 4 : 3); |
| 601 | if (!oitem) return 0; |
| 602 | pstr = oitem; |
| 603 | *pstr++ = '{'; |
| 604 | if (fmt) { |
| 605 | *pstr++ = '\n'; |
| 606 | for (i = 0; i < depth - 1; i++) *pstr++ = '\t'; |
| 607 | } |
| 608 | *pstr++ = '}'; |
| 609 | *pstr++ = 0; |
| 610 | return oitem; |
| 611 | } |
| 612 | |
| 613 | entries = (char**)cJSON_malloc(numentries * sizeof(char*)); |
| 614 | if (!entries) |
| 615 | return 0; |
| 616 | names = (char**)cJSON_malloc(numentries * sizeof(char*)); |
| 617 | if (!names) { |
| 618 | cJSON_free(entries); |
| 619 | return 0; |
| 620 | } |
| 621 | memset(entries, 0, sizeof(char*)*numentries); |
| 622 | memset(names, 0, sizeof(char*)*numentries); |
| 623 | |
| 624 | |
| 625 | child = item->child; |
| 626 | depth++; |
| 627 | if (fmt) len += depth; |
| 628 | while (child) { |
| 629 | names[i] = str = print_string_ptr(child->string); |
| 630 | entries[i++] = ret = print_value(child, depth, fmt); |
| 631 | if (str && ret) |
| 632 | len += strlen(ret) + strlen(str) + 2 + (fmt ? 2 + depth : 0); |
| 633 | else |
| 634 | fail = 1; |
| 635 | child = child->next; |
| 636 | } |
| 637 | |
| 638 | |
| 639 | if (!fail) oitem = (char*)cJSON_malloc(len); |
| 640 | if (!oitem) fail = 1; |
| 641 | |
| 642 | |
| 643 | if (fail) { |
| 644 | for (i = 0; i < numentries; i++) { |
| 645 | if (names[i]) cJSON_free(names[i]); |
| 646 | if (entries[i]) cJSON_free(entries[i]); |
| 647 | } |
| 648 | cJSON_free(names); |
| 649 | cJSON_free(entries); |
| 650 | return 0; |
| 651 | } |
| 652 | |
| 653 | |
| 654 | *oitem = '{'; |
| 655 | pstr = oitem + 1; |
| 656 | if (fmt)*pstr++ = '\n'; |
| 657 | *pstr = 0; |
| 658 | for (i = 0; i < numentries; i++) { |
| 659 | if (fmt) for (j = 0; j < depth; j++) *pstr++ = '\t'; |
| 660 | strcpy(pstr, names[i]); |
| 661 | pstr += strlen(names[i]); |
| 662 | *pstr++ = ':'; |
| 663 | if (fmt) *pstr++ = '\t'; |
| 664 | strcpy(pstr, entries[i]); |
| 665 | pstr += strlen(entries[i]); |
| 666 | if (i != numentries - 1) *pstr++ = ','; |
| 667 | if (fmt) *pstr++ = '\n'; |
| 668 | *pstr = 0; |
| 669 | cJSON_free(names[i]); |
| 670 | cJSON_free(entries[i]); |
| 671 | } |
| 672 | |
| 673 | cJSON_free(names); |
| 674 | cJSON_free(entries); |
| 675 | if (fmt) for (i = 0; i < depth - 1; i++) *pstr++ = '\t'; |
| 676 | *pstr++ = '}'; |
| 677 | *pstr++ = 0; |
| 678 | return oitem; |
| 679 | } |
| 680 | |
| 681 | int cJSON_GetArraySize(cJSON *array) |
| 682 | { |
| 683 | int i = 0; |
| 684 | cJSON *citem = array->child; |
| 685 | |
| 686 | while (citem)i++, citem = citem->next; |
| 687 | return i; |
| 688 | } |
| 689 | cJSON *cJSON_GetArrayItem(cJSON *array, int item) |
| 690 | { |
| 691 | cJSON *citem = array->child; |
| 692 | while (citem && item > 0) item--, citem = citem->next; |
| 693 | return citem; |
| 694 | } |
| 695 | cJSON *cJSON_GetObjectItem(cJSON *object, const char *string) |
| 696 | { |
| 697 | cJSON *citem = object->child; |
| 698 | while (citem && cJSON_strcasecmp(citem->string, string)) citem = citem->next; |
| 699 | return citem; |
| 700 | } |
| 701 | |
| 702 | static void suffix_object(cJSON *prev, cJSON *item) |
| 703 | { |
| 704 | prev->next = item; |
| 705 | item->prev = prev; |
| 706 | } |
| 707 | |
| 708 | static cJSON *create_reference(cJSON *item) |
| 709 | { |
| 710 | cJSON *refer = cJSON_New_Item(); |
| 711 | if (!refer) |
| 712 | return 0; |
| 713 | memcpy(refer, item, sizeof(cJSON)); |
| 714 | refer->string = 0; |
| 715 | refer->type |= cJSON_IsReference; |
| 716 | refer->next = refer->prev = 0; |
| 717 | return refer; |
| 718 | } |
| 719 | |
| 720 | void cJSON_AddItemToArray(cJSON *array, cJSON *item) |
| 721 | { |
| 722 | cJSON *citem = array->child; |
| 723 | if (!item) |
| 724 | return; |
| 725 | if (!citem) { |
| 726 | array->child = item; |
| 727 | } else { |
| 728 | while (citem && citem->next) citem = citem->next; |
| 729 | suffix_object(citem, item); |
| 730 | } |
| 731 | } |
| 732 | void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) |
| 733 | { |
| 734 | if (!item) |
| 735 | return; |
| 736 | if (item->string) cJSON_free(item->string); |
| 737 | item->string = cJSON_strdup(string); |
| 738 | cJSON_AddItemToArray(object, item); |
| 739 | } |
| 740 | void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) |
| 741 | { |
| 742 | cJSON_AddItemToArray(array, create_reference(item)); |
| 743 | } |
| 744 | void cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) |
| 745 | { |
| 746 | cJSON_AddItemToObject(object, string, create_reference(item)); |
| 747 | } |
| 748 | |
| 749 | cJSON *cJSON_DetachItemFromArray(cJSON *array, int which) |
| 750 | { |
| 751 | cJSON *citem = array->child; |
| 752 | while (citem && which > 0) citem = citem->next, which--; |
| 753 | if (!citem) |
| 754 | return 0; |
| 755 | if (citem->prev) citem->prev->next = citem->next; |
| 756 | if (citem->next) citem->next->prev = citem->prev; |
| 757 | if (citem == array->child) array->child = citem->next; |
| 758 | citem->prev = citem->next = 0; |
| 759 | return citem; |
| 760 | } |
| 761 | void cJSON_DeleteItemFromArray(cJSON *array, int which) |
| 762 | { |
| 763 | cJSON_Delete(cJSON_DetachItemFromArray(array, which)); |
| 764 | } |
| 765 | cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string) |
| 766 | { |
| 767 | int i = 0; |
| 768 | cJSON *citem = object->child; |
| 769 | while (citem && cJSON_strcasecmp(citem->string, string)) i++, citem = citem->next; |
| 770 | if (citem) |
| 771 | return cJSON_DetachItemFromArray(object, i); |
| 772 | return 0; |
| 773 | } |
| 774 | void cJSON_DeleteItemFromObject(cJSON *object, const char *string) |
| 775 | { |
| 776 | cJSON_Delete(cJSON_DetachItemFromObject(object, string)); |
| 777 | } |
| 778 | |
| 779 | void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) |
| 780 | { |
| 781 | cJSON *citem = array->child; |
| 782 | while (citem && which > 0) citem = citem->next, which--; |
| 783 | if (!citem) |
| 784 | return; |
| 785 | newitem->next = citem->next; |
| 786 | newitem->prev = citem->prev; |
| 787 | if (newitem->next) newitem->next->prev = newitem; |
| 788 | if (citem == array->child) array->child = newitem; |
| 789 | else newitem->prev->next = newitem; |
| 790 | citem->next = citem->prev = 0; |
| 791 | cJSON_Delete(citem); |
| 792 | } |
| 793 | void cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) |
| 794 | { |
| 795 | int i = 0; |
| 796 | cJSON *citem = object->child; |
| 797 | while (citem && cJSON_strcasecmp(citem->string, string))i++, citem = citem->next; |
| 798 | if (citem) { |
| 799 | newitem->string = cJSON_strdup(string); |
| 800 | cJSON_ReplaceItemInArray(object, i, newitem); |
| 801 | } |
| 802 | } |
| 803 | |
| 804 | cJSON *cJSON_CreateNull(void) |
| 805 | { |
| 806 | cJSON *item = cJSON_New_Item(); |
| 807 | if (item)item->type = cJSON_NULL; |
| 808 | return item; |
| 809 | } |
| 810 | cJSON *cJSON_CreateTrue(void) |
| 811 | { |
| 812 | cJSON *item = cJSON_New_Item(); |
| 813 | if (item)item->type = cJSON_True; |
| 814 | return item; |
| 815 | } |
| 816 | cJSON *cJSON_CreateFalse(void) |
| 817 | { |
| 818 | cJSON *item = cJSON_New_Item(); |
| 819 | if (item)item->type = cJSON_False; |
| 820 | return item; |
| 821 | } |
| 822 | cJSON *cJSON_CreateBool(int b) |
| 823 | { |
| 824 | cJSON *item = cJSON_New_Item(); |
| 825 | if (item)item->type = b ? cJSON_True : cJSON_False; |
| 826 | return item; |
| 827 | } |
| 828 | cJSON *cJSON_CreateNumber(double num) |
| 829 | { |
| 830 | cJSON *item = cJSON_New_Item(); |
| 831 | if (item) { |
| 832 | item->type = cJSON_Number; |
| 833 | item->valuedouble = num; |
| 834 | item->valueint = (int)num; |
| 835 | } |
| 836 | return item; |
| 837 | } |
| 838 | cJSON *cJSON_CreateString(const char *string) |
| 839 | { |
| 840 | cJSON *item = cJSON_New_Item(); |
| 841 | if (item) { |
| 842 | item->type = cJSON_String; |
| 843 | item->valuestring = cJSON_strdup(string); |
| 844 | } |
| 845 | return item; |
| 846 | } |
| 847 | cJSON *cJSON_CreateArray(void) |
| 848 | { |
| 849 | cJSON *item = cJSON_New_Item(); |
| 850 | if (item)item->type = cJSON_Array; |
| 851 | return item; |
| 852 | } |
| 853 | cJSON *cJSON_CreateObject(void) |
| 854 | { |
| 855 | cJSON *item = cJSON_New_Item(); |
| 856 | if (item)item->type = cJSON_Object; |
| 857 | return item; |
| 858 | } |
| 859 | |
| 860 | cJSON *cJSON_CreateIntArray(const int *numbers, int count) |
| 861 | { |
| 862 | int i; |
| 863 | cJSON *n = 0, *p = 0, *a = cJSON_CreateArray(); |
| 864 | for (i = 0; a && i < count; i++) { |
| 865 | n = cJSON_CreateNumber(numbers[i]); |
| 866 | if (!i)a->child = n; |
| 867 | else suffix_object(p, n); |
| 868 | p = n; |
| 869 | } |
| 870 | return a; |
| 871 | } |
| 872 | cJSON *cJSON_CreateFloatArray(const float *numbers, int count) |
| 873 | { |
| 874 | int i; |
| 875 | cJSON *n = 0, *p = 0, *a = cJSON_CreateArray(); |
| 876 | for (i = 0; a && i < count; i++) { |
| 877 | n = cJSON_CreateNumber(numbers[i]); |
| 878 | if (!i)a->child = n; |
| 879 | else suffix_object(p, n); |
| 880 | p = n; |
| 881 | } |
| 882 | return a; |
| 883 | } |
| 884 | cJSON *cJSON_CreateDoubleArray(const double *numbers, int count) |
| 885 | { |
| 886 | int i; |
| 887 | cJSON *n = 0, *p = 0, *a = cJSON_CreateArray(); |
| 888 | for (i = 0; a && i < count; i++) { |
| 889 | n = cJSON_CreateNumber(numbers[i]); |
| 890 | if (!i)a->child = n; |
| 891 | else suffix_object(p, n); |
| 892 | p = n; |
| 893 | } |
| 894 | return a; |
| 895 | } |
| 896 | cJSON *cJSON_CreateStringArray(const char **strings, int count) |
| 897 | { |
| 898 | int i; |
| 899 | cJSON *n = 0, *p = 0, *a = cJSON_CreateArray(); |
| 900 | for (i = 0; a && i < count; i++) { |
| 901 | n = cJSON_CreateString(strings[i]); |
| 902 | if (!i)a->child = n; |
| 903 | else suffix_object(p, n); |
| 904 | p = n; |
| 905 | } |
| 906 | return a; |
| 907 | } |
| 908 | |
| 909 | cJSON *cJSON_Duplicate(cJSON *item, int recurse) |
| 910 | { |
| 911 | cJSON *newitem, *cptr, *nptr = 0, *newchild; |
| 912 | |
| 913 | if (!item) |
| 914 | return 0; |
| 915 | |
| 916 | newitem = cJSON_New_Item(); |
| 917 | if (!newitem) |
| 918 | return 0; |
| 919 | |
| 920 | newitem->type = item->type & (~cJSON_IsReference), newitem->valueint = item->valueint, newitem->valuedouble = item->valuedouble; |
| 921 | if (item->valuestring) { |
| 922 | newitem->valuestring = cJSON_strdup(item->valuestring); |
| 923 | if (!newitem->valuestring) { |
| 924 | cJSON_Delete(newitem); |
| 925 | return 0; |
| 926 | } |
| 927 | } |
| 928 | if (item->string) { |
| 929 | newitem->string = cJSON_strdup(item->string); |
| 930 | if (!newitem->string) { |
| 931 | cJSON_Delete(newitem); |
| 932 | return 0; |
| 933 | } |
| 934 | } |
| 935 | |
| 936 | if (!recurse) |
| 937 | return newitem; |
| 938 | |
| 939 | cptr = item->child; |
| 940 | while (cptr) { |
| 941 | newchild = cJSON_Duplicate(cptr, 1); |
| 942 | if (!newchild) { |
| 943 | cJSON_Delete(newitem); |
| 944 | return 0; |
| 945 | } |
| 946 | if (nptr) { |
| 947 | nptr->next = newchild, newchild->prev = nptr; |
| 948 | nptr = newchild; |
| 949 | } else { |
| 950 | newitem->child = newchild; |
| 951 | nptr = newchild; |
| 952 | } |
| 953 | cptr = cptr->next; |
| 954 | } |
| 955 | return newitem; |
| 956 | } |
| 957 | |
| 958 | void cJSON_Minify(char *json) |
| 959 | { |
| 960 | char *cpr_str = json; |
| 961 | while (*json) { |
| 962 | if (*json == ' ') json++; |
| 963 | else if (*json == '\t') json++; |
| 964 | else if (*json == '\r') json++; |
| 965 | else if (*json == '\n') json++; |
| 966 | else if (*json == '/' && json[1] == '/') while (*json && *json != '\n') json++; |
| 967 | else if (*json == '/' && json[1] == '*') { |
| 968 | while (*json && !(*json == '*' && json[1] == '/')) json++; |
| 969 | json += 2; |
| 970 | } else if (*json == '\"') { |
| 971 | *cpr_str++ = *json++; |
| 972 | while (*json && *json != '\"') { |
| 973 | if (*json == '\\') *cpr_str++ = *json++; |
| 974 | *cpr_str++ = *json++; |
| 975 | } |
| 976 | *cpr_str++ = *json++; |
| 977 | } else *cpr_str++ = *json++; |
| 978 | } |
| 979 | *cpr_str = 0; |
| 980 | } |