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.
b'\\ No newline at end of file'