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