cJSON.c 18.6 KB
Newer Older
D
Dave Gamble 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
  Copyright (c) 2009 Dave Gamble

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
*/

23 24
/* cJSON */
/* JSON parser in C. */
D
Dave Gamble 已提交
25 26 27 28 29 30

#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <float.h>
31
#include <limits.h>
D
Dave Gamble 已提交
32
#include <ctype.h>
D
Dave Gamble 已提交
33 34
#include "cJSON.h"

35 36 37 38
static const char *ep;

const char *cJSON_GetErrorPtr() {return ep;}

39 40
static int cJSON_strcasecmp(const char *s1,const char *s2)
{
41
	if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
42 43 44
	for(; tolower(*s1) == tolower(*s2); ++s1, ++s2)	if(*s1 == 0)	return 0;
	return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
}
45

46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
static void *(*cJSON_malloc)(size_t sz) = malloc;
static void (*cJSON_free)(void *ptr) = free;

static char* cJSON_strdup(const char* str)
{
      size_t len;
      char* copy;

      len = strlen(str) + 1;
      if (!(copy = (char*)cJSON_malloc(len))) return 0;
      memcpy(copy,str,len);
      return copy;
}

void cJSON_InitHooks(cJSON_Hooks* hooks)
{
    if (!hooks) { /* Reset hooks */
        cJSON_malloc = malloc;
        cJSON_free = free;
        return;
    }

	cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
	cJSON_free	 = (hooks->free_fn)?hooks->free_fn:free;
}

72
/* Internal constructor. */
73 74 75 76 77 78
static cJSON *cJSON_New_Item()
{
	cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
	if (node) memset(node,0,sizeof(cJSON));
	return node;
}
D
Dave Gamble 已提交
79

80
/* Delete a cJSON structure. */
D
Dave Gamble 已提交
81 82 83 84 85 86
void cJSON_Delete(cJSON *c)
{
	cJSON *next;
	while (c)
	{
		next=c->next;
D
Dave Gamble 已提交
87 88
		if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
		if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
89 90
		if (c->string) cJSON_free(c->string);
		cJSON_free(c);
D
Dave Gamble 已提交
91 92 93 94
		c=next;
	}
}

95
/* Parse the input text to generate a number, and populate the result into item. */
D
Dave Gamble 已提交
96 97 98 99
static const char *parse_number(cJSON *item,const char *num)
{
	double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;

100 101 102 103 104 105 106 107
	/* Could use sscanf for this? */
	if (*num=='-') sign=-1,num++;	/* Has sign? */
	if (*num=='0') num++;			/* is zero */
	if (*num>='1' && *num<='9')	do	n=(n*10.0)+(*num++ -'0');	while (*num>='0' && *num<='9');	/* Number? */
	if (*num=='.') {num++;		do	n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');}	/* Fractional part? */
	if (*num=='e' || *num=='E')		/* Exponent? */
	{	num++;if (*num=='+') num++;	else if (*num=='-') signsubscale=-1,num++;		/* With sign? */
		while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0');	/* Number? */
D
Dave Gamble 已提交
108 109
	}

110
	n=sign*n*pow(10.0,(scale+subscale*signsubscale));	/* number = +/- number.fraction * 10^+/- exponent */
D
Dave Gamble 已提交
111 112 113 114 115 116 117
	
	item->valuedouble=n;
	item->valueint=(int)n;
	item->type=cJSON_Number;
	return num;
}

118
/* Render the number nicely from the given item into a string. */
D
Dave Gamble 已提交
119 120 121 122
static char *print_number(cJSON *item)
{
	char *str;
	double d=item->valuedouble;
123
	if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
D
Dave Gamble 已提交
124
	{
125
		str=(char*)cJSON_malloc(21);	/* 2^64+1 can be represented in 21 chars. */
126
		if (str) sprintf(str,"%d",item->valueint);
D
Dave Gamble 已提交
127 128 129
	}
	else
	{
130
		str=(char*)cJSON_malloc(64);	/* This is a nice tradeoff. */
131 132 133 134 135 136
		if (str)
		{
			if (fabs(floor(d)-d)<=DBL_EPSILON)			sprintf(str,"%.0f",d);
			else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)	sprintf(str,"%e",d);
			else										sprintf(str,"%f",d);
		}
D
Dave Gamble 已提交
137 138 139 140
	}
	return str;
}

141
/* Parse the input text into an unescaped cstring, and populate item. */
142
static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
D
Dave Gamble 已提交
143 144 145
static const char *parse_string(cJSON *item,const char *str)
{
	const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc;
146
	if (*str!='\"') {ep=str;return 0;}	/* not a string! */
D
Dave Gamble 已提交
147
	
D
Dave Gamble 已提交
148
	while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++;	/* Skip escaped quotes. */
D
Dave Gamble 已提交
149
	
150
	out=(char*)cJSON_malloc(len+1);	/* This is how long we need for the string, roughly. */
151
	if (!out) return 0;
D
Dave Gamble 已提交
152 153
	
	ptr=str+1;ptr2=out;
D
Dave Gamble 已提交
154
	while (*ptr!='\"' && *ptr)
D
Dave Gamble 已提交
155 156 157 158 159 160 161 162 163 164 165 166
	{
		if (*ptr!='\\') *ptr2++=*ptr++;
		else
		{
			ptr++;
			switch (*ptr)
			{
				case 'b': *ptr2++='\b';	break;
				case 'f': *ptr2++='\f';	break;
				case 'n': *ptr2++='\n';	break;
				case 'r': *ptr2++='\r';	break;
				case 't': *ptr2++='\t';	break;
167 168
				case 'u':	 /* transcode utf16 to utf8. DOES NOT SUPPORT SURROGATE PAIRS CORRECTLY. */
					sscanf(ptr+1,"%4x",&uc);	/* get the unicode char. */
D
Dave Gamble 已提交
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
					len=3;if (uc<0x80) len=1;else if (uc<0x800) len=2;ptr2+=len;
					
					switch (len) {
						case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
						case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
						case 1: *--ptr2 =(uc | firstByteMark[len]);
					}
					ptr2+=len;ptr+=4;
					break;
				default:  *ptr2++=*ptr; break;
			}
			ptr++;
		}
	}
	*ptr2=0;
	if (*ptr=='\"') ptr++;
	item->valuestring=out;
	item->type=cJSON_String;
	return ptr;
}

190
/* Render the cstring provided to an escaped version that can be printed. */
D
Dave Gamble 已提交
191 192
static char *print_string_ptr(const char *str)
{
D
Dave Gamble 已提交
193
	const char *ptr;char *ptr2,*out;int len=0;unsigned char token;
D
Dave Gamble 已提交
194
	
195
	if (!str) return cJSON_strdup("");
D
Dave Gamble 已提交
196
	ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;}
D
Dave Gamble 已提交
197
	
198
	out=(char*)cJSON_malloc(len+3);
199 200
	if (!out) return 0;

D
Dave Gamble 已提交
201 202 203 204
	ptr2=out;ptr=str;
	*ptr2++='\"';
	while (*ptr)
	{
205
		if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
D
Dave Gamble 已提交
206 207 208
		else
		{
			*ptr2++='\\';
D
Dave Gamble 已提交
209
			switch (token=*ptr++)
D
Dave Gamble 已提交
210 211 212 213 214 215 216 217
			{
				case '\\':	*ptr2++='\\';	break;
				case '\"':	*ptr2++='\"';	break;
				case '\b':	*ptr2++='b';	break;
				case '\f':	*ptr2++='f';	break;
				case '\n':	*ptr2++='n';	break;
				case '\r':	*ptr2++='r';	break;
				case '\t':	*ptr2++='t';	break;
D
Dave Gamble 已提交
218
				default: sprintf(ptr2,"u%04x",token);ptr2+=5;	break;	/* escape and print */
D
Dave Gamble 已提交
219 220 221 222 223 224
			}
		}
	}
	*ptr2++='\"';*ptr2++=0;
	return out;
}
225
/* Invote print_string_ptr (which is useful) on an item. */
D
Dave Gamble 已提交
226 227
static char *print_string(cJSON *item)	{return print_string_ptr(item->valuestring);}

228
/* Predeclare these prototypes. */
D
Dave Gamble 已提交
229
static const char *parse_value(cJSON *item,const char *value);
D
Dave Gamble 已提交
230
static char *print_value(cJSON *item,int depth,int fmt);
D
Dave Gamble 已提交
231
static const char *parse_array(cJSON *item,const char *value);
D
Dave Gamble 已提交
232
static char *print_array(cJSON *item,int depth,int fmt);
D
Dave Gamble 已提交
233
static const char *parse_object(cJSON *item,const char *value);
D
Dave Gamble 已提交
234
static char *print_object(cJSON *item,int depth,int fmt);
D
Dave Gamble 已提交
235

236
/* Utility to jump whitespace and cr/lf */
D
Dave Gamble 已提交
237
static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}
238

239
/* Parse an object - create a new root, and populate. */
240 241 242
cJSON *cJSON_Parse(const char *value)
{
	cJSON *c=cJSON_New_Item();
D
Dave Gamble 已提交
243
	ep=0;
244 245 246 247 248 249
	if (!c) return 0;       /* memory fail */

	if (!parse_value(c,skip(value))) {cJSON_Delete(c);return 0;}
	return c;
}

250
/* Render a cJSON item/entity/structure to text. */
D
Dave Gamble 已提交
251 252
char *cJSON_Print(cJSON *item)				{return print_value(item,0,1);}
char *cJSON_PrintUnformatted(cJSON *item)	{return print_value(item,0,0);}
D
Dave Gamble 已提交
253

254
/* Parser core - when encountering text, process appropriately. */
D
Dave Gamble 已提交
255 256
static const char *parse_value(cJSON *item,const char *value)
{
257
	if (!value)						return 0;	/* Fail on null. */
D
Dave Gamble 已提交
258 259 260 261 262 263 264 265
	if (!strncmp(value,"null",4))	{ item->type=cJSON_NULL;  return value+4; }
	if (!strncmp(value,"false",5))	{ item->type=cJSON_False; return value+5; }
	if (!strncmp(value,"true",4))	{ item->type=cJSON_True; item->valueint=1;	return value+4; }
	if (*value=='\"')				{ return parse_string(item,value); }
	if (*value=='-' || (*value>='0' && *value<='9'))	{ return parse_number(item,value); }
	if (*value=='[')				{ return parse_array(item,value); }
	if (*value=='{')				{ return parse_object(item,value); }

266
	ep=value;return 0;	/* failure. */
D
Dave Gamble 已提交
267 268
}

269
/* Render a value to text. */
D
Dave Gamble 已提交
270
static char *print_value(cJSON *item,int depth,int fmt)
D
Dave Gamble 已提交
271 272
{
	char *out=0;
D
Dave Gamble 已提交
273
	if (!item) return 0;
D
Dave Gamble 已提交
274
	switch ((item->type)&255)
D
Dave Gamble 已提交
275
	{
276 277 278
		case cJSON_NULL:	out=cJSON_strdup("null");	break;
		case cJSON_False:	out=cJSON_strdup("false");break;
		case cJSON_True:	out=cJSON_strdup("true"); break;
D
Dave Gamble 已提交
279 280
		case cJSON_Number:	out=print_number(item);break;
		case cJSON_String:	out=print_string(item);break;
D
Dave Gamble 已提交
281 282
		case cJSON_Array:	out=print_array(item,depth,fmt);break;
		case cJSON_Object:	out=print_object(item,depth,fmt);break;
D
Dave Gamble 已提交
283 284 285 286
	}
	return out;
}

287
/* Build an array from input text. */
D
Dave Gamble 已提交
288 289 290
static const char *parse_array(cJSON *item,const char *value)
{
	cJSON *child;
291
	if (*value!='[')	{ep=value;return 0;}	/* not an array! */
D
Dave Gamble 已提交
292 293 294

	item->type=cJSON_Array;
	value=skip(value+1);
295
	if (*value==']') return value+1;	/* empty array. */
D
Dave Gamble 已提交
296 297

	item->child=child=cJSON_New_Item();
298 299
	if (!item->child) return 0;		 /* memory fail */
	value=skip(parse_value(child,skip(value)));	/* skip any spacing, get the value. */
300
	if (!value) return 0;
D
Dave Gamble 已提交
301 302 303 304

	while (*value==',')
	{
		cJSON *new_item;
305
		if (!(new_item=cJSON_New_Item())) return 0; 	/* memory fail */
D
Dave Gamble 已提交
306 307
		child->next=new_item;new_item->prev=child;child=new_item;
		value=skip(parse_value(child,skip(value+1)));
308
		if (!value) return 0;	/* memory fail */
D
Dave Gamble 已提交
309 310
	}

311
	if (*value==']') return value+1;	/* end of array */
312
	ep=value;return 0;	/* malformed. */
D
Dave Gamble 已提交
313 314
}

315
/* Render an array to text */
D
Dave Gamble 已提交
316
static char *print_array(cJSON *item,int depth,int fmt)
D
Dave Gamble 已提交
317
{
318 319
	char **entries;
	char *out=0,*ptr,*ret;int len=5;
D
Dave Gamble 已提交
320
	cJSON *child=item->child;
321
	int numentries=0,i=0,fail=0;
D
Dave Gamble 已提交
322
	
323
	/* How many entries in the array? */
324
	while (child) numentries++,child=child->next;
325
	/* Allocate an array to hold the values for each */
326 327 328
	entries=(char**)cJSON_malloc(numentries*sizeof(char*));
	if (!entries) return 0;
	memset(entries,0,numentries*sizeof(char*));
329
	/* Retrieve all the results: */
330 331
	child=item->child;
	while (child && !fail)
D
Dave Gamble 已提交
332
	{
D
Dave Gamble 已提交
333
		ret=print_value(child,depth+1,fmt);
334
		entries[i++]=ret;
D
Dave Gamble 已提交
335
		if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
D
Dave Gamble 已提交
336 337
		child=child->next;
	}
338
	
339
	/* If we didn't fail, try to malloc the output string */
340
	if (!fail) out=(char*)cJSON_malloc(len);
341
	/* If that fails, we fail. */
342 343
	if (!out) fail=1;

344
	/* Handle failure. */
345 346 347 348 349 350 351
	if (fail)
	{
		for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
		cJSON_free(entries);
		return 0;
	}
	
352
	/* Compose the output array. */
353 354 355 356 357
	*out='[';
	ptr=out+1;*ptr=0;
	for (i=0;i<numentries;i++)
	{
		strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
D
Dave Gamble 已提交
358
		if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}
359 360 361
		cJSON_free(entries[i]);
	}
	cJSON_free(entries);
D
Dave Gamble 已提交
362 363 364 365
	*ptr++=']';*ptr++=0;
	return out;	
}

366
/* Build an object from the text. */
D
Dave Gamble 已提交
367 368 369
static const char *parse_object(cJSON *item,const char *value)
{
	cJSON *child;
370
	if (*value!='{')	{ep=value;return 0;}	/* not an object! */
D
Dave Gamble 已提交
371 372 373
	
	item->type=cJSON_Object;
	value=skip(value+1);
374
	if (*value=='}') return value+1;	/* empty array. */
D
Dave Gamble 已提交
375 376
	
	item->child=child=cJSON_New_Item();
377
	if (!item->child) return 0;
D
Dave Gamble 已提交
378
	value=skip(parse_string(child,skip(value)));
379
	if (!value) return 0;
D
Dave Gamble 已提交
380
	child->string=child->valuestring;child->valuestring=0;
381
	if (*value!=':') {ep=value;return 0;}	/* fail! */
382
	value=skip(parse_value(child,skip(value+1)));	/* skip any spacing, get the value. */
383
	if (!value) return 0;
D
Dave Gamble 已提交
384 385 386 387
	
	while (*value==',')
	{
		cJSON *new_item;
388
		if (!(new_item=cJSON_New_Item()))	return 0; /* memory fail */
D
Dave Gamble 已提交
389 390
		child->next=new_item;new_item->prev=child;child=new_item;
		value=skip(parse_string(child,skip(value+1)));
391
		if (!value) return 0;
D
Dave Gamble 已提交
392
		child->string=child->valuestring;child->valuestring=0;
393
		if (*value!=':') {ep=value;return 0;}	/* fail! */
394
		value=skip(parse_value(child,skip(value+1)));	/* skip any spacing, get the value. */
395
		if (!value) return 0;
D
Dave Gamble 已提交
396 397
	}
	
398
	if (*value=='}') return value+1;	/* end of array */
399
	ep=value;return 0;	/* malformed. */
D
Dave Gamble 已提交
400 401
}

402
/* Render an object to text. */
D
Dave Gamble 已提交
403
static char *print_object(cJSON *item,int depth,int fmt)
D
Dave Gamble 已提交
404
{
405 406
	char **entries=0,**names=0;
	char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
D
Dave Gamble 已提交
407
	cJSON *child=item->child;
408
	int numentries=0,fail=0;
409
	/* Count the number of entries. */
410
	while (child) numentries++,child=child->next;
411
	/* Allocate space for the names and the objects */
412 413 414 415 416 417 418
	entries=(char**)cJSON_malloc(numentries*sizeof(char*));
	if (!entries) return 0;
	names=(char**)cJSON_malloc(numentries*sizeof(char*));
	if (!names) {cJSON_free(entries);return 0;}
	memset(entries,0,sizeof(char*)*numentries);
	memset(names,0,sizeof(char*)*numentries);

419
	/* Collect all the results into our arrays: */
D
Dave Gamble 已提交
420
	child=item->child;depth++;if (fmt) len+=depth;
D
Dave Gamble 已提交
421 422
	while (child)
	{
423
		names[i]=str=print_string_ptr(child->string);
D
Dave Gamble 已提交
424 425
		entries[i++]=ret=print_value(child,depth,fmt);
		if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
426 427 428
		child=child->next;
	}
	
429
	/* Try to allocate the output string */
430 431 432
	if (!fail) out=(char*)cJSON_malloc(len);
	if (!out) fail=1;

433
	/* Handle failure */
434 435
	if (fail)
	{
436 437
		for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}
		cJSON_free(names);cJSON_free(entries);
438 439 440
		return 0;
	}
	
441
	/* Compose the output: */
D
Dave Gamble 已提交
442
	*out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
443 444
	for (i=0;i<numentries;i++)
	{
D
Dave Gamble 已提交
445
		if (fmt) for (j=0;j<depth;j++) *ptr++='\t';
446
		strcpy(ptr,names[i]);ptr+=strlen(names[i]);
D
Dave Gamble 已提交
447
		*ptr++=':';if (fmt) *ptr++='\t';
448 449
		strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
		if (i!=numentries-1) *ptr++=',';
D
Dave Gamble 已提交
450
		if (fmt) *ptr++='\n';*ptr=0;
451
		cJSON_free(names[i]);cJSON_free(entries[i]);
D
Dave Gamble 已提交
452
	}
453 454
	
	cJSON_free(names);cJSON_free(entries);
D
Dave Gamble 已提交
455
	if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
D
Dave Gamble 已提交
456 457 458 459
	*ptr++='}';*ptr++=0;
	return out;	
}

460
/* Get Array size/item / object item. */
D
Dave Gamble 已提交
461
int    cJSON_GetArraySize(cJSON *array)							{cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
462
cJSON *cJSON_GetArrayItem(cJSON *array,int item)				{cJSON *c=array->child;  while (c && item>0) item--,c=c->next; return c;}
463
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string)	{cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
D
Dave Gamble 已提交
464

465
/* Utility for array list handling. */
D
Dave Gamble 已提交
466
static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
467
/* Utility for handling references. */
468
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;}
D
Dave Gamble 已提交
469

470
/* Add item to array/object. */
471
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);}}
472
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);}
D
Dave Gamble 已提交
473 474 475
void	cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)						{cJSON_AddItemToArray(array,create_reference(item));}
void	cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item)	{cJSON_AddItemToObject(object,string,create_reference(item));}

D
Dave Gamble 已提交
476
cJSON *cJSON_DetachItemFromArray(cJSON *array,int which)			{cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0;
477
	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;}
478
void   cJSON_DeleteItemFromArray(cJSON *array,int which)			{cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
479
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;}
480
void   cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
D
Dave Gamble 已提交
481

482
/* Replace array/object items with new ones. */
D
Dave Gamble 已提交
483 484
void   cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem)		{cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return;
	newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem;
485
	if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);}
486
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);}}
D
Dave Gamble 已提交
487

488
/* Create basic types: */
489 490 491
cJSON *cJSON_CreateNull()						{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
cJSON *cJSON_CreateTrue()						{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
cJSON *cJSON_CreateFalse()						{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
D
Dave Gamble 已提交
492
cJSON *cJSON_CreateBool(int b)					{cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
493 494 495 496
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 *cJSON_CreateString(const char *string)	{cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;}
cJSON *cJSON_CreateArray()						{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
cJSON *cJSON_CreateObject()						{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}
D
Dave Gamble 已提交
497

498
/* Create Arrays: */
499 500 501 502
cJSON *cJSON_CreateIntArray(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 *cJSON_CreateFloatArray(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 *cJSON_CreateDoubleArray(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 *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;}