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 static const char *ep;
36
cJSON_GetErrorPtr(void)37 const char *cJSON_GetErrorPtr(void) {return ep;}
38
cJSON_strcasecmp(const char * s1,const char * s2)39 static int cJSON_strcasecmp(const char *s1,const char *s2)
40 {
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);
44 }
45
46 static void *(*cJSON_malloc)(size_t sz) = malloc;
47 static void (*cJSON_free)(void *ptr) = free;
48
cJSON_strdup(const char * str)49 static char* cJSON_strdup(const char* str)
50 {
51 size_t len;
52 char* copy;
53
54 len = strlen(str) + 1;
55 if (!(copy = (char*)cJSON_malloc(len))) return 0;
56 memcpy(copy,str,len);
57 return copy;
58 }
59
cJSON_InitHooks(cJSON_Hooks * hooks)60 void cJSON_InitHooks(cJSON_Hooks* hooks)
61 {
62 if (!hooks) { /* Reset hooks */
63 cJSON_malloc = malloc;
64 cJSON_free = free;
65 return;
66 }
67
68 cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
69 cJSON_free = (hooks->free_fn)?hooks->free_fn:free;
70 }
71
72 /* Internal constructor. */
cJSON_New_Item(void)73 static cJSON *cJSON_New_Item(void)
74 {
75 cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
76 if (node) memset(node,0,sizeof(cJSON));
77 return node;
78 }
79
80 /* Delete a cJSON structure. */
cJSON_Delete(cJSON * c)81 void cJSON_Delete(cJSON *c)
82 {
83 cJSON *next;
84 while (c)
85 {
86 next=c->next;
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);
90 cJSON_free(c);
91 c=next;
92 }
93 }
94
95 /* Parse the input text to generate a number, and populate the result into item. */
parse_number(cJSON * item,const char * num)96 static const char *parse_number(cJSON *item,const char *num)
97 {
98 double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;
99
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? */
107 }
108
109 n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */
110
111 item->valuedouble=n;
112 item->valueint=(int)n;
113 item->type=cJSON_Number;
114 return num;
115 }
116
117 /* Render the number nicely from the given item into a string. */
print_number(cJSON * item)118 static char *print_number(cJSON *item)
119 {
120 char *str;
121 double d=item->valuedouble;
122 if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
123 {
124 str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */
125 if (str) sprintf(str,"%d",item->valueint);
126 }
127 else
128 {
129 str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */
130 if (str)
131 {
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);
135 }
136 }
137 return str;
138 }
139
parse_hex4(const char * str)140 static unsigned parse_hex4(const char *str)
141 {
142 unsigned h=0;
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;
144 h=h<<4;str++;
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;
146 h=h<<4;str++;
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;
148 h=h<<4;str++;
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;
150 return h;
151 }
152
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 };
parse_string(cJSON * item,const char * str)155 static const char *parse_string(cJSON *item,const char *str)
156 {
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! */
159
160 while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */
161
162 out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */
163 if (!out) return 0;
164
165 ptr=str+1;ptr2=out;
166 while (*ptr!='\"' && *ptr)
167 {
168 if (*ptr!='\\') *ptr2++=*ptr++;
169 else
170 {
171 ptr++;
172 switch (*ptr)
173 {
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. */
181
182 if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */
183
184 if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */
185 {
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));
190 }
191
192 len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
193
194 switch (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]);
199 }
200 ptr2+=len;
201 break;
202 default: *ptr2++=*ptr; break;
203 }
204 ptr++;
205 }
206 }
207 *ptr2=0;
208 if (*ptr=='\"') ptr++;
209 item->valuestring=out;
210 item->type=cJSON_String;
211 return ptr;
212 }
213
214 /* Render the cstring provided to an escaped version that can be printed. */
print_string_ptr(const char * str)215 static char *print_string_ptr(const char *str)
216 {
217 const char *ptr;char *ptr2,*out;int len=0;unsigned char token;
218
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++;}
221
222 out=(char*)cJSON_malloc(len+3);
223 if (!out) return 0;
224
225 ptr2=out;ptr=str;
226 *ptr2++='\"';
227 while (*ptr)
228 {
229 if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
230 else
231 {
232 *ptr2++='\\';
233 switch (token=*ptr++)
234 {
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 */
243 }
244 }
245 }
246 *ptr2++='\"';*ptr2++=0;
247 return out;
248 }
249 /* Invote print_string_ptr (which is useful) on an item. */
print_string(cJSON * item)250 static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);}
251
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);
259
260 /* Utility to jump whitespace and cr/lf */
skip(const char * in)261 static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}
262
263 /* Parse an object - create a new root, and populate. */
cJSON_ParseWithOpts(const char * value,const char ** return_parse_end,int require_null_terminated)264 cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
265 {
266 const char *end=0;
267 cJSON *c=cJSON_New_Item();
268 ep=0;
269 if (!c) return 0; /* memory fail */
270
271 end=parse_value(c,skip(value));
272 if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */
273
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;
277 return c;
278 }
279 /* Default options for cJSON_Parse */
cJSON_Parse(const char * value)280 cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);}
281
282 /* Render a cJSON item/entity/structure to text. */
cJSON_Print(cJSON * item)283 char *cJSON_Print(cJSON *item) {return print_value(item,0,1);}
cJSON_PrintUnformatted(cJSON * item)284 char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);}
285
286 /* Parser core - when encountering text, process appropriately. */
parse_value(cJSON * item,const char * value)287 static const char *parse_value(cJSON *item,const char *value)
288 {
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); }
297
298 ep=value;return 0; /* failure. */
299 }
300
301 /* Render a value to text. */
print_value(cJSON * item,int depth,int fmt)302 static char *print_value(cJSON *item,int depth,int fmt)
303 {
304 char *out=0;
305 if (!item) return 0;
306 switch ((item->type)&255)
307 {
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;
315 }
316 return out;
317 }
318
319 /* Build an array from input text. */
parse_array(cJSON * item,const char * value)320 static const char *parse_array(cJSON *item,const char *value)
321 {
322 cJSON *child;
323 if (*value!='[') {ep=value;return 0;} /* not an array! */
324
325 item->type=cJSON_Array;
326 value=skip(value+1);
327 if (*value==']') return value+1; /* empty array. */
328
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;
333
334 while (*value==',')
335 {
336 cJSON *new_item;
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 */
341 }
342
343 if (*value==']') return value+1; /* end of array */
344 ep=value;return 0; /* malformed. */
345 }
346
347 /* Render an array to text */
print_array(cJSON * item,int depth,int fmt)348 static char *print_array(cJSON *item,int depth,int fmt)
349 {
350 char **entries;
351 char *out=0,*ptr,*ret;int len=5;
352 cJSON *child=item->child;
353 int numentries=0,i=0,fail=0;
354
355 /* How many entries in the array? */
356 while (child) numentries++,child=child->next;
357 /* Explicitly handle numentries==0 */
358 if (!numentries)
359 {
360 out=(char*)cJSON_malloc(3);
361 if (out) strcpy(out,"[]");
362 return out;
363 }
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: */
369 child=item->child;
370 while (child && !fail)
371 {
372 ret=print_value(child,depth+1,fmt);
373 entries[i++]=ret;
374 if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
375 child=child->next;
376 }
377
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. */
381 if (!out) fail=1;
382
383 /* Handle failure. */
384 if (fail)
385 {
386 for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
387 cJSON_free(entries);
388 return 0;
389 }
390
391 /* Compose the output array. */
392 *out='[';
393 ptr=out+1;*ptr=0;
394 for (i=0;i<numentries;i++)
395 {
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]);
399 }
400 cJSON_free(entries);
401 *ptr++=']';*ptr++=0;
402 return out;
403 }
404
405 /* Build an object from the text. */
parse_object(cJSON * item,const char * value)406 static const char *parse_object(cJSON *item,const char *value)
407 {
408 cJSON *child;
409 if (*value!='{') {ep=value;return 0;} /* not an object! */
410
411 item->type=cJSON_Object;
412 value=skip(value+1);
413 if (*value=='}') return value+1; /* empty array. */
414
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;
423
424 while (*value==',')
425 {
426 cJSON *new_item;
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;
435 }
436
437 if (*value=='}') return value+1; /* end of array */
438 ep=value;return 0; /* malformed. */
439 }
440
441 /* Render an object to text. */
print_object(cJSON * item,int depth,int fmt)442 static char *print_object(cJSON *item,int depth,int fmt)
443 {
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 */
451 if (!numentries)
452 {
453 out=(char*)cJSON_malloc(fmt?depth+4:3);
454 if (!out) return 0;
455 ptr=out;*ptr++='{';
456 if (fmt) {*ptr++='\n';for (i=0;i<depth-1;i++) *ptr++='\t';}
457 *ptr++='}';*ptr++=0;
458 return out;
459 }
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);
467
468 /* Collect all the results into our arrays: */
469 child=item->child;depth++;if (fmt) len+=depth;
470 while (child)
471 {
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;
475 child=child->next;
476 }
477
478 /* Try to allocate the output string */
479 if (!fail) out=(char*)cJSON_malloc(len);
480 if (!out) fail=1;
481
482 /* Handle failure */
483 if (fail)
484 {
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);
487 return 0;
488 }
489
490 /* Compose the output: */
491 *out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
492 for (i=0;i<numentries;i++)
493 {
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]);
501 }
502
503 cJSON_free(names);cJSON_free(entries);
504 if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
505 *ptr++='}';*ptr++=0;
506 return out;
507 }
508
509 /* Get Array size/item / object item. */
cJSON_GetArraySize(cJSON * array)510 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)511 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)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;}
513
514 /* Utility for array list handling. */
suffix_object(cJSON * prev,cJSON * item)515 static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
516 /* Utility for handling references. */
create_reference(cJSON * item)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;}
518
519 /* Add item to array/object. */
cJSON_AddItemToArray(cJSON * array,cJSON * item)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);}}
cJSON_AddItemToObject(cJSON * object,const char * string,cJSON * 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);}
cJSON_AddItemReferenceToArray(cJSON * array,cJSON * item)522 void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));}
cJSON_AddItemReferenceToObject(cJSON * object,const char * string,cJSON * item)523 void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));}
524
cJSON_DetachItemFromArray(cJSON * array,int which)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;}
cJSON_DeleteItemFromArray(cJSON * array,int which)527 void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
cJSON_DetachItemFromObject(cJSON * object,const char * string)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;}
cJSON_DeleteItemFromObject(cJSON * object,const char * string)529 void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
530
531 /* Replace array/object items with new ones. */
cJSON_ReplaceItemInArray(cJSON * array,int which,cJSON * newitem)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);}
cJSON_ReplaceItemInObject(cJSON * object,const char * string,cJSON * newitem)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);}}
536
537 /* Create basic types: */
cJSON_CreateNull(void)538 cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
cJSON_CreateTrue(void)539 cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
cJSON_CreateFalse(void)540 cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
cJSON_CreateBool(int b)541 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)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;}
cJSON_CreateString(const char * string)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;}
cJSON_CreateArray(void)544 cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
cJSON_CreateObject(void)545 cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}
546
547 /* Create Arrays: */
cJSON_CreateIntArray(const int * numbers,int count)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;}
cJSON_CreateFloatArray(const float * numbers,int count)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;}
cJSON_CreateDoubleArray(const double * numbers,int count)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;}
cJSON_CreateStringArray(const char ** strings,int count)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;}
552
553 /* Duplication */
cJSON_Duplicate(cJSON * item,int recurse)554 cJSON *cJSON_Duplicate(cJSON *item,int recurse)
555 {
556 cJSON *newitem,*cptr,*nptr=0,*newchild;
557 /* Bail on bad ptr */
558 if (!item) return 0;
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. */
569 cptr=item->child;
570 while (cptr)
571 {
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 */
576 cptr=cptr->next;
577 }
578 return newitem;
579 }
580
cJSON_Minify(char * json)581 void cJSON_Minify(char *json)
582 {
583 char *into=json;
584 while (*json)
585 {
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.
594 }
595 *into=0; // and null-terminate.
596 }