2 Copyright (c) 2009 Dave Gamble
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:
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
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
24 /* JSON parser in C. */
35 static const char *ep;
37 const char *cJSON_GetErrorPtr(void) {return ep;}
39 static int cJSON_strcasecmp(const char *s1,const char *s2)
41 if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
42 for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0;
43 return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
46 static void *(*cJSON_malloc)(size_t sz) = malloc;
47 static void (*cJSON_free)(void *ptr) = free;
49 static char* cJSON_strdup(const char* str)
54 len = strlen(str) + 1;
55 if (!(copy = (char*)cJSON_malloc(len))) return 0;
60 void cJSON_InitHooks(cJSON_Hooks* hooks)
62 if (!hooks) { /* Reset hooks */
63 cJSON_malloc = malloc;
68 cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
69 cJSON_free = (hooks->free_fn)?hooks->free_fn:free;
72 /* Internal constructor. */
73 static cJSON *cJSON_New_Item(void)
75 cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
76 if (node) memset(node,0,sizeof(cJSON));
80 /* Delete a cJSON structure. */
81 void cJSON_Delete(cJSON *c)
87 if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
88 if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
89 if (c->string) cJSON_free(c->string);
95 /* Parse the input text to generate a number, and populate the result into item. */
96 static const char *parse_number(cJSON *item,const char *num)
98 double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;
100 if (*num=='-') sign=-1,num++; /* Has sign? */
101 if (*num=='0') num++; /* is zero */
102 if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */
103 if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */
104 if (*num=='e' || *num=='E') /* Exponent? */
105 { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */
106 while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */
109 n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */
112 item->valueint=(int)n;
113 item->type=cJSON_Number;
117 /* Render the number nicely from the given item into a string. */
118 static char *print_number(cJSON *item)
121 double d=item->valuedouble;
122 if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
124 str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */
125 if (str) sprintf(str,"%d",item->valueint);
129 str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */
132 if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d);
133 else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d);
134 else sprintf(str,"%f",d);
140 static unsigned parse_hex4(const char *str)
143 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;
145 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;
147 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;
149 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;
153 /* Parse the input text into an unescaped cstring, and populate item. */
154 static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
155 static const char *parse_string(cJSON *item,const char *str)
157 const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;
158 if (*str!='\"') {ep=str;return 0;} /* not a string! */
160 while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */
162 out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */
166 while (*ptr!='\"' && *ptr)
168 if (*ptr!='\\') *ptr2++=*ptr++;
174 case 'b': *ptr2++='\b'; break;
175 case 'f': *ptr2++='\f'; break;
176 case 'n': *ptr2++='\n'; break;
177 case 'r': *ptr2++='\r'; break;
178 case 't': *ptr2++='\t'; break;
179 case 'u': /* transcode utf16 to utf8. */
180 uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */
182 if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */
184 if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */
186 if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */
187 uc2=parse_hex4(ptr+3);ptr+=6;
188 if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */
189 uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
192 len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
195 case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
196 case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
197 case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
198 case 1: *--ptr2 =(uc | firstByteMark[len]);
202 default: *ptr2++=*ptr; break;
208 if (*ptr=='\"') ptr++;
209 item->valuestring=out;
210 item->type=cJSON_String;
214 /* Render the cstring provided to an escaped version that can be printed. */
215 static char *print_string_ptr(const char *str)
217 const char *ptr;char *ptr2,*out;int len=0;unsigned char token;
219 if (!str) return cJSON_strdup("");
220 ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;}
222 out=(char*)cJSON_malloc(len+3);
229 if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
233 switch (token=*ptr++)
235 case '\\': *ptr2++='\\'; break;
236 case '\"': *ptr2++='\"'; break;
237 case '\b': *ptr2++='b'; break;
238 case '\f': *ptr2++='f'; break;
239 case '\n': *ptr2++='n'; break;
240 case '\r': *ptr2++='r'; break;
241 case '\t': *ptr2++='t'; break;
242 default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */
246 *ptr2++='\"';*ptr2++=0;
249 /* Invote print_string_ptr (which is useful) on an item. */
250 static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);}
252 /* Predeclare these prototypes. */
253 static const char *parse_value(cJSON *item,const char *value);
254 static char *print_value(cJSON *item,int depth,int fmt);
255 static const char *parse_array(cJSON *item,const char *value);
256 static char *print_array(cJSON *item,int depth,int fmt);
257 static const char *parse_object(cJSON *item,const char *value);
258 static char *print_object(cJSON *item,int depth,int fmt);
260 /* Utility to jump whitespace and cr/lf */
261 static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}
263 /* Parse an object - create a new root, and populate. */
264 cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
267 cJSON *c=cJSON_New_Item();
269 if (!c) return 0; /* memory fail */
271 end=parse_value(c,skip(value));
272 if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */
274 /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
275 if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}}
276 if (return_parse_end) *return_parse_end=end;
279 /* Default options for cJSON_Parse */
280 cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);}
282 /* Render a cJSON item/entity/structure to text. */
283 char *cJSON_Print(cJSON *item) {return print_value(item,0,1);}
284 char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);}
286 /* Parser core - when encountering text, process appropriately. */
287 static const char *parse_value(cJSON *item,const char *value)
289 if (!value) return 0; /* Fail on null. */
290 if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; }
291 if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; }
292 if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; }
293 if (*value=='\"') { return parse_string(item,value); }
294 if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); }
295 if (*value=='[') { return parse_array(item,value); }
296 if (*value=='{') { return parse_object(item,value); }
298 ep=value;return 0; /* failure. */
301 /* Render a value to text. */
302 static char *print_value(cJSON *item,int depth,int fmt)
306 switch ((item->type)&255)
308 case cJSON_NULL: out=cJSON_strdup("null"); break;
309 case cJSON_False: out=cJSON_strdup("false");break;
310 case cJSON_True: out=cJSON_strdup("true"); break;
311 case cJSON_Number: out=print_number(item);break;
312 case cJSON_String: out=print_string(item);break;
313 case cJSON_Array: out=print_array(item,depth,fmt);break;
314 case cJSON_Object: out=print_object(item,depth,fmt);break;
319 /* Build an array from input text. */
320 static const char *parse_array(cJSON *item,const char *value)
323 if (*value!='[') {ep=value;return 0;} /* not an array! */
325 item->type=cJSON_Array;
327 if (*value==']') return value+1; /* empty array. */
329 item->child=child=cJSON_New_Item();
330 if (!item->child) return 0; /* memory fail */
331 value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */
332 if (!value) return 0;
337 if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
338 child->next=new_item;new_item->prev=child;child=new_item;
339 value=skip(parse_value(child,skip(value+1)));
340 if (!value) return 0; /* memory fail */
343 if (*value==']') return value+1; /* end of array */
344 ep=value;return 0; /* malformed. */
347 /* Render an array to text */
348 static char *print_array(cJSON *item,int depth,int fmt)
351 char *out=0,*ptr,*ret;int len=5;
352 cJSON *child=item->child;
353 int numentries=0,i=0,fail=0;
355 /* How many entries in the array? */
356 while (child) numentries++,child=child->next;
357 /* Explicitly handle numentries==0 */
360 out=(char*)cJSON_malloc(3);
361 if (out) strcpy(out,"[]");
364 /* Allocate an array to hold the values for each */
365 entries=(char**)cJSON_malloc(numentries*sizeof(char*));
366 if (!entries) return 0;
367 memset(entries,0,numentries*sizeof(char*));
368 /* Retrieve all the results: */
370 while (child && !fail)
372 ret=print_value(child,depth+1,fmt);
374 if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
378 /* If we didn't fail, try to malloc the output string */
379 if (!fail) out=(char*)cJSON_malloc(len);
380 /* If that fails, we fail. */
383 /* Handle failure. */
386 for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
391 /* Compose the output array. */
394 for (i=0;i<numentries;i++)
396 strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
397 if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}
398 cJSON_free(entries[i]);
405 /* Build an object from the text. */
406 static const char *parse_object(cJSON *item,const char *value)
409 if (*value!='{') {ep=value;return 0;} /* not an object! */
411 item->type=cJSON_Object;
413 if (*value=='}') return value+1; /* empty array. */
415 item->child=child=cJSON_New_Item();
416 if (!item->child) return 0;
417 value=skip(parse_string(child,skip(value)));
418 if (!value) return 0;
419 child->string=child->valuestring;child->valuestring=0;
420 if (*value!=':') {ep=value;return 0;} /* fail! */
421 value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
422 if (!value) return 0;
427 if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
428 child->next=new_item;new_item->prev=child;child=new_item;
429 value=skip(parse_string(child,skip(value+1)));
430 if (!value) return 0;
431 child->string=child->valuestring;child->valuestring=0;
432 if (*value!=':') {ep=value;return 0;} /* fail! */
433 value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
434 if (!value) return 0;
437 if (*value=='}') return value+1; /* end of array */
438 ep=value;return 0; /* malformed. */
441 /* Render an object to text. */
442 static char *print_object(cJSON *item,int depth,int fmt)
444 char **entries=0,**names=0;
445 char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
446 cJSON *child=item->child;
447 int numentries=0,fail=0;
448 /* Count the number of entries. */
449 while (child) numentries++,child=child->next;
450 /* Explicitly handle empty object case */
453 out=(char*)cJSON_malloc(fmt?depth+4:3);
456 if (fmt) {*ptr++='\n';for (i=0;i<depth-1;i++) *ptr++='\t';}
460 /* Allocate space for the names and the objects */
461 entries=(char**)cJSON_malloc(numentries*sizeof(char*));
462 if (!entries) return 0;
463 names=(char**)cJSON_malloc(numentries*sizeof(char*));
464 if (!names) {cJSON_free(entries);return 0;}
465 memset(entries,0,sizeof(char*)*numentries);
466 memset(names,0,sizeof(char*)*numentries);
468 /* Collect all the results into our arrays: */
469 child=item->child;depth++;if (fmt) len+=depth;
472 names[i]=str=print_string_ptr(child->string);
473 entries[i++]=ret=print_value(child,depth,fmt);
474 if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
478 /* Try to allocate the output string */
479 if (!fail) out=(char*)cJSON_malloc(len);
485 for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}
486 cJSON_free(names);cJSON_free(entries);
490 /* Compose the output: */
491 *out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
492 for (i=0;i<numentries;i++)
494 if (fmt) for (j=0;j<depth;j++) *ptr++='\t';
495 strcpy(ptr,names[i]);ptr+=strlen(names[i]);
496 *ptr++=':';if (fmt) *ptr++='\t';
497 strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
498 if (i!=numentries-1) *ptr++=',';
499 if (fmt) *ptr++='\n';*ptr=0;
500 cJSON_free(names[i]);cJSON_free(entries[i]);
503 cJSON_free(names);cJSON_free(entries);
504 if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
509 /* Get Array size/item / object item. */
510 int cJSON_GetArraySize(cJSON *array) {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
511 cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;}
512 cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
514 /* Utility for array list handling. */
515 static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
516 /* Utility for handling references. */
517 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;}
519 /* Add item to array/object. */
520 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);}}
521 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);}
522 void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));}
523 void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));}
525 cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0;
526 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;}
527 void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
528 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;}
529 void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
531 /* Replace array/object items with new ones. */
532 void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return;
533 newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem;
534 if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);}
535 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);}}
537 /* Create basic types: */
538 cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
539 cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
540 cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
541 cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
542 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;}
543 cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;}
544 cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
545 cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}
548 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(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
549 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(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
550 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(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
551 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(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
554 cJSON *cJSON_Duplicate(cJSON *item,int recurse)
556 cJSON *newitem,*cptr,*nptr=0,*newchild;
557 /* Bail on bad ptr */
559 /* Create new item */
560 newitem=cJSON_New_Item();
561 if (!newitem) return 0;
562 /* Copy over all vars */
563 newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble;
564 if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}}
565 if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}}
566 /* If non-recursive, then we're done! */
567 if (!recurse) return newitem;
568 /* Walk the ->next chain for the child. */
572 newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */
573 if (!newchild) {cJSON_Delete(newitem);return 0;}
574 if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */
575 else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */
581 void cJSON_Minify(char *json)
586 if (*json==' ') json++;
587 else if (*json=='\t') json++; // Whitespace characters.
588 else if (*json=='\r') json++;
589 else if (*json=='\n') json++;
590 else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; // double-slash comments, to end of line.
591 else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} // multiline comments.
592 else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} // string literals, which are \" sensitive.
593 else *into++=*json++; // All other characters.
595 *into=0; // and null-terminate.