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 #include "cJSON.h"
34
35
36 #if defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__)
37 // Work arround to fix build issues that may occur with Mingw:
38 // error: 'DBL_EPSILON' was not declared in this scope
39 // error: 'FLT_EPSILON' was not declared in this scope
40
41 # ifndef LDBL_EPSILON
42 # define LDBL_EPSILON __LDBL_EPSILON__
43 # endif
44 # ifndef DBL_EPSILON
45 # define DBL_EPSILON __DBL_EPSILON__
46 # endif
47 # ifndef FLT_EPSILON
48 # define FLT_EPSILON __FLT_EPSILON__
49 # endif
50 #endif
51
52
53 static const char *ep;
54
cJSON_GetErrorPtr(void)55 const char *cJSON_GetErrorPtr(void) {return ep;}
56
cJSON_strcasecmp(const char * s1,const char * s2)57 static int cJSON_strcasecmp(const char *s1,const char *s2)
58 {
59 if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
60 for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0;
61 return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
62 }
63
64 static void *(*cJSON_malloc)(size_t sz) = malloc;
65 static void (*cJSON_free)(void *ptr) = free;
66
cJSON_strdup(const char * str)67 static char* cJSON_strdup(const char* str)
68 {
69 size_t len;
70 char* copy;
71
72 len = strlen(str) + 1;
73 if (!(copy = (char*)cJSON_malloc(len))) return 0;
74 memcpy(copy,str,len);
75 return copy;
76 }
77
cJSON_InitHooks(cJSON_Hooks * hooks)78 void cJSON_InitHooks(cJSON_Hooks* hooks)
79 {
80 if (!hooks) { /* Reset hooks */
81 cJSON_malloc = malloc;
82 cJSON_free = free;
83 return;
84 }
85
86 cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
87 cJSON_free = (hooks->free_fn)?hooks->free_fn:free;
88 }
89
90 /* Internal constructor. */
cJSON_New_Item(void)91 static cJSON *cJSON_New_Item(void)
92 {
93 cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
94 if (node) memset(node,0,sizeof(cJSON));
95 return node;
96 }
97
98 /* Delete a cJSON structure. */
cJSON_Delete(cJSON * c)99 void cJSON_Delete(cJSON *c)
100 {
101 cJSON *next;
102 while (c)
103 {
104 next=c->next;
105 if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
106 if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
107 if (c->string) cJSON_free(c->string);
108 cJSON_free(c);
109 c=next;
110 }
111 }
112
113 /* Parse the input text to generate a number, and populate the result into item. */
parse_number(cJSON * item,const char * num)114 static const char *parse_number(cJSON *item,const char *num)
115 {
116 double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;
117
118 if (*num=='-') sign=-1,num++; /* Has sign? */
119 if (*num=='0') num++; /* is zero */
120 if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */
121 if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */
122 if (*num=='e' || *num=='E') /* Exponent? */
123 { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */
124 while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */
125 }
126
127 n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */
128
129 item->valuedouble=n;
130 item->valueint=(int)n;
131 item->type=cJSON_Number;
132 return num;
133 }
134
135 /* Render the number nicely from the given item into a string. */
print_number(cJSON * item)136 static char *print_number(cJSON *item)
137 {
138 char *str;
139 double d=item->valuedouble;
140 if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
141 {
142 str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */
143 if (str) sprintf(str,"%d",item->valueint);
144 }
145 else
146 {
147 str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */
148 if (str)
149 {
150 if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d);
151 else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d);
152 else sprintf(str,"%f",d);
153 }
154 }
155 return str;
156 }
157
parse_hex4(const char * str)158 static unsigned parse_hex4(const char *str)
159 {
160 unsigned h=0;
161 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;
162 h=h<<4;str++;
163 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;
164 h=h<<4;str++;
165 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;
166 h=h<<4;str++;
167 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;
168 return h;
169 }
170
171 /* Parse the input text into an unescaped cstring, and populate item. */
172 static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
parse_string(cJSON * item,const char * str)173 static const char *parse_string(cJSON *item,const char *str)
174 {
175 const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;
176 if (*str!='\"') {ep=str;return 0;} /* not a string! */
177
178 while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */
179
180 out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */
181 if (!out) return 0;
182
183 ptr=str+1;ptr2=out;
184 while (*ptr!='\"' && *ptr)
185 {
186 if (*ptr!='\\') *ptr2++=*ptr++;
187 else
188 {
189 ptr++;
190 switch (*ptr)
191 {
192 case 'b': *ptr2++='\b'; break;
193 case 'f': *ptr2++='\f'; break;
194 case 'n': *ptr2++='\n'; break;
195 case 'r': *ptr2++='\r'; break;
196 case 't': *ptr2++='\t'; break;
197 case 'u': /* transcode utf16 to utf8. */
198 uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */
199
200 if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */
201
202 if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */
203 {
204 if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */
205 uc2=parse_hex4(ptr+3);ptr+=6;
206 if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */
207 uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
208 }
209
210 len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
211
212 switch (len) {
213 case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
214 case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
215 case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
216 case 1: *--ptr2 =(uc | firstByteMark[len]);
217 }
218 ptr2+=len;
219 break;
220 default: *ptr2++=*ptr; break;
221 }
222 ptr++;
223 }
224 }
225 *ptr2=0;
226 if (*ptr=='\"') ptr++;
227 item->valuestring=out;
228 item->type=cJSON_String;
229 return ptr;
230 }
231
232 /* Render the cstring provided to an escaped version that can be printed. */
print_string_ptr(const char * str)233 static char *print_string_ptr(const char *str)
234 {
235 const char *ptr;char *ptr2,*out;int len=0;unsigned char token;
236
237 if (!str) return cJSON_strdup("");
238 ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;}
239
240 out=(char*)cJSON_malloc(len+3);
241 if (!out) return 0;
242
243 ptr2=out;ptr=str;
244 *ptr2++='\"';
245 while (*ptr)
246 {
247 if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
248 else
249 {
250 *ptr2++='\\';
251 switch (token=*ptr++)
252 {
253 case '\\': *ptr2++='\\'; break;
254 case '\"': *ptr2++='\"'; break;
255 case '\b': *ptr2++='b'; break;
256 case '\f': *ptr2++='f'; break;
257 case '\n': *ptr2++='n'; break;
258 case '\r': *ptr2++='r'; break;
259 case '\t': *ptr2++='t'; break;
260 default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */
261 }
262 }
263 }
264 *ptr2++='\"';*ptr2++=0;
265 return out;
266 }
267 /* Invote print_string_ptr (which is useful) on an item. */
print_string(cJSON * item)268 static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);}
269
270 /* Predeclare these prototypes. */
271 static const char *parse_value(cJSON *item,const char *value);
272 static char *print_value(cJSON *item,int depth,int fmt);
273 static const char *parse_array(cJSON *item,const char *value);
274 static char *print_array(cJSON *item,int depth,int fmt);
275 static const char *parse_object(cJSON *item,const char *value);
276 static char *print_object(cJSON *item,int depth,int fmt);
277
278 /* Utility to jump whitespace and cr/lf */
skip(const char * in)279 static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}
280
281 /* Parse an object - create a new root, and populate. */
cJSON_ParseWithOpts(const char * value,const char ** return_parse_end,int require_null_terminated)282 cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
283 {
284 const char *end=0;
285 cJSON *c=cJSON_New_Item();
286 ep=0;
287 if (!c) return 0; /* memory fail */
288
289 end=parse_value(c,skip(value));
290 if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */
291
292 /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
293 if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}}
294 if (return_parse_end) *return_parse_end=end;
295 return c;
296 }
297 /* Default options for cJSON_Parse */
cJSON_Parse(const char * value)298 cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);}
299
300 /* Render a cJSON item/entity/structure to text. */
cJSON_Print(cJSON * item)301 char *cJSON_Print(cJSON *item) {return print_value(item,0,1);}
cJSON_PrintUnformatted(cJSON * item)302 char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);}
303
304 /* Parser core - when encountering text, process appropriately. */
parse_value(cJSON * item,const char * value)305 static const char *parse_value(cJSON *item,const char *value)
306 {
307 if (!value) return 0; /* Fail on null. */
308 if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; }
309 if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; }
310 if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; }
311 if (*value=='\"') { return parse_string(item,value); }
312 if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); }
313 if (*value=='[') { return parse_array(item,value); }
314 if (*value=='{') { return parse_object(item,value); }
315
316 ep=value;return 0; /* failure. */
317 }
318
319 /* Render a value to text. */
print_value(cJSON * item,int depth,int fmt)320 static char *print_value(cJSON *item,int depth,int fmt)
321 {
322 char *out=0;
323 if (!item) return 0;
324 switch ((item->type)&255)
325 {
326 case cJSON_NULL: out=cJSON_strdup("null"); break;
327 case cJSON_False: out=cJSON_strdup("false");break;
328 case cJSON_True: out=cJSON_strdup("true"); break;
329 case cJSON_Number: out=print_number(item);break;
330 case cJSON_String: out=print_string(item);break;
331 case cJSON_Array: out=print_array(item,depth,fmt);break;
332 case cJSON_Object: out=print_object(item,depth,fmt);break;
333 }
334 return out;
335 }
336
337 /* Build an array from input text. */
parse_array(cJSON * item,const char * value)338 static const char *parse_array(cJSON *item,const char *value)
339 {
340 cJSON *child;
341 if (*value!='[') {ep=value;return 0;} /* not an array! */
342
343 item->type=cJSON_Array;
344 value=skip(value+1);
345 if (*value==']') return value+1; /* empty array. */
346
347 item->child=child=cJSON_New_Item();
348 if (!item->child) return 0; /* memory fail */
349 value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */
350 if (!value) return 0;
351
352 while (*value==',')
353 {
354 cJSON *new_item;
355 if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
356 child->next=new_item;new_item->prev=child;child=new_item;
357 value=skip(parse_value(child,skip(value+1)));
358 if (!value) return 0; /* memory fail */
359 }
360
361 if (*value==']') return value+1; /* end of array */
362 ep=value;return 0; /* malformed. */
363 }
364
365 /* Render an array to text */
print_array(cJSON * item,int depth,int fmt)366 static char *print_array(cJSON *item,int depth,int fmt)
367 {
368 char **entries;
369 char *out=0,*ptr,*ret;int len=5;
370 cJSON *child=item->child;
371 int numentries=0,i=0,fail=0;
372
373 /* How many entries in the array? */
374 while (child) numentries++,child=child->next;
375 /* Explicitly handle numentries==0 */
376 if (!numentries)
377 {
378 out=(char*)cJSON_malloc(3);
379 if (out) strcpy(out,"[]");
380 return out;
381 }
382 /* Allocate an array to hold the values for each */
383 entries=(char**)cJSON_malloc(numentries*sizeof(char*));
384 if (!entries) return 0;
385 memset(entries,0,numentries*sizeof(char*));
386 /* Retrieve all the results: */
387 child=item->child;
388 while (child && !fail)
389 {
390 ret=print_value(child,depth+1,fmt);
391 entries[i++]=ret;
392 if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
393 child=child->next;
394 }
395
396 /* If we didn't fail, try to malloc the output string */
397 if (!fail) out=(char*)cJSON_malloc(len);
398 /* If that fails, we fail. */
399 if (!out) fail=1;
400
401 /* Handle failure. */
402 if (fail)
403 {
404 for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
405 cJSON_free(entries);
406 return 0;
407 }
408
409 /* Compose the output array. */
410 *out='[';
411 ptr=out+1;*ptr=0;
412 for (i=0;i<numentries;i++)
413 {
414 strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
415 if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}
416 cJSON_free(entries[i]);
417 }
418 cJSON_free(entries);
419 *ptr++=']';*ptr++=0;
420 return out;
421 }
422
423 /* Build an object from the text. */
parse_object(cJSON * item,const char * value)424 static const char *parse_object(cJSON *item,const char *value)
425 {
426 cJSON *child;
427 if (*value!='{') {ep=value;return 0;} /* not an object! */
428
429 item->type=cJSON_Object;
430 value=skip(value+1);
431 if (*value=='}') return value+1; /* empty array. */
432
433 item->child=child=cJSON_New_Item();
434 if (!item->child) return 0;
435 value=skip(parse_string(child,skip(value)));
436 if (!value) return 0;
437 child->string=child->valuestring;child->valuestring=0;
438 if (*value!=':') {ep=value;return 0;} /* fail! */
439 value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
440 if (!value) return 0;
441
442 while (*value==',')
443 {
444 cJSON *new_item;
445 if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
446 child->next=new_item;new_item->prev=child;child=new_item;
447 value=skip(parse_string(child,skip(value+1)));
448 if (!value) return 0;
449 child->string=child->valuestring;child->valuestring=0;
450 if (*value!=':') {ep=value;return 0;} /* fail! */
451 value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
452 if (!value) return 0;
453 }
454
455 if (*value=='}') return value+1; /* end of array */
456 ep=value;return 0; /* malformed. */
457 }
458
459 /* Render an object to text. */
print_object(cJSON * item,int depth,int fmt)460 static char *print_object(cJSON *item,int depth,int fmt)
461 {
462 char **entries=0,**names=0;
463 char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
464 cJSON *child=item->child;
465 int numentries=0,fail=0;
466 /* Count the number of entries. */
467 while (child) numentries++,child=child->next;
468 /* Explicitly handle empty object case */
469 if (!numentries)
470 {
471 out=(char*)cJSON_malloc(fmt?depth+4:3);
472 if (!out) return 0;
473 ptr=out;*ptr++='{';
474 if (fmt) {*ptr++='\n';for (i=0;i<depth-1;i++) *ptr++='\t';}
475 *ptr++='}';*ptr++=0;
476 return out;
477 }
478 /* Allocate space for the names and the objects */
479 entries=(char**)cJSON_malloc(numentries*sizeof(char*));
480 if (!entries) return 0;
481 names=(char**)cJSON_malloc(numentries*sizeof(char*));
482 if (!names) {cJSON_free(entries);return 0;}
483 memset(entries,0,sizeof(char*)*numentries);
484 memset(names,0,sizeof(char*)*numentries);
485
486 /* Collect all the results into our arrays: */
487 child=item->child;depth++;if (fmt) len+=depth;
488 while (child)
489 {
490 names[i]=str=print_string_ptr(child->string);
491 entries[i++]=ret=print_value(child,depth,fmt);
492 if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
493 child=child->next;
494 }
495
496 /* Try to allocate the output string */
497 if (!fail) out=(char*)cJSON_malloc(len);
498 if (!out) fail=1;
499
500 /* Handle failure */
501 if (fail)
502 {
503 for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}
504 cJSON_free(names);cJSON_free(entries);
505 return 0;
506 }
507
508 /* Compose the output: */
509 *out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
510 for (i=0;i<numentries;i++)
511 {
512 if (fmt) for (j=0;j<depth;j++) *ptr++='\t';
513 strcpy(ptr,names[i]);ptr+=strlen(names[i]);
514 *ptr++=':';if (fmt) *ptr++='\t';
515 strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
516 if (i!=numentries-1) *ptr++=',';
517 if (fmt) *ptr++='\n';*ptr=0;
518 cJSON_free(names[i]);cJSON_free(entries[i]);
519 }
520
521 cJSON_free(names);cJSON_free(entries);
522 if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
523 *ptr++='}';*ptr++=0;
524 return out;
525 }
526
527 /* Get Array size/item / object item. */
cJSON_GetArraySize(cJSON * array)528 int cJSON_GetArraySize(cJSON *array) {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
cJSON_GetArrayItem(cJSON * array,int item)529 cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;}
cJSON_GetObjectItem(cJSON * object,const char * string)530 cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
531
532 /* Utility for array list handling. */
suffix_object(cJSON * prev,cJSON * item)533 static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
534 /* Utility for handling references. */
create_reference(cJSON * item)535 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;}
536
537 /* Add item to array/object. */
cJSON_AddItemToArray(cJSON * array,cJSON * item)538 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);}}
cJSON_AddItemToObject(cJSON * object,const char * string,cJSON * item)539 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);}
cJSON_AddItemReferenceToArray(cJSON * array,cJSON * item)540 void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));}
cJSON_AddItemReferenceToObject(cJSON * object,const char * string,cJSON * item)541 void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));}
542
cJSON_DetachItemFromArray(cJSON * array,int which)543 cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0;
544 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;}
cJSON_DeleteItemFromArray(cJSON * array,int which)545 void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
cJSON_DetachItemFromObject(cJSON * object,const char * string)546 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;}
cJSON_DeleteItemFromObject(cJSON * object,const char * string)547 void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
548
549 /* Replace array/object items with new ones. */
cJSON_ReplaceItemInArray(cJSON * array,int which,cJSON * newitem)550 void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return;
551 newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem;
552 if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);}
cJSON_ReplaceItemInObject(cJSON * object,const char * string,cJSON * newitem)553 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);}}
554
555 /* Create basic types: */
cJSON_CreateNull(void)556 cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
cJSON_CreateTrue(void)557 cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
cJSON_CreateFalse(void)558 cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
cJSON_CreateBool(int b)559 cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
cJSON_CreateNumber(double num)560 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;}
cJSON_CreateString(const char * string)561 cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;}
cJSON_CreateArray(void)562 cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
cJSON_CreateObject(void)563 cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}
564
565 /* Create Arrays: */
cJSON_CreateIntArray(const int * numbers,int count)566 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;}
cJSON_CreateFloatArray(const float * numbers,int count)567 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;}
cJSON_CreateDoubleArray(const double * numbers,int count)568 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;}
cJSON_CreateStringArray(const char ** strings,int count)569 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;}
570
571 /* Duplication */
cJSON_Duplicate(cJSON * item,int recurse)572 cJSON *cJSON_Duplicate(cJSON *item,int recurse)
573 {
574 cJSON *newitem,*cptr,*nptr=0,*newchild;
575 /* Bail on bad ptr */
576 if (!item) return 0;
577 /* Create new item */
578 newitem=cJSON_New_Item();
579 if (!newitem) return 0;
580 /* Copy over all vars */
581 newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble;
582 if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}}
583 if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}}
584 /* If non-recursive, then we're done! */
585 if (!recurse) return newitem;
586 /* Walk the ->next chain for the child. */
587 cptr=item->child;
588 while (cptr)
589 {
590 newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */
591 if (!newchild) {cJSON_Delete(newitem);return 0;}
592 if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */
593 else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */
594 cptr=cptr->next;
595 }
596 return newitem;
597 }
598
cJSON_Minify(char * json)599 void cJSON_Minify(char *json)
600 {
601 char *into=json;
602 while (*json)
603 {
604 if (*json==' ') json++;
605 else if (*json=='\t') json++; // Whitespace characters.
606 else if (*json=='\r') json++;
607 else if (*json=='\n') json++;
608 else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; // double-slash comments, to end of line.
609 else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} // multiline comments.
610 else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} // string literals, which are \" sensitive.
611 else *into++=*json++; // All other characters.
612 }
613 *into=0; // and null-terminate.
614 }
615