123872eedae5d93aaa9c95199507f963a9de142d.svn-base (30457B)
1 /* 2 Copyright (c) 2009 Dave Gamble 3 Permission is hereby granted, free of charge, to any person obtaining a copy 4 of this software and associated documentation files (the "Software"), to deal 5 in the Software without restriction, including without limitation the rights 6 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 copies of the Software, and to permit persons to whom the Software is 8 furnished to do so, subject to the following conditions: 9 The above copyright notice and this permission notice shall be included in 10 all copies or substantial portions of the Software. 11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 17 THE SOFTWARE. 18 */ 19 20 /* cJSON */ 21 /* JSON parser in C. */ 22 23 #include <string.h> 24 #include <stdio.h> 25 #include <math.h> 26 #include <stdlib.h> 27 #include <float.h> 28 #include <limits.h> 29 #include <ctype.h> 30 #include "cJSON.h" 31 32 static const char *global_ep; 33 34 const char *cJSON_GetErrorPtr(void) { return global_ep; } 35 36 static int cJSON_strcasecmp(const char *s1, const char *s2) 37 { 38 if (!s1) return (s1 == s2) ? 0 : 1; if (!s2) return 1; 39 for (; tolower(*s1) == tolower(*s2); ++s1, ++s2) if (*s1 == 0) return 0; 40 return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); 41 } 42 43 static void *(*cJSON_malloc)(size_t sz) = malloc; 44 static void(*cJSON_free)(void *ptr) = free; 45 46 static char* cJSON_strdup(const char* str) 47 { 48 size_t len; 49 char* copy; 50 51 len = strlen(str) + 1; 52 if (!(copy = (char*)cJSON_malloc(len))) return 0; 53 memcpy(copy, str, len); 54 return copy; 55 } 56 57 void cJSON_InitHooks(cJSON_Hooks* hooks) 58 { 59 if (!hooks) { /* Reset hooks */ 60 cJSON_malloc = malloc; 61 cJSON_free = free; 62 return; 63 } 64 65 cJSON_malloc = (hooks->malloc_fn) ? hooks->malloc_fn : malloc; 66 cJSON_free = (hooks->free_fn) ? hooks->free_fn : free; 67 } 68 69 /* Internal constructor. */ 70 static cJSON *cJSON_New_Item(void) 71 { 72 cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); 73 if (node) memset(node, 0, sizeof(cJSON)); 74 return node; 75 } 76 77 /* Delete a cJSON structure. */ 78 void cJSON_Delete(cJSON *c) 79 { 80 cJSON *next; 81 while (c) 82 { 83 next = c->next; 84 if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child); 85 if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring); 86 if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string); 87 cJSON_free(c); 88 c = next; 89 } 90 } 91 92 /* Parse the input text to generate a number, and populate the result into item. */ 93 static const char *parse_number(cJSON *item, const char *num) 94 { 95 double n = 0, sign = 1, scale = 0; int subscale = 0, signsubscale = 1; 96 97 if (*num == '-') sign = -1, num++; /* Has sign? */ 98 if (*num == '0') num++; /* is zero */ 99 if (*num >= '1' && *num <= '9') do n = (n*10.0) + (*num++ - '0'); while (*num >= '0' && *num <= '9'); /* Number? */ 100 if (*num == '.' && num[1] >= '0' && num[1] <= '9') { num++; do n = (n*10.0) + (*num++ - '0'), scale--; while (*num >= '0' && *num <= '9'); } /* Fractional part? */ 101 if (*num == 'e' || *num == 'E') /* Exponent? */ 102 { 103 num++; if (*num == '+') num++; else if (*num == '-') signsubscale = -1, num++; /* With sign? */ 104 while (*num >= '0' && *num <= '9') subscale = (subscale * 10) + (*num++ - '0'); /* Number? */ 105 } 106 107 n = sign*n*pow(10.0, (scale + subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */ 108 109 item->valuedouble = n; 110 item->valueint = (int)n; 111 item->type = cJSON_Number; 112 return num; 113 } 114 115 static int pow2gt(int x) { --x; x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; return x + 1; } 116 117 typedef struct { char *buffer; int length; int offset; } printbuffer; 118 119 static char* ensure(printbuffer *p, int needed) 120 { 121 char *newbuffer; int newsize; 122 if (!p || !p->buffer) return 0; 123 needed += p->offset; 124 if (needed <= p->length) return p->buffer + p->offset; 125 126 newsize = pow2gt(needed); 127 newbuffer = (char*)cJSON_malloc(newsize); 128 if (!newbuffer) { cJSON_free(p->buffer); p->length = 0, p->buffer = 0; return 0; } 129 if (newbuffer) memcpy(newbuffer, p->buffer, p->length); 130 cJSON_free(p->buffer); 131 p->length = newsize; 132 p->buffer = newbuffer; 133 return newbuffer + p->offset; 134 } 135 136 static int update(printbuffer *p) 137 { 138 char *str; 139 if (!p || !p->buffer) return 0; 140 str = p->buffer + p->offset; 141 return p->offset + strlen(str); 142 } 143 144 /* Render the number nicely from the given item into a string. */ 145 static char *print_number(cJSON *item, printbuffer *p) 146 { 147 char *str = 0; 148 double d = item->valuedouble; 149 if (d == 0) 150 { 151 if (p) str = ensure(p, 2); 152 else str = (char*)cJSON_malloc(2); /* special case for 0. */ 153 if (str) strcpy(str, "0"); 154 } 155 else if (fabs(((double)item->valueint) - d) <= DBL_EPSILON && d <= INT_MAX && d >= INT_MIN) 156 { 157 if (p) str = ensure(p, 21); 158 else str = (char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */ 159 if (str) sprintf(str, "%d", item->valueint); 160 } 161 else 162 { 163 if (p) str = ensure(p, 64); 164 else str = (char*)cJSON_malloc(64); /* This is a nice tradeoff. */ 165 if (str) 166 { 167 if (fpclassify(d) != FP_ZERO && !isnormal(d)) sprintf(str, "null"); 168 else if (fabs(floor(d) - d) <= DBL_EPSILON && fabs(d)<1.0e60) sprintf(str, "%.0f", d); 169 else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str, "%e", d); 170 else sprintf(str, "%f", d); 171 } 172 } 173 return str; 174 } 175 176 static unsigned parse_hex4(const char *str) 177 { 178 unsigned h = 0; 179 if (*str >= '0' && *str <= '9') h += (*str) - '0'; else if (*str >= 'A' && *str <= 'F') h += 10 + (*str) - 'A'; else if (*str >= 'a' && *str <= 'f') h += 10 + (*str) - 'a'; else return 0; 180 h = h << 4; str++; 181 if (*str >= '0' && *str <= '9') h += (*str) - '0'; else if (*str >= 'A' && *str <= 'F') h += 10 + (*str) - 'A'; else if (*str >= 'a' && *str <= 'f') h += 10 + (*str) - 'a'; else return 0; 182 h = h << 4; str++; 183 if (*str >= '0' && *str <= '9') h += (*str) - '0'; else if (*str >= 'A' && *str <= 'F') h += 10 + (*str) - 'A'; else if (*str >= 'a' && *str <= 'f') h += 10 + (*str) - 'a'; else return 0; 184 h = h << 4; str++; 185 if (*str >= '0' && *str <= '9') h += (*str) - '0'; else if (*str >= 'A' && *str <= 'F') h += 10 + (*str) - 'A'; else if (*str >= 'a' && *str <= 'f') h += 10 + (*str) - 'a'; else return 0; 186 return h; 187 } 188 189 /* Parse the input text into an unescaped cstring, and populate item. */ 190 static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; 191 static const char *parse_string(cJSON *item, const char *str, const char **ep) 192 { 193 const char *ptr = str + 1, *end_ptr = str + 1; char *ptr2; char *out; int len = 0; unsigned uc, uc2; 194 if (*str != '\"') { *ep = str; return 0; } /* not a string! */ 195 196 while (*end_ptr != '\"' && *end_ptr && ++len) if (*end_ptr++ == '\\') end_ptr++; /* Skip escaped quotes. */ 197 198 out = (char*)cJSON_malloc(len + 1); /* This is how long we need for the string, roughly. */ 199 if (!out) return 0; 200 item->valuestring = out; /* assign here so out will be deleted during cJSON_Delete() later */ 201 item->type = cJSON_String; 202 203 ptr = str + 1; ptr2 = out; 204 while (ptr < end_ptr) 205 { 206 if (*ptr != '\\') *ptr2++ = *ptr++; 207 else 208 { 209 ptr++; 210 switch (*ptr) 211 { 212 case 'b': *ptr2++ = '\b'; break; 213 case 'f': *ptr2++ = '\f'; break; 214 case 'n': *ptr2++ = '\n'; break; 215 case 'r': *ptr2++ = '\r'; break; 216 case 't': *ptr2++ = '\t'; break; 217 case 'u': /* transcode utf16 to utf8. */ 218 uc = parse_hex4(ptr + 1); ptr += 4; /* get the unicode char. */ 219 if (ptr >= end_ptr) { *ep = str; return 0; } /* invalid */ 220 221 if ((uc >= 0xDC00 && uc <= 0xDFFF) || uc == 0) { *ep = str; return 0; } /* check for invalid. */ 222 223 if (uc >= 0xD800 && uc <= 0xDBFF) /* UTF16 surrogate pairs. */ 224 { 225 if (ptr + 6 > end_ptr) { *ep = str; return 0; } /* invalid */ 226 if (ptr[1] != '\\' || ptr[2] != 'u') { *ep = str; return 0; } /* missing second-half of surrogate. */ 227 uc2 = parse_hex4(ptr + 3); ptr += 6; 228 if (uc2<0xDC00 || uc2>0xDFFF) { *ep = str; return 0; } /* invalid second-half of surrogate. */ 229 uc = 0x10000 + (((uc & 0x3FF) << 10) | (uc2 & 0x3FF)); 230 } 231 232 len = 4; if (uc<0x80) len = 1; else if (uc<0x800) len = 2; else if (uc<0x10000) len = 3; ptr2 += len; 233 234 switch (len) { 235 case 4: *--ptr2 = ((uc | 0x80) & 0xBF); uc >>= 6; 236 case 3: *--ptr2 = ((uc | 0x80) & 0xBF); uc >>= 6; 237 case 2: *--ptr2 = ((uc | 0x80) & 0xBF); uc >>= 6; 238 case 1: *--ptr2 = (uc | firstByteMark[len]); 239 } 240 ptr2 += len; 241 break; 242 default: *ptr2++ = *ptr; break; 243 } 244 ptr++; 245 } 246 } 247 *ptr2 = 0; 248 if (*ptr == '\"') ptr++; 249 return ptr; 250 } 251 252 /* Render the cstring provided to an escaped version that can be printed. */ 253 static char *print_string_ptr(const char *str, printbuffer *p) 254 { 255 const char *ptr; char *ptr2, *out; int len = 0, flag = 0; unsigned char token; 256 257 if (!str) 258 { 259 if (p) out = ensure(p, 3); 260 else out = (char*)cJSON_malloc(3); 261 if (!out) return 0; 262 strcpy(out, "\"\""); 263 return out; 264 } 265 266 for (ptr = str; *ptr; ptr++) flag |= ((*ptr>0 && *ptr<32) || (*ptr == '\"') || (*ptr == '\\')) ? 1 : 0; 267 if (!flag) 268 { 269 len = ptr - str; 270 if (p) out = ensure(p, len + 3); 271 else out = (char*)cJSON_malloc(len + 3); 272 if (!out) return 0; 273 ptr2 = out; *ptr2++ = '\"'; 274 strcpy(ptr2, str); 275 ptr2[len] = '\"'; 276 ptr2[len + 1] = 0; 277 return out; 278 } 279 280 ptr = str; while ((token = *ptr) && ++len) { if (strchr("\"\\\b\f\n\r\t", token)) len++; else if (token<32) len += 5; ptr++; } 281 282 if (p) out = ensure(p, len + 3); 283 else out = (char*)cJSON_malloc(len + 3); 284 if (!out) return 0; 285 286 ptr2 = out; ptr = str; 287 *ptr2++ = '\"'; 288 while (*ptr) 289 { 290 if ((unsigned char)*ptr>31 && *ptr != '\"' && *ptr != '\\') *ptr2++ = *ptr++; 291 else 292 { 293 *ptr2++ = '\\'; 294 switch (token = *ptr++) 295 { 296 case '\\': *ptr2++ = '\\'; break; 297 case '\"': *ptr2++ = '\"'; break; 298 case '\b': *ptr2++ = 'b'; break; 299 case '\f': *ptr2++ = 'f'; break; 300 case '\n': *ptr2++ = 'n'; break; 301 case '\r': *ptr2++ = 'r'; break; 302 case '\t': *ptr2++ = 't'; break; 303 default: sprintf(ptr2, "u%04x", token); ptr2 += 5; break; /* escape and print */ 304 } 305 } 306 } 307 *ptr2++ = '\"'; *ptr2++ = 0; 308 return out; 309 } 310 /* Invote print_string_ptr (which is useful) on an item. */ 311 static char *print_string(cJSON *item, printbuffer *p) { return print_string_ptr(item->valuestring, p); } 312 313 /* Predeclare these prototypes. */ 314 static const char *parse_value(cJSON *item, const char *value, const char **ep); 315 static char *print_value(cJSON *item, int depth, int fmt, printbuffer *p); 316 static const char *parse_array(cJSON *item, const char *value, const char **ep); 317 static char *print_array(cJSON *item, int depth, int fmt, printbuffer *p); 318 static const char *parse_object(cJSON *item, const char *value, const char **ep); 319 static char *print_object(cJSON *item, int depth, int fmt, printbuffer *p); 320 321 /* Utility to jump whitespace and cr/lf */ 322 static const char *skip(const char *in) { while (in && *in && (unsigned char)*in <= 32) in++; return in; } 323 324 /* Parse an object - create a new root, and populate. */ 325 cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated) 326 { 327 const char *end = 0, **ep = return_parse_end ? return_parse_end : &global_ep; 328 cJSON *c = cJSON_New_Item(); 329 *ep = 0; 330 if (!c) return 0; /* memory fail */ 331 332 end = parse_value(c, skip(value), ep); 333 if (!end) { cJSON_Delete(c); return 0; } /* parse failure. ep is set. */ 334 335 /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ 336 if (require_null_terminated) { end = skip(end); if (*end) { cJSON_Delete(c); *ep = end; return 0; } } 337 if (return_parse_end) *return_parse_end = end; 338 return c; 339 } 340 /* Default options for cJSON_Parse */ 341 cJSON *cJSON_Parse(const char *value) { return cJSON_ParseWithOpts(value, 0, 0); } 342 343 /* Render a cJSON item/entity/structure to text. */ 344 char *cJSON_Print(cJSON *item) { return print_value(item, 0, 1, 0); } 345 char *cJSON_PrintUnformatted(cJSON *item) { return print_value(item, 0, 0, 0); } 346 347 char *cJSON_PrintBuffered(cJSON *item, int prebuffer, int fmt) 348 { 349 printbuffer p; 350 p.buffer = (char*)cJSON_malloc(prebuffer); 351 p.length = prebuffer; 352 p.offset = 0; 353 return print_value(item, 0, fmt, &p); 354 } 355 356 357 /* Parser core - when encountering text, process appropriately. */ 358 static const char *parse_value(cJSON *item, const char *value, const char **ep) 359 { 360 if (!value) return 0; /* Fail on null. */ 361 if (!strncmp(value, "null", 4)) { item->type = cJSON_NULL; return value + 4; } 362 if (!strncmp(value, "false", 5)) { item->type = cJSON_False; return value + 5; } 363 if (!strncmp(value, "true", 4)) { item->type = cJSON_True; item->valueint = 1; return value + 4; } 364 if (*value == '\"') { return parse_string(item, value, ep); } 365 if (*value == '-' || (*value >= '0' && *value <= '9')) { return parse_number(item, value); } 366 if (*value == '[') { return parse_array(item, value, ep); } 367 if (*value == '{') { return parse_object(item, value, ep); } 368 369 *ep = value; return 0; /* failure. */ 370 } 371 372 /* Render a value to text. */ 373 static char *print_value(cJSON *item, int depth, int fmt, printbuffer *p) 374 { 375 char *out = 0; 376 if (!item) return 0; 377 if (p) 378 { 379 switch ((item->type) & 255) 380 { 381 case cJSON_NULL: {out = ensure(p, 5); if (out) strcpy(out, "null"); break; } 382 case cJSON_False: {out = ensure(p, 6); if (out) strcpy(out, "false"); break; } 383 case cJSON_True: {out = ensure(p, 5); if (out) strcpy(out, "true"); break; } 384 case cJSON_Number: out = print_number(item, p); break; 385 case cJSON_String: out = print_string(item, p); break; 386 case cJSON_Array: out = print_array(item, depth, fmt, p); break; 387 case cJSON_Object: out = print_object(item, depth, fmt, p); break; 388 } 389 } 390 else 391 { 392 switch ((item->type) & 255) 393 { 394 case cJSON_NULL: out = cJSON_strdup("null"); break; 395 case cJSON_False: out = cJSON_strdup("false"); break; 396 case cJSON_True: out = cJSON_strdup("true"); break; 397 case cJSON_Number: out = print_number(item, 0); break; 398 case cJSON_String: out = print_string(item, 0); break; 399 case cJSON_Array: out = print_array(item, depth, fmt, 0); break; 400 case cJSON_Object: out = print_object(item, depth, fmt, 0); break; 401 } 402 } 403 return out; 404 } 405 406 /* Build an array from input text. */ 407 static const char *parse_array(cJSON *item, const char *value, const char **ep) 408 { 409 cJSON *child; 410 if (*value != '[') { *ep = value; return 0; } /* not an array! */ 411 412 item->type = cJSON_Array; 413 value = skip(value + 1); 414 if (*value == ']') return value + 1; /* empty array. */ 415 416 item->child = child = cJSON_New_Item(); 417 if (!item->child) return 0; /* memory fail */ 418 value = skip(parse_value(child, skip(value), ep)); /* skip any spacing, get the value. */ 419 if (!value) return 0; 420 421 while (*value == ',') 422 { 423 cJSON *new_item; 424 if (!(new_item = cJSON_New_Item())) return 0; /* memory fail */ 425 child->next = new_item; new_item->prev = child; child = new_item; 426 value = skip(parse_value(child, skip(value + 1), ep)); 427 if (!value) return 0; /* memory fail */ 428 } 429 430 if (*value == ']') return value + 1; /* end of array */ 431 *ep = value; return 0; /* malformed. */ 432 } 433 434 /* Render an array to text */ 435 static char *print_array(cJSON *item, int depth, int fmt, printbuffer *p) 436 { 437 char **entries; 438 char *out = 0, *ptr, *ret; int len = 5; 439 cJSON *child = item->child; 440 int numentries = 0, i = 0, fail = 0; 441 size_t tmplen = 0; 442 443 /* How many entries in the array? */ 444 while (child) numentries++, child = child->next; 445 /* Explicitly handle numentries==0 */ 446 if (!numentries) 447 { 448 if (p) out = ensure(p, 3); 449 else out = (char*)cJSON_malloc(3); 450 if (out) strcpy(out, "[]"); 451 return out; 452 } 453 454 if (p) 455 { 456 /* Compose the output array. */ 457 i = p->offset; 458 ptr = ensure(p, 1); if (!ptr) return 0; *ptr = '['; p->offset++; 459 child = item->child; 460 while (child && !fail) 461 { 462 print_value(child, depth + 1, fmt, p); 463 p->offset = update(p); 464 if (child->next) { len = fmt ? 2 : 1; ptr = ensure(p, len + 1); if (!ptr) return 0; *ptr++ = ','; if (fmt)*ptr++ = ' '; *ptr = 0; p->offset += len; } 465 child = child->next; 466 } 467 ptr = ensure(p, 2); if (!ptr) return 0; *ptr++ = ']'; *ptr = 0; 468 out = (p->buffer) + i; 469 } 470 else 471 { 472 /* Allocate an array to hold the values for each */ 473 entries = (char**)cJSON_malloc(numentries * sizeof(char*)); 474 if (!entries) return 0; 475 memset(entries, 0, numentries * sizeof(char*)); 476 /* Retrieve all the results: */ 477 child = item->child; 478 while (child && !fail) 479 { 480 ret = print_value(child, depth + 1, fmt, 0); 481 entries[i++] = ret; 482 if (ret) len += strlen(ret) + 2 + (fmt ? 1 : 0); else fail = 1; 483 child = child->next; 484 } 485 486 /* If we didn't fail, try to malloc the output string */ 487 if (!fail) out = (char*)cJSON_malloc(len); 488 /* If that fails, we fail. */ 489 if (!out) fail = 1; 490 491 /* Handle failure. */ 492 if (fail) 493 { 494 for (i = 0; i<numentries; i++) if (entries[i]) cJSON_free(entries[i]); 495 cJSON_free(entries); 496 return 0; 497 } 498 499 /* Compose the output array. */ 500 *out = '['; 501 ptr = out + 1; *ptr = 0; 502 for (i = 0; i<numentries; i++) 503 { 504 tmplen = strlen(entries[i]); memcpy(ptr, entries[i], tmplen); ptr += tmplen; 505 if (i != numentries - 1) { *ptr++ = ','; if (fmt)*ptr++ = ' '; *ptr = 0; } 506 cJSON_free(entries[i]); 507 } 508 cJSON_free(entries); 509 *ptr++ = ']'; *ptr++ = 0; 510 } 511 return out; 512 } 513 514 /* Build an object from the text. */ 515 static const char *parse_object(cJSON *item, const char *value, const char **ep) 516 { 517 cJSON *child; 518 if (*value != '{') { *ep = value; return 0; } /* not an object! */ 519 520 item->type = cJSON_Object; 521 value = skip(value + 1); 522 if (*value == '}') return value + 1; /* empty array. */ 523 524 item->child = child = cJSON_New_Item(); 525 if (!item->child) return 0; 526 value = skip(parse_string(child, skip(value), ep)); 527 if (!value) return 0; 528 child->string = child->valuestring; child->valuestring = 0; 529 if (*value != ':') { *ep = value; return 0; } /* fail! */ 530 value = skip(parse_value(child, skip(value + 1), ep)); /* skip any spacing, get the value. */ 531 if (!value) return 0; 532 533 while (*value == ',') 534 { 535 cJSON *new_item; 536 if (!(new_item = cJSON_New_Item())) return 0; /* memory fail */ 537 child->next = new_item; new_item->prev = child; child = new_item; 538 value = skip(parse_string(child, skip(value + 1), ep)); 539 if (!value) return 0; 540 child->string = child->valuestring; child->valuestring = 0; 541 if (*value != ':') { *ep = value; return 0; } /* fail! */ 542 value = skip(parse_value(child, skip(value + 1), ep)); /* skip any spacing, get the value. */ 543 if (!value) return 0; 544 } 545 546 if (*value == '}') return value + 1; /* end of array */ 547 *ep = value; return 0; /* malformed. */ 548 } 549 550 /* Render an object to text. */ 551 static char *print_object(cJSON *item, int depth, int fmt, printbuffer *p) 552 { 553 char **entries = 0, **names = 0; 554 char *out = 0, *ptr, *ret, *str; int len = 7, i = 0, j; 555 cJSON *child = item->child; 556 int numentries = 0, fail = 0; 557 size_t tmplen = 0; 558 /* Count the number of entries. */ 559 while (child) numentries++, child = child->next; 560 /* Explicitly handle empty object case */ 561 if (!numentries) 562 { 563 if (p) out = ensure(p, fmt ? depth + 4 : 3); 564 else out = (char*)cJSON_malloc(fmt ? depth + 4 : 3); 565 if (!out) return 0; 566 ptr = out; *ptr++ = '{'; 567 if (fmt) { *ptr++ = '\n'; for (i = 0; i<depth; i++) *ptr++ = '\t'; } 568 *ptr++ = '}'; *ptr++ = 0; 569 return out; 570 } 571 if (p) 572 { 573 /* Compose the output: */ 574 i = p->offset; 575 len = fmt ? 2 : 1; ptr = ensure(p, len + 1); if (!ptr) return 0; 576 *ptr++ = '{'; if (fmt) *ptr++ = '\n'; *ptr = 0; p->offset += len; 577 child = item->child; depth++; 578 while (child) 579 { 580 if (fmt) 581 { 582 ptr = ensure(p, depth); if (!ptr) return 0; 583 for (j = 0; j<depth; j++) *ptr++ = '\t'; 584 p->offset += depth; 585 } 586 print_string_ptr(child->string, p); 587 p->offset = update(p); 588 589 len = fmt ? 2 : 1; 590 ptr = ensure(p, len); if (!ptr) return 0; 591 *ptr++ = ':'; if (fmt) *ptr++ = '\t'; 592 p->offset += len; 593 594 print_value(child, depth, fmt, p); 595 p->offset = update(p); 596 597 len = (fmt ? 1 : 0) + (child->next ? 1 : 0); 598 ptr = ensure(p, len + 1); if (!ptr) return 0; 599 if (child->next) *ptr++ = ','; 600 if (fmt) *ptr++ = '\n'; *ptr = 0; 601 p->offset += len; 602 child = child->next; 603 } 604 ptr = ensure(p, fmt ? (depth + 1) : 2); if (!ptr) return 0; 605 if (fmt) for (i = 0; i<depth - 1; i++) *ptr++ = '\t'; 606 *ptr++ = '}'; *ptr = 0; 607 out = (p->buffer) + i; 608 } 609 else 610 { 611 /* Allocate space for the names and the objects */ 612 entries = (char**)cJSON_malloc(numentries * sizeof(char*)); 613 if (!entries) return 0; 614 names = (char**)cJSON_malloc(numentries * sizeof(char*)); 615 if (!names) { cJSON_free(entries); return 0; } 616 memset(entries, 0, sizeof(char*)*numentries); 617 memset(names, 0, sizeof(char*)*numentries); 618 619 /* Collect all the results into our arrays: */ 620 child = item->child; depth++; if (fmt) len += depth; 621 while (child && !fail) 622 { 623 names[i] = str = print_string_ptr(child->string, 0); 624 entries[i++] = ret = print_value(child, depth, fmt, 0); 625 if (str && ret) len += strlen(ret) + strlen(str) + 2 + (fmt ? 2 + depth : 0); else fail = 1; 626 child = child->next; 627 } 628 629 /* Try to allocate the output string */ 630 if (!fail) out = (char*)cJSON_malloc(len); 631 if (!out) fail = 1; 632 633 /* Handle failure */ 634 if (fail) 635 { 636 for (i = 0; i<numentries; i++) { if (names[i]) cJSON_free(names[i]); if (entries[i]) cJSON_free(entries[i]); } 637 cJSON_free(names); cJSON_free(entries); 638 return 0; 639 } 640 641 /* Compose the output: */ 642 *out = '{'; ptr = out + 1; if (fmt)*ptr++ = '\n'; *ptr = 0; 643 for (i = 0; i<numentries; i++) 644 { 645 if (fmt) for (j = 0; j<depth; j++) *ptr++ = '\t'; 646 tmplen = strlen(names[i]); memcpy(ptr, names[i], tmplen); ptr += tmplen; 647 *ptr++ = ':'; if (fmt) *ptr++ = '\t'; 648 strcpy(ptr, entries[i]); ptr += strlen(entries[i]); 649 if (i != numentries - 1) *ptr++ = ','; 650 if (fmt) *ptr++ = '\n'; *ptr = 0; 651 cJSON_free(names[i]); cJSON_free(entries[i]); 652 } 653 654 cJSON_free(names); cJSON_free(entries); 655 if (fmt) for (i = 0; i<depth - 1; i++) *ptr++ = '\t'; 656 *ptr++ = '}'; *ptr++ = 0; 657 } 658 return out; 659 } 660 661 /* Get Array size/item / object item. */ 662 int cJSON_GetArraySize(cJSON *array) { cJSON *c = array->child; int i = 0; while (c)i++, c = c->next; return i; } 663 cJSON *cJSON_GetArrayItem(cJSON *array, int item) { cJSON *c = array ? array->child : 0; while (c && item>0) item--, c = c->next; return c; } 664 cJSON *cJSON_GetObjectItem(cJSON *object, const char *string) { cJSON *c = object ? object->child : 0; while (c && cJSON_strcasecmp(c->string, string)) c = c->next; return c; } 665 int cJSON_HasObjectItem(cJSON *object, const char *string) { return cJSON_GetObjectItem(object, string) ? 1 : 0; } 666 667 /* Utility for array list handling. */ 668 static void suffix_object(cJSON *prev, cJSON *item) { prev->next = item; item->prev = prev; } 669 /* Utility for handling references. */ 670 static cJSON *create_reference(cJSON *item) { cJSON *ref = cJSON_New_Item(); if (!ref) return 0; memcpy(ref, item, sizeof(cJSON)); ref->string = 0; ref->type |= cJSON_IsReference; ref->next = ref->prev = 0; return ref; } 671 672 /* Add item to array/object. */ 673 void cJSON_AddItemToArray(cJSON *array, cJSON *item) { cJSON *c = array->child; if (!item) return; if (!c) { array->child = item; } else { while (c && c->next) c = c->next; suffix_object(c, item); } } 674 void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) { if (!item) return; if (item->string) cJSON_free(item->string); item->string = cJSON_strdup(string); cJSON_AddItemToArray(object, item); } 675 void cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) { if (!item) return; if (!(item->type&cJSON_StringIsConst) && item->string) cJSON_free(item->string); item->string = (char*)string; item->type |= cJSON_StringIsConst; cJSON_AddItemToArray(object, item); } 676 void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) { cJSON_AddItemToArray(array, create_reference(item)); } 677 void cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) { cJSON_AddItemToObject(object, string, create_reference(item)); } 678 679 cJSON *cJSON_DetachItemFromArray(cJSON *array, int which) { 680 cJSON *c = array->child; while (c && which>0) c = c->next, which--; if (!c) return 0; 681 if (c->prev) c->prev->next = c->next; if (c->next) c->next->prev = c->prev; if (c == array->child) array->child = c->next; c->prev = c->next = 0; return c; 682 } 683 void cJSON_DeleteItemFromArray(cJSON *array, int which) { cJSON_Delete(cJSON_DetachItemFromArray(array, which)); } 684 cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string) { int i = 0; cJSON *c = object->child; while (c && cJSON_strcasecmp(c->string, string)) i++, c = c->next; if (c) return cJSON_DetachItemFromArray(object, i); return 0; } 685 void cJSON_DeleteItemFromObject(cJSON *object, const char *string) { cJSON_Delete(cJSON_DetachItemFromObject(object, string)); } 686 687 /* Replace array/object items with new ones. */ 688 void cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) { 689 cJSON *c = array->child; while (c && which>0) c = c->next, which--; if (!c) { cJSON_AddItemToArray(array, newitem); return; } 690 newitem->next = c; newitem->prev = c->prev; c->prev = newitem; if (c == array->child) array->child = newitem; else newitem->prev->next = newitem; 691 } 692 void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) { 693 cJSON *c = array->child; while (c && which>0) c = c->next, which--; if (!c) return; 694 newitem->next = c->next; newitem->prev = c->prev; if (newitem->next) newitem->next->prev = newitem; 695 if (c == array->child) array->child = newitem; else newitem->prev->next = newitem; c->next = c->prev = 0; cJSON_Delete(c); 696 } 697 void cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) { int i = 0; cJSON *c = object->child; while (c && cJSON_strcasecmp(c->string, string))i++, c = c->next; if (c) { newitem->string = cJSON_strdup(string); cJSON_ReplaceItemInArray(object, i, newitem); } } 698 699 /* Create basic types: */ 700 cJSON *cJSON_CreateNull(void) { cJSON *item = cJSON_New_Item(); if (item)item->type = cJSON_NULL; return item; } 701 cJSON *cJSON_CreateTrue(void) { cJSON *item = cJSON_New_Item(); if (item)item->type = cJSON_True; return item; } 702 cJSON *cJSON_CreateFalse(void) { cJSON *item = cJSON_New_Item(); if (item)item->type = cJSON_False; return item; } 703 cJSON *cJSON_CreateBool(int b) { cJSON *item = cJSON_New_Item(); if (item)item->type = b ? cJSON_True : cJSON_False; return item; } 704 cJSON *cJSON_CreateNumber(double num) { cJSON *item = cJSON_New_Item(); if (item) { item->type = cJSON_Number; item->valuedouble = num; item->valueint = (int)num; }return item; } 705 cJSON *cJSON_CreateString(const char *string) { cJSON *item = cJSON_New_Item(); if (item) { item->type = cJSON_String; item->valuestring = cJSON_strdup(string); if (!item->valuestring) { cJSON_Delete(item); return 0; } }return item; } 706 cJSON *cJSON_CreateArray(void) { cJSON *item = cJSON_New_Item(); if (item)item->type = cJSON_Array; return item; } 707 cJSON *cJSON_CreateObject(void) { cJSON *item = cJSON_New_Item(); if (item)item->type = cJSON_Object; return item; } 708 709 /* Create Arrays: */ 710 cJSON *cJSON_CreateIntArray(const int *numbers, int count) { int i; cJSON *n = 0, *p = 0, *a = cJSON_CreateArray(); for (i = 0; a && i<count; i++) { n = cJSON_CreateNumber(numbers[i]); if (!n) { cJSON_Delete(a); return 0; }if (!i)a->child = n; else suffix_object(p, n); p = n; }return a; } 711 cJSON *cJSON_CreateFloatArray(const float *numbers, int count) { int i; cJSON *n = 0, *p = 0, *a = cJSON_CreateArray(); for (i = 0; a && i<count; i++) { n = cJSON_CreateNumber(numbers[i]); if (!n) { cJSON_Delete(a); return 0; }if (!i)a->child = n; else suffix_object(p, n); p = n; }return a; } 712 cJSON *cJSON_CreateDoubleArray(const double *numbers, int count) { int i; cJSON *n = 0, *p = 0, *a = cJSON_CreateArray(); for (i = 0; a && i<count; i++) { n = cJSON_CreateNumber(numbers[i]); if (!n) { cJSON_Delete(a); return 0; }if (!i)a->child = n; else suffix_object(p, n); p = n; }return a; } 713 cJSON *cJSON_CreateStringArray(const char **strings, int count) { int i; cJSON *n = 0, *p = 0, *a = cJSON_CreateArray(); for (i = 0; a && i<count; i++) { n = cJSON_CreateString(strings[i]); if (!n) { cJSON_Delete(a); return 0; }if (!i)a->child = n; else suffix_object(p, n); p = n; }return a; } 714 715 /* Duplication */ 716 cJSON *cJSON_Duplicate(cJSON *item, int recurse) 717 { 718 cJSON *newitem, *cptr, *nptr = 0, *newchild; 719 /* Bail on bad ptr */ 720 if (!item) return 0; 721 /* Create new item */ 722 newitem = cJSON_New_Item(); 723 if (!newitem) return 0; 724 /* Copy over all vars */ 725 newitem->type = item->type&(~cJSON_IsReference), newitem->valueint = item->valueint, newitem->valuedouble = item->valuedouble; 726 if (item->valuestring) { newitem->valuestring = cJSON_strdup(item->valuestring); if (!newitem->valuestring) { cJSON_Delete(newitem); return 0; } } 727 if (item->string) { newitem->string = cJSON_strdup(item->string); if (!newitem->string) { cJSON_Delete(newitem); return 0; } } 728 /* If non-recursive, then we're done! */ 729 if (!recurse) return newitem; 730 /* Walk the ->next chain for the child. */ 731 cptr = item->child; 732 while (cptr) 733 { 734 newchild = cJSON_Duplicate(cptr, 1); /* Duplicate (with recurse) each item in the ->next chain */ 735 if (!newchild) { cJSON_Delete(newitem); return 0; } 736 if (nptr) { nptr->next = newchild, newchild->prev = nptr; nptr = newchild; } /* If newitem->child already set, then crosswire ->prev and ->next and move on */ 737 else { newitem->child = newchild; nptr = newchild; } /* Set newitem->child and move to it */ 738 cptr = cptr->next; 739 } 740 return newitem; 741 } 742 743 void cJSON_Minify(char *json) 744 { 745 char *into = json; 746 while (*json) 747 { 748 if (*json == ' ') json++; 749 else if (*json == '\t') json++; /* Whitespace characters. */ 750 else if (*json == '\r') json++; 751 else if (*json == '\n') json++; 752 else if (*json == '/' && json[1] == '/') while (*json && *json != '\n') json++; /* double-slash comments, to end of line. */ 753 else if (*json == '/' && json[1] == '*') { while (*json && !(*json == '*' && json[1] == '/')) json++; json += 2; } /* multiline comments. */ 754 else if (*json == '\"') { *into++ = *json++; while (*json && *json != '\"') { if (*json == '\\') *into++ = *json++; *into++ = *json++; }*into++ = *json++; } /* string literals, which are \" sensitive. */ 755 else *into++ = *json++; /* All other characters. */ 756 } 757 *into = 0; /* and null-terminate. */ 758 }