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) if (*end_ptr++ == '\\') end_ptr++; /* Skip escaped quotes. */ 209 210 out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */ 211 if (!out) return 0; 212 item->valuestring=out; /* assign here so out will be deleted during cJSON_Delete() later */ 213 item->type=cJSON_String; 214 215 ptr=str+1;ptr2=out; 216 while (ptr < end_ptr) 217 { 218 if (*ptr!='\\') *ptr2++=*ptr++; 219 else 220 { 221 ptr++; 222 switch (*ptr) 223 { 224 case 'b': *ptr2++='\b'; break; 225 case 'f': *ptr2++='\f'; break; 226 case 'n': *ptr2++='\n'; break; 227 case 'r': *ptr2++='\r'; break; 228 case 't': *ptr2++='\t'; break; 229 case 'u': /* transcode utf16 to utf8. */ 230 uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */ 231 if (ptr >= end_ptr) {*ep=str;return 0;} /* invalid */ 232 233 if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) {*ep=str;return 0;} /* check for invalid. */ 234 235 if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */ 236 { 237 if (ptr+6 > end_ptr) {*ep=str;return 0;} /* invalid */ 238 if (ptr[1]!='\\' || ptr[2]!='u') {*ep=str;return 0;} /* missing second-half of surrogate. */ 239 uc2=parse_hex4(ptr+3);ptr+=6; 240 if (uc2<0xDC00 || uc2>0xDFFF) {*ep=str;return 0;} /* invalid second-half of surrogate. */ 241 uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF)); 242 } 243 244 len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; 245 246 switch (len) { 247 case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; 248 case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; 249 case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; 250 case 1: *--ptr2 =(uc | firstByteMark[len]); 251 } 252 ptr2+=len; 253 break; 254 default: *ptr2++=*ptr; break; 255 } 256 ptr++; 257 } 258 } 259 *ptr2=0; 260 if (*ptr=='\"') ptr++; 261 return ptr; 262 } 263 264 /* Render the cstring provided to an escaped version that can be printed. */ 265 static char *print_string_ptr(const char *str,printbuffer *p) 266 { 267 const char *ptr;char *ptr2,*out;int len=0,flag=0;unsigned char token; 268 269 if (!str) 270 { 271 if (p) out=ensure(p,3); 272 else out=(char*)cJSON_malloc(3); 273 if (!out) return 0; 274 strcpy(out,"\"\""); 275 return out; 276 } 277 278 for (ptr=str;*ptr;ptr++) flag|=((*ptr>0 && *ptr<32)||(*ptr=='\"')||(*ptr=='\\'))?1:0; 279 if (!flag) 280 { 281 len=ptr-str; 282 if (p) out=ensure(p,len+3); 283 else out=(char*)cJSON_malloc(len+3); 284 if (!out) return 0; 285 ptr2=out;*ptr2++='\"'; 286 strcpy(ptr2,str); 287 ptr2[len]='\"'; 288 ptr2[len+1]=0; 289 return out; 290 } 291 292 ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;} 293 294 if (p) out=ensure(p,len+3); 295 else out=(char*)cJSON_malloc(len+3); 296 if (!out) return 0; 297 298 ptr2=out;ptr=str; 299 *ptr2++='\"'; 300 while (*ptr) 301 { 302 if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; 303 else 304 { 305 *ptr2++='\\'; 306 switch (token=*ptr++) 307 { 308 case '\\': *ptr2++='\\'; break; 309 case '\"': *ptr2++='\"'; break; 310 case '\b': *ptr2++='b'; break; 311 case '\f': *ptr2++='f'; break; 312 case '\n': *ptr2++='n'; break; 313 case '\r': *ptr2++='r'; break; 314 case '\t': *ptr2++='t'; break; 315 default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */ 316 } 317 } 318 } 319 *ptr2++='\"';*ptr2++=0; 320 return out; 321 } 322 /* Invote print_string_ptr (which is useful) on an item. */ 323 static char *print_string(cJSON *item,printbuffer *p) {return print_string_ptr(item->valuestring,p);} 324 325 /* Predeclare these prototypes. */ 326 static const char *parse_value(cJSON *item,const char *value,const char **ep); 327 static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p); 328 static const char *parse_array(cJSON *item,const char *value,const char **ep); 329 static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p); 330 static const char *parse_object(cJSON *item,const char *value,const char **ep); 331 static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p); 332 333 /* Utility to jump whitespace and cr/lf */ 334 static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;} 335 336 /* Parse an object - create a new root, and populate. */ 337 cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated) 338 { 339 const char *end=0,**ep=return_parse_end?return_parse_end:&global_ep; 340 cJSON *c=cJSON_New_Item(); 341 *ep=0; 342 if (!c) return 0; /* memory fail */ 343 344 end=parse_value(c,skip(value),ep); 345 if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */ 346 347 /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ 348 if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);*ep=end;return 0;}} 349 if (return_parse_end) *return_parse_end=end; 350 return c; 351 } 352 /* Default options for cJSON_Parse */ 353 cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);} 354 355 /* Render a cJSON item/entity/structure to text. */ 356 char *cJSON_Print(cJSON *item) {return print_value(item,0,1,0);} 357 char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0,0);} 358 359 char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt) 360 { 361 printbuffer p; 362 p.buffer=(char*)cJSON_malloc(prebuffer); 363 p.length=prebuffer; 364 p.offset=0; 365 return print_value(item,0,fmt,&p); 366 } 367 368 369 /* Parser core - when encountering text, process appropriately. */ 370 static const char *parse_value(cJSON *item,const char *value,const char **ep) 371 { 372 if (!value) return 0; /* Fail on null. */ 373 if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; } 374 if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; } 375 if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; } 376 if (*value=='\"') { return parse_string(item,value,ep); } 377 if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); } 378 if (*value=='[') { return parse_array(item,value,ep); } 379 if (*value=='{') { return parse_object(item,value,ep); } 380 381 *ep=value;return 0; /* failure. */ 382 } 383 384 /* Render a value to text. */ 385 static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p) 386 { 387 char *out=0; 388 if (!item) return 0; 389 if (p) 390 { 391 switch ((item->type)&255) 392 { 393 case cJSON_NULL: {out=ensure(p,5); if (out) strcpy(out,"null"); break;} 394 case cJSON_False: {out=ensure(p,6); if (out) strcpy(out,"false"); break;} 395 case cJSON_True: {out=ensure(p,5); if (out) strcpy(out,"true"); break;} 396 case cJSON_Number: out=print_number(item,p);break; 397 case cJSON_String: out=print_string(item,p);break; 398 case cJSON_Array: out=print_array(item,depth,fmt,p);break; 399 case cJSON_Object: out=print_object(item,depth,fmt,p);break; 400 } 401 } 402 else 403 { 404 switch ((item->type)&255) 405 { 406 case cJSON_NULL: out=cJSON_strdup("null"); break; 407 case cJSON_False: out=cJSON_strdup("false");break; 408 case cJSON_True: out=cJSON_strdup("true"); break; 409 case cJSON_Number: out=print_number(item,0);break; 410 case cJSON_String: out=print_string(item,0);break; 411 case cJSON_Array: out=print_array(item,depth,fmt,0);break; 412 case cJSON_Object: out=print_object(item,depth,fmt,0);break; 413 } 414 } 415 return out; 416 } 417 418 /* Build an array from input text. */ 419 static const char *parse_array(cJSON *item,const char *value,const char **ep) 420 { 421 cJSON *child; 422 if (*value!='[') {*ep=value;return 0;} /* not an array! */ 423 424 item->type=cJSON_Array; 425 value=skip(value+1); 426 if (*value==']') return value+1; /* empty array. */ 427 428 item->child=child=cJSON_New_Item(); 429 if (!item->child) return 0; /* memory fail */ 430 value=skip(parse_value(child,skip(value),ep)); /* skip any spacing, get the value. */ 431 if (!value) return 0; 432 433 while (*value==',') 434 { 435 cJSON *new_item; 436 if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ 437 child->next=new_item;new_item->prev=child;child=new_item; 438 value=skip(parse_value(child,skip(value+1),ep)); 439 if (!value) return 0; /* memory fail */ 440 } 441 442 if (*value==']') return value+1; /* end of array */ 443 *ep=value;return 0; /* malformed. */ 444 } 445 446 /* Render an array to text */ 447 static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p) 448 { 449 char **entries; 450 char *out=0,*ptr,*ret;int len=5; 451 cJSON *child=item->child; 452 int numentries=0,i=0,fail=0; 453 size_t tmplen=0; 454 455 /* How many entries in the array? */ 456 while (child) numentries++,child=child->next; 457 /* Explicitly handle numentries==0 */ 458 if (!numentries) 459 { 460 if (p) out=ensure(p,3); 461 else out=(char*)cJSON_malloc(3); 462 if (out) strcpy(out,"[]"); 463 return out; 464 } 465 466 if (p) 467 { 468 /* Compose the output array. */ 469 i=p->offset; 470 ptr=ensure(p,1);if (!ptr) return 0; *ptr='['; p->offset++; 471 child=item->child; 472 while (child && !fail) 473 { 474 print_value(child,depth+1,fmt,p); 475 p->offset=update(p); 476 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;} 477 child=child->next; 478 } 479 ptr=ensure(p,2);if (!ptr) return 0; *ptr++=']';*ptr=0; 480 out=(p->buffer)+i; 481 } 482 else 483 { 484 /* Allocate an array to hold the values for each */ 485 entries=(char**)cJSON_malloc(numentries*sizeof(char*)); 486 if (!entries) return 0; 487 memset(entries,0,numentries*sizeof(char*)); 488 /* Retrieve all the results: */ 489 child=item->child; 490 while (child && !fail) 491 { 492 ret=print_value(child,depth+1,fmt,0); 493 entries[i++]=ret; 494 if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; 495 child=child->next; 496 } 497 498 /* If we didn't fail, try to malloc the output string */ 499 if (!fail) out=(char*)cJSON_malloc(len); 500 /* If that fails, we fail. */ 501 if (!out) fail=1; 502 503 /* Handle failure. */ 504 if (fail) 505 { 506 for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]); 507 cJSON_free(entries); 508 return 0; 509 } 510 511 /* Compose the output array. */ 512 *out='['; 513 ptr=out+1;*ptr=0; 514 for (i=0;i<numentries;i++) 515 { 516 tmplen=strlen(entries[i]);memcpy(ptr,entries[i],tmplen);ptr+=tmplen; 517 if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;} 518 cJSON_free(entries[i]); 519 } 520 cJSON_free(entries); 521 *ptr++=']';*ptr++=0; 522 } 523 return out; 524 } 525 526 /* Build an object from the text. */ 527 static const char *parse_object(cJSON *item,const char *value,const char **ep) 528 { 529 cJSON *child; 530 if (*value!='{') {*ep=value;return 0;} /* not an object! */ 531 532 item->type=cJSON_Object; 533 value=skip(value+1); 534 if (*value=='}') return value+1; /* empty array. */ 535 536 item->child=child=cJSON_New_Item(); 537 if (!item->child) return 0; 538 value=skip(parse_string(child,skip(value),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 while (*value==',') 546 { 547 cJSON *new_item; 548 if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ 549 child->next=new_item;new_item->prev=child;child=new_item; 550 value=skip(parse_string(child,skip(value+1),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 558 if (*value=='}') return value+1; /* end of array */ 559 *ep=value;return 0; /* malformed. */ 560 } 561 562 /* Render an object to text. */ 563 static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p) 564 { 565 char **entries=0,**names=0; 566 char *out=0,*ptr,*ret,*str;int len=7,i=0,j; 567 cJSON *child=item->child; 568 int numentries=0,fail=0; 569 size_t tmplen=0; 570 /* Count the number of entries. */ 571 while (child) numentries++,child=child->next; 572 /* Explicitly handle empty object case */ 573 if (!numentries) 574 { 575 if (p) out=ensure(p,fmt?depth+4:3); 576 else out=(char*)cJSON_malloc(fmt?depth+4:3); 577 if (!out) return 0; 578 ptr=out;*ptr++='{'; 579 if (fmt) {*ptr++='\n';for (i=0;i<depth;i++) *ptr++='\t';} 580 *ptr++='}';*ptr++=0; 581 return out; 582 } 583 if (p) 584 { 585 /* Compose the output: */ 586 i=p->offset; 587 len=fmt?2:1; ptr=ensure(p,len+1); if (!ptr) return 0; 588 *ptr++='{'; if (fmt) *ptr++='\n'; *ptr=0; p->offset+=len; 589 child=item->child;depth++; 590 while (child) 591 { 592 if (fmt) 593 { 594 ptr=ensure(p,depth); if (!ptr) return 0; 595 for (j=0;j<depth;j++) *ptr++='\t'; 596 p->offset+=depth; 597 } 598 print_string_ptr(child->string,p); 599 p->offset=update(p); 600 601 len=fmt?2:1; 602 ptr=ensure(p,len); if (!ptr) return 0; 603 *ptr++=':';if (fmt) *ptr++='\t'; 604 p->offset+=len; 605 606 print_value(child,depth,fmt,p); 607 p->offset=update(p); 608 609 len=(fmt?1:0)+(child->next?1:0); 610 ptr=ensure(p,len+1); if (!ptr) return 0; 611 if (child->next) *ptr++=','; 612 if (fmt) *ptr++='\n';*ptr=0; 613 p->offset+=len; 614 child=child->next; 615 } 616 ptr=ensure(p,fmt?(depth+1):2); if (!ptr) return 0; 617 if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t'; 618 *ptr++='}';*ptr=0; 619 out=(p->buffer)+i; 620 } 621 else 622 { 623 /* Allocate space for the names and the objects */ 624 entries=(char**)cJSON_malloc(numentries*sizeof(char*)); 625 if (!entries) return 0; 626 names=(char**)cJSON_malloc(numentries*sizeof(char*)); 627 if (!names) {cJSON_free(entries);return 0;} 628 memset(entries,0,sizeof(char*)*numentries); 629 memset(names,0,sizeof(char*)*numentries); 630 631 /* Collect all the results into our arrays: */ 632 child=item->child;depth++;if (fmt) len+=depth; 633 while (child && !fail) 634 { 635 names[i]=str=print_string_ptr(child->string,0); 636 entries[i++]=ret=print_value(child,depth,fmt,0); 637 if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1; 638 child=child->next; 639 } 640 641 /* Try to allocate the output string */ 642 if (!fail) out=(char*)cJSON_malloc(len); 643 if (!out) fail=1; 644 645 /* Handle failure */ 646 if (fail) 647 { 648 for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);} 649 cJSON_free(names);cJSON_free(entries); 650 return 0; 651 } 652 653 /* Compose the output: */ 654 *out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0; 655 for (i=0;i<numentries;i++) 656 { 657 if (fmt) for (j=0;j<depth;j++) *ptr++='\t'; 658 tmplen=strlen(names[i]);memcpy(ptr,names[i],tmplen);ptr+=tmplen; 659 *ptr++=':';if (fmt) *ptr++='\t'; 660 strcpy(ptr,entries[i]);ptr+=strlen(entries[i]); 661 if (i!=numentries-1) *ptr++=','; 662 if (fmt) *ptr++='\n';*ptr=0; 663 cJSON_free(names[i]);cJSON_free(entries[i]); 664 } 665 666 cJSON_free(names);cJSON_free(entries); 667 if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t'; 668 *ptr++='}';*ptr++=0; 669 } 670 return out; 671 } 672 673 /* Get Array size/item / object item. */ 674 int cJSON_GetArraySize(cJSON *array) {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;} 675 cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array?array->child:0;while (c && item>0) item--,c=c->next; return c;} 676 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;} 677 int cJSON_HasObjectItem(cJSON *object,const char *string) {return cJSON_GetObjectItem(object,string)?1:0;} 678 679 /* Utility for array list handling. */ 680 static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} 681 /* Utility for handling references. */ 682 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;} 683 684 /* Add item to array/object. */ 685 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);}} 686 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);} 687 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);} 688 void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} 689 void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} 690 691 cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; 692 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;} 693 void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} 694 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;} 695 void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} 696 697 /* Replace array/object items with new ones. */ 698 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;} 699 newitem->next=c;newitem->prev=c->prev;c->prev=newitem;if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;} 700 void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; 701 newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; 702 if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} 703 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);}} 704 705 /* Create basic types: */ 706 cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} 707 cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} 708 cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} 709 cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} 710 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;} 711 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;} 712 cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} 713 cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} 714 715 /* Create Arrays: */ 716 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;} 717 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;} 718 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;} 719 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;} 720 721 /* Duplication */ 722 cJSON *cJSON_Duplicate(cJSON *item,int recurse) 723 { 724 cJSON *newitem,*cptr,*nptr=0,*newchild; 725 /* Bail on bad ptr */ 726 if (!item) return 0; 727 /* Create new item */ 728 newitem=cJSON_New_Item(); 729 if (!newitem) return 0; 730 /* Copy over all vars */ 731 newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble; 732 if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}} 733 if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}} 734 /* If non-recursive, then we're done! */ 735 if (!recurse) return newitem; 736 /* Walk the ->next chain for the child. */ 737 cptr=item->child; 738 while (cptr) 739 { 740 newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */ 741 if (!newchild) {cJSON_Delete(newitem);return 0;} 742 if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */ 743 else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */ 744 cptr=cptr->next; 745 } 746 return newitem; 747 } 748 749 void cJSON_Minify(char *json) 750 { 751 char *into=json; 752 while (*json) 753 { 754 if (*json==' ') json++; 755 else if (*json=='\t') json++; /* Whitespace characters. */ 756 else if (*json=='\r') json++; 757 else if (*json=='\n') json++; 758 else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; /* double-slash comments, to end of line. */ 759 else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} /* multiline comments. */ 760 else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} /* string literals, which are \" sensitive. */ 761 else *into++=*json++; /* All other characters. */ 762 } 763 *into=0; /* and null-terminate. */ 764 } 765