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