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