cjson源码解析

/*
  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.
*/

/* cJSON */
/* JSON parser in C. */

#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <float.h>
#include <limits.h>
#include <ctype.h>
#include "cJSON.h"
#pragma warning(disable : 4996)

//返回解析出错时对应的字符地址

static const char *ep;
const char *cJSON_GetErrorPtr(void) {return ep;}

//不区分大小写字符串比较,感觉和原生的strcasecmp没什么区别

static int cJSON_strcasecmp(const char *s1,const char *s2)
{
	if (!s1) 
		return (s1==s2)?0:1;
	if (!s2) return 1;
	for(; tolower(*s1) == tolower(*s2); ++s1, ++s2)	
		if(*s1 == 0)	return 0;
	return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
}

//定义cJSON中内存分配采用的方式,这里直接使用原生的malloc,free函数

static void *(*cJSON_malloc)(size_t sz) = malloc;
static void (*cJSON_free)(void *ptr) = free;

//定义cJSON中的字符串拷贝函数

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

      len = strlen(str) + 1;//函数进行分配空间的时候,需要加上末尾的'\0',所以最后添加了一个1
      if (!(copy = (char*)cJSON_malloc(len))) return 0;
      memcpy(copy,str,len);
      return copy;
}

//选择系统使用那种内存分配方式,这里使用原生的malloc、free函数。

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;
}

/* Internal constructor. */
//构造一个item,同时给item赋初值为全0,item可以理解为一个节点

static cJSON *cJSON_New_Item(void)
{
	cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
	if (node) memset(node,0,sizeof(cJSON));//进行初始化,将json数据中所有的内存都设置为 0
	return node;
}

/* Delete a cJSON structure.
释放链表,对于有子链表的链表,采用递归的方式进行内存释放
目前还没有找到为什么需要 c->type & cJSON_IsReference 判断
*/

void cJSON_Delete(cJSON *c)
{
	/*
	这个删除节点,首先是删除这个节点的孩子节点们(next和pre是兄弟节点之间的称呼)
	其次是删除孩子节点的节点(child是孩子节点之间的称呼)
	*/
	cJSON *next;
	while (c)
	{
		next=c->next;
		if (!(c->type&cJSON_IsReference) && c->child)
			cJSON_Delete(c->child);          //递归释放内存256
		if (!(c->type&cJSON_IsReference) && c->valuestring)
			cJSON_free(c->valuestring);//512
		if (!(c->type&cJSON_StringIsConst) && c->string)
			cJSON_free(c->string);
		cJSON_free(c);
		c=next;
	}
 }

/* Parse the input text to generate a number, and populate the result into item. 
解析数字,并把数据保存在item中对应的地方
*/
static const char *parse_number(cJSON *item,const char *num)
{
	/*
	局部变量说明:
		1.n			:用于保存数字;
		2.sign		:数字部分的符号标志,如果是负数,就等于-1,如果是正数,就是1
		3.scale		:保存小数点后面有多少个数字的相反数
		4.subscale  :保存指数后面的数字
		5.signsubscale:指数部分的符号标志,如果是负数就等于-1,如果是正数就是1.
		
		如:

			num字符串: -1234.1234e4
			1.n			=12341234
			2.sign		=-1
			3.scale		=-4
			4.subscale  =4
			5.signsubscale = 1

			结果公示 = sign * n * pow( 10.0, (scale + subscale * signsubscale))

			n = -1 * 12341234 * pow( 10.0,(-4 + 4 * 1))
			n = -12341234 * pow(10.0 , 0)
			n = -12341234
	
	*/
	double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;

	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[1]>='0' && num[1]<='9') 
	{
		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? */
	}

	n=sign*n*pow(10.0,(scale+subscale*signsubscale));	/* number = +/- number.fraction * 10^+/- exponent */
	/*
	一两种形式来保存数据,在下面的函数print_number()中输出数字的时候要比较这两个数据。
	*/
	item->valuedouble	=n;
	item->valueint		=(int)n;
	item->type			=cJSON_Number;
	return num;
}

//这个函数是为了返回大于等于x的最小的2的N次方数
//这个方法是为了将最高位以下的位全部都置成1,然后再加1就是最小的2的N次方。
static int pow2gt (int x)	{	--x;	x|=x>>1;	x|=x>>2;	x|=x>>4;	x|=x>>8;	x|=x>>16;	return x+1;	}

typedef struct {char *buffer; int length; int offset; } printbuffer;
///一个字符串的封装,封装长度和目前读取到的offset
/*
ensure 函数是一个协助printbuffer分配内存的函数
len表示当前字符串起始偏移量 即newbuffer+p -> offset 起始的

*/
static char* ensure(printbuffer *p,int needed)//分配printbuffer所需要的的空间的大小
{
	char *newbuffer;
	int   newsize;
	if (!p || !p->buffer) return 0;//如果为空的话,返回0
	needed+=p->offset;//需要额外分配的内存 也就是偏移量
	if (needed<=p->length) return p->buffer+p->offset;//内存够用直接返回
	newsize=pow2gt(needed);//不得不说这个用的很妙

	newbuffer=(char*)cJSON_malloc(newsize);//malloc出新内存 用来放什么?后边来看是放buffer里面的内容
	if (!newbuffer) {cJSON_free(p->buffer);p->length=0,p->buffer=0;return 0;}//如果needed是空,就将printbuffer进行释放
	if (newbuffer) memcpy(newbuffer,p->buffer,p->length);//将printbuffer中的内容复制到newbuffer中
	cJSON_free(p->buffer);//释放掉之前的buffer
	p->length=newsize;
	p->buffer=newbuffer;
	return newbuffer+p->offset;//为什么要返回这个,这个函数是要干什么?
}

/*
返回的是一个地址,偏移量加上字符串str长度的地址,但这里char *str知识一个局部指针变量!
该指针指向原有的buffer+offset地址处后面的字符串,返回值是一个int型
*/
static int update(printbuffer *p)
{
	char *str;
	if (!p || !p->buffer) return 0;
	str=p->buffer+p->offset;//str指向数据所在地的地址
	return p->offset+strlen(str);
}

/* Render the number nicely from the given item into a string.
下面的代码中使用到DBL_EPSILON,其意思是双精度最小误差;
请参考url: http://blog.csdn.net/x356982611/article/details/19922453
*/

//把数据转化为字符串
static char *print_number(cJSON *item,printbuffer *p)
{
	/*
	局部变量说明:
		1.str:	用于指向输出的数字字符串
		2.d	:保存item中的double数字
	*/
	char *str=0;
	double d=item->valuedouble;
	if (d==0)	//这个item中没有数据存放
	{
		if (p)	str=ensure(p,2);
		else	str=(char*)cJSON_malloc(2); /* special case for 0.*/
		if (str) strcpy(str,"0");
	}
	/*
	fabs函数是求绝对值函数,DBL_EPSILON是最小误差,如果整数减去浮点数值的绝对值低于DBL_ESILON,
	则说明该数可以近似看成是整数,否则就是浮点数
	*/

	//在32位和64位机器中,int都是占32位
	else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
	{
		if (p)	str=ensure(p,21);//因为是utf8编码,需要进行套用模板所以就只有21个位可以进行填充二进制数字。
		else	str=(char*)cJSON_malloc(21);	/* 2^64+1 can be represented in 21 chars. */
		if (str)	sprintf(str,"%d",item->valueint);//将item->valueint中的数据打印到str中去
	}
	else
	{
		if (p)	str=ensure(p,64);
		else	str=(char*)cJSON_malloc(64);	/* This is a nice tradeoff. */
		if (str)
		{
			if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d);
			//floor函数是向下取整的意思,%.0f是输出float型或double型数据,按定点格式,小数以下占0位,不输出的小数部分进行4舍5入。
			else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)			sprintf(str,"%e",d);
			//%e表示输出的数字以科学计数显示
			else												sprintf(str,"%f",d);
			//%f表示以小数形式输出单、双精度数,隐含输出6位小数,%c是以字符形式输出,只输出一个字符,%d是用来输出十进制整数数据的实际长度输出
		}
	}
	return str;	//返回这个里面的字符串。
}

static unsigned parse_hex4(const char *str)
{
	/*
	局部变量说明:
		1.h: 保存最终返回的数据
	*/
	unsigned h=0;
	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;

	h=h<<4;str++;//因为是int型,所以每次进行移动的时候都是4个字节。

	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;
	h=h<<4;str++;
	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;
	h=h<<4;str++;
	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;
	return h;//将这个字符转换为16进制。
}

/* Parse the input text into an unescaped cstring, and populate item. 
将输入的文本分析到非转义cstring并填充item,目前不了解这里是什么情况
不清楚这里的unicode编码格式字符串的处理方式
*/
static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
static const char* parse_string(cJSON* item, const char* str)
{
	/*
	局部变量说明:
		1.ptr:传入参数string的指针
		2.ptr2:指向输出字符串里的地址,主要用于从ptr字符串中拷贝字符串到out中
		3.out:指向动态分配的输出字符串的首地址
		4.len:动态分配需要的字符串的长度,分配时要在基础上+1;
		5.uc:unicode编码格式字符串
		6.uc2:unicode编码格式字符串
	*/
	const char* ptr = str + 1;
	char* ptr2;
	char* out;
	int len = 0;
	unsigned uc, uc2;
	//判断第一个字符串是否是"\",如果不是,那么就不是字符串
	if (*str != '\"') { ep = str; return 0; }	/* not a string! */
	//计算机字符串的长度,为后面的内存分配提供数据长度信息
	while (*ptr != '\"' && *ptr && ++len)
	{					   //进来一个数据模式为:str = 0x00effa98 "\"frame rate\": 24\n}\n}"
		if (*ptr++ == '\\')//在这个if中进行了指针的自加操作
			ptr++;	/* Skip escaped quotes. */
	}
	out=(char*)cJSON_malloc(len+1);	/* This is how long we need for the string, roughly. */
	if (!out) return 0;
	//ptr指向'\' 后面那个字符,ptr2指向out的首地址,有利于数据拷贝
	ptr=str+1;
	ptr2=out;
	while (*ptr!='\"' && *ptr)
	{
		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;
				case 'u':	 /* transcode utf16 to utf8. */
					uc=parse_hex4(ptr+1);ptr+=4;	/* get the unicode char. */

					if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0)	break;	/* check for invalid.	*/

					if (uc>=0xD800 && uc<=0xDBFF)	/* UTF16 surrogate pairs.	*/
					{
						if (ptr[1]!='\\' || ptr[2]!='u')	break;	/* missing second-half of surrogate.	*/
						uc2=parse_hex4(ptr+3);ptr+=6;
						if (uc2<0xDC00 || uc2>0xDFFF)		break;	/* invalid second-half of surrogate.	*/
						uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
					}

					len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
					
					switch (len) {
						case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
						case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
						case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
						case 1: *--ptr2 =(uc | firstByteMark[len]);
					}
					ptr2+=len;
					break;
				default:  *ptr2++=*ptr;
					break;
			}
			ptr++;
		}
	}
	*ptr2=0;
	if (*ptr=='\"') ptr++;
	item->valuestring=out;
	item->type=cJSON_String;
	return ptr;
}

/* Render the cstring provided to an escaped version that can be printed. */
static char *print_string_ptr(const char *str,printbuffer *p)	//输出这个item中的string
{
	/*
	局部变量说明:
		1.ptr:指向参数传入的str字符串
		2.ptr2:指向要输出的out字符串
		3.out:输出字符串
		4.len:输出字符串的长度,用于内存分配出输出字符串的空间大小
		5.token:字符保存中间变量
	*/
	const char *ptr;char *ptr2,*out;int len=0,flag=0;unsigned char token;
	for (ptr=str;*ptr;ptr++)
		flag|=((*ptr>0 && *ptr<32)||(*ptr=='\"')||(*ptr=='\\'))?1:0;
	/*	这个里面\"代表的是"这里的作用是判断ptr中有没有ASCII码在1到31这个区间的,或者是特殊符号	*/
	if (!flag)//如果不存在特殊字符就直接进行字符串的复制。
	{
		len=ptr-str;//这里代表的是str这个字符串的长度
		if (p) out=ensure(p,len+3);
		else		
			out=(char*)cJSON_malloc(len+3);//str = 0x0092c108 "format"
		if (!out) return 0;
		ptr2=out;*ptr2++='\"';//增加前后双引号,然后再以\0进行结尾
		strcpy(ptr2,str);//out = 0x0092d1e8 "\"format\"",这里进行了自动增加转义字符
		ptr2[len]='\"';//前面有ptr++改变了ptr的初始位置。
		ptr2[len+1]=0;
		return out;
	}
	
	if (!str)//如果str为NULL的话进行的一系列操作
	{
		if (p)	out=ensure(p,3);
		else	out=(char*)cJSON_malloc(3);
		if (!out) return 0;
		strcpy(out,"\"\"");
		return out;
	}
	//计算字符串需要的长度
	ptr=str;
	while ((token=*ptr) && ++len) 
	{
		if (strchr("\"\\\b\f\n\r\t",token)) //\t\r\n都是转义字符,空格是单纯的空格,可以直接输入
			//\f是换页\b是退格符
			//strchr函数代表的是在前一个字符串中找一个与token字符串相同的字符串,看看是否存在
			len++; 
		else if (token<32) //控制字符在ASCII表中所在的位置。
			/*
			除了前面列出来的空白字符,其他的空白都+5的长度,
			不知道为什么,应该与unicode编码有关
			如:
				"\uxxxx",u再加4个字符就是5个字符,前面解析字符的时候是这么解析的。
			*/
			len+=5;
		ptr++;
	}
	if (p)	out=ensure(p,len+3);//这个函数表示增加3个空间,主要是为了在out中添加前后双引号以及结尾字符。
	else	out=(char*)cJSON_malloc(len+3);
	if (!out) return 0;//进行判断分配内存是否成功,如果没有成功的话就返回0

	ptr2=out;ptr=str;
	*ptr2++='\"';
	while (*ptr)
	{
		if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\')
			*ptr2++=*ptr++;//进行字符串的复制
		else
		{
			*ptr2++='\\';
			switch (token=*ptr++)
			{
				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;
				default: sprintf(ptr2,"u%04x",token);ptr2+=5;	break;	
					/* 小于escape and print */
			}
		}
	}
	*ptr2++='\"';*ptr2++=0;
	return out;
}
/* Invote print_string_ptr (which is useful) on an item. */
static char *print_string(cJSON *item,printbuffer *p)	
{
	return print_string_ptr(item->valuestring,p);
}
/* Predeclare these prototypes. --> 提前声明这些原型*/
static const char *parse_value(cJSON *item,const char *value);//这里定义了一个常量指针,即这个指针指向的内容不可以变,但是,这个指针指向的位置可以改变
static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p);
static const char *parse_array(cJSON *item,const char *value);
static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p);
static const char *parse_object(cJSON *item,const char *value);
static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p);

/* Utility to jump whitespace and cr/lf --> 跳过不可见字符,这些字符都集中在ascii的前32个字符
	其实就是将字符前的一些空字符去掉。
*/
static const char *skip(const char *in) 
{
	while (in && *in && (unsigned char)*in<=32) 
		in++; 
	return in;
}
/* Parse an object - create a new root, and populate. --> 创建一个根,并填充
require_null_terminated 是为了确保字符串必须以'\0'结尾
若参数提供return_parse_end将返回json字符串解析完成之后的部分进行返回
*/
cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
{
	/*
	出去的时候要返回一个json结构的数据
	局部变量说明:
		1.end:当解析完真个字符串的时候,最后一个字符如果不是NULL,则代表这个输入的value的字符串
				可能有问题;
		2.c:cJSON节点,也是所谓的根节点。
	*/
	const char *end=0;
	cJSON *c=cJSON_New_Item();
	ep=0;
	if (!c) return 0;       /* memory fail */

	end=parse_value(c,skip(value));
	if (!end)	{cJSON_Delete(c);return 0;}	/* parse failure. ep is set. */

	/* 
	if we require null-terminated JSON without appended garbage, skip and then check for a null terminator 
	检查是否是正常的json结束字符串
	*/
	if (require_null_terminated) 
	{
		end=skip(end);
		if (*end)
		{
			cJSON_Delete(c);
			ep=end;return 0;
		}
	}
	if (return_parse_end)
		*return_parse_end=end;
	return c;
}
/* Default options for cJSON_Parse ,默认不检查NULL终止符 
json字符串的解析
*/
cJSON *cJSON_Parse(const char *value) 
{
	return cJSON_ParseWithOpts(value,0,0);
}

/* Render a cJSON item/entity/structure to text. 
print_value中的
	第二个参数是代表json对象的深度;
	第三个代码中的意思是逗号分割键值对后面是否要加空格

如下是第三个参数实例:
	fmt = 0: {"zjf":1,"jfz":2,"fjz":3} 或 [1,2,3,4]
	fmt = 1: {"zjf":1,"jfz":2,"fjz":3} 或 [1,2,3,4]

如上,这里提供了2中选择供我们选择使用
*/
char *cJSON_Print(cJSON *item)				{return print_value(item,0,1,0);}
char *cJSON_PrintUnformatted(cJSON *item)	{return print_value(item,0,0,0);}

char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt)
{
	printbuffer p;
	p.buffer=(char*)cJSON_malloc(prebuffer);
	p.length=prebuffer;
	p.offset=0;
	return print_value(item,0,fmt,&p);
	return p.buffer;
}

/* Parser core - when encountering text, process appropriately.
根据首字符的不同来决定采用哪种方式进行解析字符串
*/
static const char *parse_value(cJSON *item,const char *value)
{
	if (!value)						return 0;	/* Fail on null. */
	if (!strncmp(value,"null",4))	
	{ item->type=cJSON_NULL;  return value+4; }
	//将value和后面的字符串进行比较判断是否相等,如果相等返回指针的所在位置
	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); }//进行对象解析

	ep=value;return 0;	/* failure. */
}

/* Render a value to text. 
根据item的类型来选这使用哪种方式进行数的输出格式
传进来的值为:item,0,1,0  还有item,0,0,0。指针指向0的问题,就是指针不指向任何对象,相当于NULL。
*/
static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p)//print_value(item,0,fmt,&p);fmt代表的是格式符号
{
	char *out=0;
	if (!item) return 0;
	if (p)
	{
		switch ((item->type)&255)
		{
			case cJSON_NULL:	{out=ensure(p,5);	if (out) strcpy(out,"null");	break;}
			case cJSON_False:	{out=ensure(p,6);	if (out) strcpy(out,"false");	break;}
			case cJSON_True:	{out=ensure(p,5);	if (out) strcpy(out,"true");	break;}
			case cJSON_Number:	out=print_number(item,p);break;
			case cJSON_String:	out=print_string(item,p);break;
			case cJSON_Array:	out=print_array(item,depth,fmt,p);break;
			case cJSON_Object:	out=print_object(item,depth,fmt,p);break;
		}
	}
	else
	{
		switch ((item->type)&255)
		{
			case cJSON_NULL:	out=cJSON_strdup("null");	break;
			case cJSON_False:	out=cJSON_strdup("false");break;
			case cJSON_True:	out=cJSON_strdup("true"); break;
			case cJSON_Number:	out=print_number(item,0);break;
			case cJSON_String:	out=print_string(item,0);break;
			case cJSON_Array:	out=print_array(item,depth,fmt,0);break;
			case cJSON_Object:	out=print_object(item,depth,fmt,0);break;//传进来的值为item,0,1,0  还有item,0,0,0。
		}
	}
	return out;
}

/* Build an array from input text.
以下数据为格式分析:
	[
		[0,-1,0],
		[1,0,0],
		[0,0,1]
	]
	1.先检测到[;
	2.然后skip掉换行符,空白字符;
	3.parse_value从新检测字符串,也就能再次检测又是一个数组了[0,-1,0],
	递归进入解析[0,-1,0],并解析出0,-1,保存在节点中。
	4.检测是否遇到','字符,如果遇到说明后面还有内容需要解析;
	5.循环解析接下来的内容。
*/
static const char *parse_array(cJSON *item,const char *value)
{
	cJSON *child;
	if (*value!='[')	{ep=value;return 0;}	/* not an array! */

	item->type=cJSON_Array;
	value=skip(value+1);
	if (*value==']') return value+1;	/* empty array. */

	item->child=child=cJSON_New_Item();
	if (!item->child) return 0;		 /* memory fail */
	value=skip(parse_value(child,skip(value)));	/* skip any spacing, get the value. */
	if (!value) return 0;

	while (*value==',')
	{
		cJSON *new_item;
		if (!(new_item=cJSON_New_Item())) return 0; 	/* memory fail */
		child->next=new_item;new_item->prev=child;child=new_item;
		value=skip(parse_value(child,skip(value+1)));
		if (!value) return 0;	/* memory fail */
	}

	if (*value==']') return value+1;	/* end of array */
	ep=value;return 0;	/* malformed.  --> 格式不正确 */
}

/* Render an array to text */
static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p)
{
	/*
	局部变量说明:
		1.entries:输出字符串数组,本来是保存在节点中的,被提取取来保存在字符串数组中;
		2.out:合并entries字符数组中的字符串,得到out
		3.ptr:指向out的指针
		4.ret:函数执行结果的返回值;
		5.len:用于统计总的字符长度
		6.child:用于指向当前正要处理的节点
		7.numentries:用于统计总共有多少个entries;
		8.i:for循环计数
		9.fail:处理出错标志。
		10.fmt:目前发现是用来调整格式的
	*/
	char **entries;
	char *out=0,*ptr,*ret;int len=5;
	cJSON *child=item->child;
	int numentries=0,i=0,fail=0;
	size_t tmplen=0;
	
	/* How many entries in the array? */
	while (child) 
		numentries++,
		child=child->next;
	/* Explicitly handle numentries==0  --> 显示处理条目为0的情况 */
	if (!numentries)//如果是一个空的一维数组,就直接返回空数组
	{
		if (p)	out=ensure(p,3);
		else	out=(char*)cJSON_malloc(3);
		if (out) strcpy(out,"[]");
		return out;
	}
	if (p)
	{
		/* Compose the output array. */
		i=p->offset;
		ptr=ensure(p,1);if (!ptr) return 0;	*ptr='[';	p->offset++;
		child=item->child;
		while (child && !fail)
		{
			print_value(child,depth+1,fmt,p);
			p->offset=update(p);
			if (child->next) 
			{
				len=fmt?2:1;
				ptr=ensure(p,len+1);
				if (!ptr) return 0;
				*ptr++=',';
				if(fmt)*ptr++=' ';
				*ptr=0;
				p->offset+=len;
			}
			child=child->next;
		}
		ptr=ensure(p,2);if (!ptr) return 0;	*ptr++=']';*ptr=0;
		out=(p->buffer)+i;
	}
	else
	{
		/* Allocate an array to hold the values for each */
		entries=(char**)cJSON_malloc(numentries*sizeof(char*));//看数组中有几个孩子节点,就申请多大的二维指针地址
		if (!entries) return 0;
		memset(entries,0,numentries*sizeof(char*));//进行指针初始化
		/* Retrieve all the results: -->回复结果*/
		child=item->child;
		while (child && !fail)
		{
			ret=print_value(child,depth+1,fmt,0);
			entries[i++]=ret;
			if (ret) 
				/*
				为什么要加2,目前只发现需要加1就够了,因为就加了一个逗号。
				不知何故......
				难道是为了给那对[]留下空间?
				*/
				len+=strlen(ret)+2+(fmt?1:0); 
			else fail=1;
			child=child->next;
		}
		
		/* If we didn't fail, try to malloc the output string */
		if (!fail)	out=(char*)cJSON_malloc(len);
		/* If that fails, we fail. */
		if (!out) fail=1;

		/* Handle failure. */
		if (fail)
		{
			for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
			cJSON_free(entries);
			return 0;
		}
		
		/* Compose the output array. --> 合成输出数组 */
		*out='[';
		ptr=out+1;*ptr=0;
		for (i=0;i<numentries;i++)
		{
			tmplen=strlen(entries[i]);
			memcpy(ptr,entries[i],tmplen);
			ptr+=tmplen;
			if (i!=numentries-1) 
			{
				*ptr++=',';		//字符和分割
				if(fmt)*ptr++=' ';//一个格式字符
				*ptr=0;//每次都结束当前字符串,但是运行后续代码,又会被取代
			}
			cJSON_free(entries[i]);
		}
		cJSON_free(entries);
		*ptr++=']';
		*ptr++=0;
	}
	return out;	
}
/*
	以下数据为格式分析:
	{
		"name":"jack(\"bee\") Nimble",
		"format":{
			"type":"rect",
			"width":1920,
			"height":1080,
			"interlace"false,
			"frame rate":24
			}
	}
	1.检测到'{';
	2.跳过空白字符,换行符;
	3.通过parse_string获取name;
	4.判断键值对表示符':';
	5.通过parse_value获取对应value;
	6.parse_value和前面的几个函数一样,是递归函数
	7.通过while循环解析剩下的键值对
*/
/* Build an object from the text. */
static const char *parse_object(cJSON *item,const char *value)
{
	cJSON *child;
	if (*value!='{')	{ep=value;return 0;}	/* not an object! ep是用来返回出错的地址所在地*/
	
	item->type=cJSON_Object;
	value=skip(value+1);
	if (*value=='}') 
		return value+1;	/* empty array. */
	
	item->child=child=cJSON_New_Item();
	if (!item->child) return 0;
	value=skip(parse_string(child,skip(value)));
	if (!value) return 0;
	child->string=child->valuestring;
	child->valuestring=0;
	if (*value!=':') {ep=value;return 0;}	/* fail! */
	value=skip(parse_value(child,skip(value+1)));	/* skip any spacing, get the value. */
	if (!value) return 0;
	
	while (*value==',')
	{
		cJSON *new_item;
		if (!(new_item=cJSON_New_Item()))	return 0; /* memory fail */
		child->next=new_item;
		new_item->prev=child;
		child=new_item;
		value=skip(parse_string(child,skip(value+1)));
		if (!value) return 0;
		child->string=child->valuestring;
		child->valuestring=0;
		if (*value!=':') {ep=value;return 0;}	/* fail! */
		value=skip(parse_value(child,skip(value+1)));	/* skip any spacing, get the value. */
		if (!value) return 0;
	}
	
	if (*value=='}') return value+1;	/* end of array */
	ep=value;return 0;	/* malformed. */
}

/* Render an object to text. 
该函数和前面print_array()相似
*/
static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p)
{
	/*
	item 0,1,0;item 0,0,0
	局部变量说明:
		1.entries:键值对value
		2.names:键值对key;
		3.out:指向输出的字符串
		4.ptr:指向out输出的字符串
		5.ret:执行函数时返回的字符串地址;
		6.str:执行函数返回的字符串地址
		7.len:字符串的长度
		8.i:for循环用于计数的变量
		9.j: for循环用于计数的变量
		10.child:指向节点的指针。
		11.fail输出出错时的标志
		12.numenties:用于统计当前结构深度层次上的节点个数
	*/
	char **entries=0,**names=0;
	char *out=0,*ptr,*ret,*str;
	int len=7,i=0,j;
	cJSON *child=item->child;
	int numentries=0,fail=0;
	size_t tmplen=0;//unsigned int类型
	/* Count the number of entries. */
	while (child)
		numentries++,child=child->next; //深度查看
	/* Explicitly handle empty object case */
	if (!numentries)
	{
		if (p) out=ensure(p,fmt?depth+4:3);//给p进行预留空间
		else	out=(char*)cJSON_malloc(fmt?depth+4:3);
		if (!out)	return 0;
		ptr=out;*ptr++='{';
		if (fmt) 
		{
			*ptr++='\n';
			for (i=0;i<depth-1;i++) 
			*ptr++='\t';
		}//水平制表符,相当于按了tab键,8个字符的空位
		*ptr++='}';*ptr++=0;
		return out;
	}
	if (p)
	{
		/* Compose the output: */
		i=p->offset;
		len=fmt?2:1;	ptr=ensure(p,len+1);	if (!ptr) return 0;
		*ptr++='{';	if (fmt) *ptr++='\n';	*ptr=0;	p->offset+=len;
		child=item->child;depth++;
		while (child)
		{
			if (fmt)
			{
				ptr=ensure(p,depth);	if (!ptr) return 0;
				for (j=0;j<depth;j++) *ptr++='\t';
				p->offset+=depth;
			}
			print_string_ptr(child->string,p);
			p->offset=update(p);
			
			len=fmt?2:1;
			ptr=ensure(p,len);	if (!ptr) return 0;
			*ptr++=':';if (fmt) *ptr++='\t';
			p->offset+=len;
			
			print_value(child,depth,fmt,p);
			p->offset=update(p);

			len=(fmt?1:0)+(child->next?1:0);
			ptr=ensure(p,len+1); if (!ptr) return 0;
			if (child->next) *ptr++=',';
			if (fmt) *ptr++='\n';*ptr=0;
			p->offset+=len;
			child=child->next;
		}
		ptr=ensure(p,fmt?(depth+1):2);	 if (!ptr) return 0;
		if (fmt)	for (i=0;i<depth-1;i++) *ptr++='\t';
		*ptr++='}';*ptr=0;
		out=(p->buffer)+i;
	}
	else
	{
		/* Allocate space for the names and the objects */
		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);

		/* Collect all the results into our arrays: */
		child=item->child;depth++;if (fmt) len+=depth;
		while (child)
		{
			names[i]=str=print_string_ptr(child->string,0);//names[i]与entries[i]都代表的一维指针,指向自己想要指向的地址。
			entries[i++]=ret=print_value(child,depth,fmt,0);
			if (str && ret) 
				len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); 
			else 
				fail=1;
			child=child->next;
		}
		
		/* Try to allocate the output string */
		if (!fail)	out=(char*)cJSON_malloc(len);
		if (!out) fail=1;

		/* Handle failure */
		if (fail)//如果失败了,要将申请的内存进行还回去
		{
			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);
			return 0;
		}
		
		/* Compose the output: */
		*out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
		for (i=0;i<numentries;i++)
		{
			if (fmt) for (j=0;j<depth;j++) *ptr++='\t';
			tmplen=strlen(names[i]);memcpy(ptr,names[i],tmplen);ptr+=tmplen;
			*ptr++=':';if (fmt) *ptr++='\t';
			strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
			if (i!=numentries-1) *ptr++=',';
			if (fmt) *ptr++='\n';*ptr=0;
			cJSON_free(names[i]);cJSON_free(entries[i]);
			/*这里进行释放的是这个指针,这个指针指向的空间还是存在的。当这个地址没有指针指向的时候,这个位置就为空了。*/
		}
		cJSON_free(names);cJSON_free(entries);
		if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
		*ptr++='}';*ptr++=0;
	}
	return out;	
}

/* Get Array size/item / object item. */
int    cJSON_GetArraySize(cJSON *array)							{cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
cJSON *cJSON_GetArrayItem(cJSON *array,int item)				{cJSON *c=array->child;  while (c && item>0) item--,c=c->next; return c;}
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string)	
{
	cJSON *c=object->child; 
	while (c && cJSON_strcasecmp(c->string,string)) 
		//次函数是为了在json结构体中,找到自己想要的结构体,进而可以读取自己想要的一些信息内容
		//比如键值名称、键值等信息。
		c=c->next; 
	return c;
}

/* Utility for array list handling. */
static void suffix_object(cJSON *prev,cJSON *item)
{
	prev->next=item;
	item->prev=prev;//这个函数是为了创建一个兄弟节点,创建好了之后,需要进行改变指针指向。
}
/* Utility for handling references. 当我们要添加的节点已经在要给树上的时候,
再向另一个树中添加这个节点时,这个节点的pre和next指针会被覆盖。于是cJSON又提供了一种引用性添加节点的方法。简单的说就是在创建一个item
新创建的item的value指针直接指向原来的value值,这样两个item就指向了同一个item了。但是这个引用计数是个难题,cJSON也没有处理好,只能引用一次*/
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;
}
/* Add item to array/object. */
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);
	}//如果这个列表中存在孩子节点,就在最后一个孩子节点的后面进行追加一个孩子节点
	
}
/*
	这里是增加一个json对象,这里的json对象就是键值对
	这里的key就是string
	这里的value是item的值
*/
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);//这个地方重新申请了一个空间赋值给这个item中的stringname
	cJSON_AddItemToArray(object,item);
}
void   cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item)	{if (!item) return; if (!(item->type&cJSON_StringIsConst) && item->string) cJSON_free(item->string);item->string=(char*)string;item->type|=cJSON_StringIsConst;cJSON_AddItemToArray(object,item);}
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));}

cJSON *cJSON_DetachItemFromArray(cJSON *array,int which)			
{//进行删除这个json结构体树中的第which个json结构体。删除之后,进行返回并释放内存。
	cJSON *c=array->child;
	while (c && which>0) c=c->next,which--;
	if (!c) return 0;
	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;
}
void   cJSON_DeleteItemFromArray(cJSON *array,int which)			{cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
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;
}
void   cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}

/* Replace array/object items with new ones. */
void   cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem)		
{
	cJSON *c=array->child;
	while (c && which>0) c=c->next,which--;if (!c) 
	{
		cJSON_AddItemToArray(array,newitem);
		return;
	}
	newitem->next=c;
	newitem->prev=c->prev;
	c->prev=newitem;
	if (c==array->child) 
		array->child=newitem; 
	else newitem->prev->next=newitem;
}
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;
	if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);}
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);
	}
}
/* Create basic types: */
cJSON *cJSON_CreateNull(void)					
{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
cJSON *cJSON_CreateTrue(void)					
{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
cJSON *cJSON_CreateFalse(void)					
{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
cJSON *cJSON_CreateBool(int b)					
{cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
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(void)					
{
	cJSON *item=cJSON_New_Item();
	if(item)
		item->type=cJSON_Array;
	return item;
}
cJSON *cJSON_CreateObject(void)					
{//创建一个对象形式的json对象
	cJSON *item=cJSON_New_Item();
	if(item)item->type=cJSON_Object;
	return item;
}

/* Create Arrays: */
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 *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 *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;}
/*
	这里的string指向的是二维数组
*/
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;
}

/* Duplication */
cJSON *cJSON_Duplicate(cJSON *item,int recurse)
{
	cJSON *newitem,*cptr,*nptr=0,*newchild;
	/* Bail on bad ptr */
	if (!item) return 0;
	/* Create new item */
	newitem=cJSON_New_Item();
	if (!newitem) return 0;
	/* Copy over all vars , ~这个运算符代表的是按位取反*/
	newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble;
	if (item->valuestring)	{newitem->valuestring=cJSON_strdup(item->valuestring);	
	if (!newitem->valuestring)	{cJSON_Delete(newitem);return 0;}}
	if (item->string)		{newitem->string=cJSON_strdup(item->string);			
	if (!newitem->string)		{cJSON_Delete(newitem);return 0;}}
	/* If non-recursive, then we're done! */
	if (!recurse) return newitem;
	/* Walk the ->next chain for the child. */
	cptr=item->child;
	while (cptr)
	{
		newchild=cJSON_Duplicate(cptr,1);		/* Duplicate (with recurse) each item in the ->next chain */
		if (!newchild) {cJSON_Delete(newitem);return 0;}
		if (nptr)	{nptr->next=newchild,newchild->prev=nptr;nptr=newchild;}	/* If newitem->child already set, then crosswire ->prev and ->next and move on */
		else		{newitem->child=newchild;nptr=newchild;}					/* Set newitem->child and move to it */
		cptr=cptr->next;
	}
	return newitem;
}

void cJSON_Minify(char *json)
{
	char *into=json;
	while (*json)
	{
		if (*json==' ') json++;
		else if (*json=='\t') json++;	/* Whitespace characters. \代表的是转义字符 */
		else if (*json=='\r') json++;
		else if (*json=='\n') json++;
		else if (*json=='/' && json[1]=='/')  while (*json && *json!='\n') json++;	/* double-slash comments, to end of line. */
		else if (*json=='/' && json[1]=='*') 
		{
			while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;
		}	/* multiline comments. */
		else if (*json=='\"')
		{
			*into++=*json++;
			while (*json && *json!='\"')
			{
				if (*json=='\\') *into++=*json++;*into++=*json++;
			}
			*into++=*json++;
		} /* string literals, which are \" sensitive. */
		else *into++=*json++;			/* All other characters. */
	}
	*into=0;	/* and null-terminate. */
}

  cjson中的.h文件

/*
  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.
*/

#ifndef cJSON__h
#define cJSON__h

#ifdef __cplusplus
extern "C"
{
#endif

/* cJSON Types: */
#define cJSON_False 0
#define cJSON_True 1
#define cJSON_NULL 2
#define cJSON_Number 3
#define cJSON_String 4
#define cJSON_Array 5
#define cJSON_Object 6
	
#define cJSON_IsReference 256
#define cJSON_StringIsConst 512

/* The cJSON structure: */
typedef struct cJSON {
	struct cJSON *next,*prev;	/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
	struct cJSON *child;		/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */

	int type;					/* The type of the item, as above. */

	char *valuestring;			/* The item's string, if type==cJSON_String */
	int valueint;				/* The item's number, if type==cJSON_Number */
	double valuedouble;			/* The item's number, if type==cJSON_Number */
	//32位中int占4个字节、double占8个字节
	char *string;				/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
} cJSON;

typedef struct cJSON_Hooks {
      void *(*malloc_fn)(size_t sz);
      void (*free_fn)(void *ptr);
} cJSON_Hooks;

/* Supply malloc, realloc and free functions to cJSON */
extern void cJSON_InitHooks(cJSON_Hooks* hooks);


/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
extern cJSON *cJSON_Parse(const char *value);
/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
extern char  *cJSON_Print(cJSON *item);
/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
extern char  *cJSON_PrintUnformatted(cJSON *item);
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt);
/* Delete a cJSON entity and all subentities. */
extern void   cJSON_Delete(cJSON *c);

/* Returns the number of items in an array (or object). */
extern int	  cJSON_GetArraySize(cJSON *array);
/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
/* Get item "string" from object. Case insensitive. */
extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);

/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
extern const char *cJSON_GetErrorPtr(void);
	
/* These calls create a cJSON item of the appropriate type. */
extern cJSON *cJSON_CreateNull(void);
extern cJSON *cJSON_CreateTrue(void);
extern cJSON *cJSON_CreateFalse(void);
extern cJSON *cJSON_CreateBool(int b);
extern cJSON *cJSON_CreateNumber(double num);
extern cJSON *cJSON_CreateString(const char *string);
extern cJSON *cJSON_CreateArray(void);
extern cJSON *cJSON_CreateObject(void);

/* These utilities create an Array of count items. */
extern cJSON *cJSON_CreateIntArray(const int *numbers,int count);
extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count);
extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count);
extern cJSON *cJSON_CreateStringArray(const char **strings,int count);

/* Append item to the specified array/object. */
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
extern void	cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
extern void	cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item);	/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
extern void	cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);

/* Remove/Detatch items from Arrays/Objects. */
extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
extern void   cJSON_DeleteItemFromArray(cJSON *array,int which);
extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
extern void   cJSON_DeleteItemFromObject(cJSON *object,const char *string);
	
/* Update array items. */
extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem);	/* Shifts pre-existing items to the right. */
extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);

/* Duplicate a cJSON item */
extern cJSON *cJSON_Duplicate(cJSON *item,int recurse);
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
need to be released. With recurse!=0, it will duplicate any children connected to the item.
The item->next and ->prev pointers are always zero on return from Duplicate. */

/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);

extern void cJSON_Minify(char *json);

/* Macros for creating things quickly. */
#define cJSON_AddNullToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateNull())
#define cJSON_AddTrueToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
#define cJSON_AddFalseToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
#define cJSON_AddBoolToObject(object,name,b)	cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
#define cJSON_AddNumberToObject(object,name,n)	cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
#define cJSON_AddStringToObject(object,name,s)	cJSON_AddItemToObject(object, name, cJSON_CreateString(s))

/* When assigning an integer value, it needs to be propagated to valuedouble too. */
#define cJSON_SetIntValue(object,val)			((object)?(object)->valueint=(object)->valuedouble=(val):(val))
#define cJSON_SetNumberValue(object,val)		((object)?(object)->valueint=(object)->valuedouble=(val):(val))

#ifdef __cplusplus
}
#endif

#endif

  test文件描述

/*
  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.
*/

#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"

/* Parse text to JSON, then render back to text, and print! */
void doit(char *text)
{
	char *out;cJSON *json;
	json=cJSON_Parse(text);
	if (!json) {printf("Error before: [%s]\n",cJSON_GetErrorPtr());}
	else
	{
		out=cJSON_Print(json);
		cJSON_Delete(json);
		printf("%s\n",out);
		free(out);
	}
}

/* Read a file, parse, render back, etc. */
void dofile(char *filename)
{
	FILE *f;long len;char *data;
	f=fopen(filename,"rb");
	fseek(f,0,SEEK_END);//SEEK_END代表的是文件的结尾
	len=ftell(f);//此时文件指针指向文件的结尾、ftell函数是返回文件的偏移地址,整好是这个文本文件的长度。
	fseek(f,0,SEEK_SET);//SEEK_SET代表的是文件的开头。fread
	data=(char*)malloc(len+1);
	fread(data,1,len,f);//这个代表的是将指针f中,读取1 * len个数据到data中。
	fclose(f);
	doit(data);
	free(data);
}

/* Used by some code below as an example datatype. */
struct record {const char *precision;double lat,lon;const char *address,*city,*state,*zip,*country; };

/* Create a bunch of objects as demonstration. */
void create_objects()
{
	cJSON *root,*fmt,*img,*thm,*fld;char *out;int i;	/* declare a few. */
	/* Our "days of the week" array: */
	const char *strings[7]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
	/* Our matrix: */
	int numbers[3][3]={{0,-1,0},{1,0,0},{0,0,1}};
	/* Our "gallery" item: */
	int ids[4]={116,943,234,38793};
	/* Our array of "records": */
	struct record fields[2]={
		{"zip",37.7668,-1.223959e+2,"","SAN FRANCISCO","CA","94107","US"},
		{"zip",37.371991,-1.22026e+2,"","SUNNYVALE","CA","94085","US"}};

	/* Here we construct some JSON standards, from the JSON site. */
	
	/* Our "Video" datatype: 这里是新增加了一个对象*/
	root=cJSON_CreateObject();	
	cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble"));
	cJSON_AddItemToObject(root, "format", fmt=cJSON_CreateObject());
	cJSON_AddStringToObject(fmt,"type",		"rect");
	/*
	#define cJSON_AddStringToObject(object,name,s)	cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
	在这个里面每一个键值对,都是一个对象。
	cJSON_CreateString是创建一个字符串的对象
	cJSON *cJSON_CreateNull(void)
	cJSON *cJSON_CreateTrue(void)
	cJSON *cJSON_CreateFalse(void)
	cJSON *cJSON_CreateBool(int b)
	cJSON *cJSON_CreateNumber(double num)创建一个数字对象
	cJSON *cJSON_CreateString(const char *string)创建一个字符串的对象
	cJSON *cJSON_CreateArray(void)创建一个数组的对象
	cJSON *cJSON_CreateObject(void)创建一个子对象
	*/
	cJSON_AddNumberToObject(fmt,"width",		1920);
	cJSON_AddNumberToObject(fmt,"height",		1080);
	cJSON_AddFalseToObject (fmt,"interlace");
	cJSON_AddNumberToObject(fmt,"frame rate",	24);
	cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble"));
	/*
	out = 0x0092dda0 "{
	\n\t\"name\":\t\"Jack (\\\"Bee\\\") Nimble\",
	\n\t\"format\":
	\t{\n\t\t\"type\":\t\"rect\",
	\n\t\t\"width\":\t1920,
	\n\t\t\"height\":\t1080,
	\n\t\t\"interlace\":\tfalse,
	\n\t\t\"frame rate\":\t24\n\t},
	\n\t\"name\":\t\"Jack (\\\"Bee\\\") Nimble\"\n}"
	*/
	out=cJSON_Print(root);	
	cJSON_Delete(root);	
	printf("%s\n",out);	
	free(out);	/* Print to text, Delete the cJSON, print it, release the string. */

	/* Our "days of the week" array: */
	root=cJSON_CreateStringArray(strings,7);

	out=cJSON_Print(root);
	cJSON_Delete(root);	
	printf("%s\n",out);	
	free(out);

	/* Our matrix: */
	root=cJSON_CreateArray();
	for (i=0;i<3;i++) 
		cJSON_AddItemToArray(root,cJSON_CreateIntArray(numbers[i],3));
/*	cJSON_ReplaceItemInArray(root,1,cJSON_CreateString("Replacement")); */
	out=cJSON_Print(root);	
	cJSON_Delete(root);	
	printf("%s\n",out);	
	free(out);

	/* Our "gallery" item: */
	root=cJSON_CreateObject();//创建了一个对象json
	cJSON_AddItemToObject(root, "Image", img=cJSON_CreateObject());
	cJSON_AddNumberToObject(img,"Width",800);
	cJSON_AddNumberToObject(img,"Height",600);
	cJSON_AddStringToObject(img,"Title","View from 15th Floor");
	cJSON_AddItemToObject(img, "Thumbnail", thm=cJSON_CreateObject());
	cJSON_AddStringToObject(thm, "Url", "http:/*www.example.com/image/481989943");
	cJSON_AddNumberToObject(thm,"Height",125);
	cJSON_AddStringToObject(thm,"Width","100");
	cJSON_AddItemToObject(img,"IDs", cJSON_CreateIntArray(ids,4));

	out=cJSON_Print(root);	
	cJSON_Delete(root);	
	printf("%s\n",out);	
	free(out);

	/* Our array of "records": */

	root=cJSON_CreateArray();//创建了一个数组json
	for (i=0;i<2;i++)
	{
		cJSON_AddItemToArray(root,fld=cJSON_CreateObject());
		cJSON_AddStringToObject(fld, "precision", fields[i].precision);
		cJSON_AddNumberToObject(fld, "Latitude", fields[i].lat);
		cJSON_AddNumberToObject(fld, "Longitude", fields[i].lon);
		cJSON_AddStringToObject(fld, "Address", fields[i].address);
		cJSON_AddStringToObject(fld, "City", fields[i].city);
		cJSON_AddStringToObject(fld, "State", fields[i].state);
		cJSON_AddStringToObject(fld, "Zip", fields[i].zip);
		cJSON_AddStringToObject(fld, "Country", fields[i].country);
	}
	
/*	cJSON_ReplaceItemInObject(cJSON_GetArrayItem(root,1),"City",cJSON_CreateIntArray(ids,4)); */
	
	out=cJSON_Print(root);	cJSON_Delete(root);	printf("%s\n",out);	free(out);

}

int main (int argc, const char * argv[]) {
	/* a bunch of json: */
	//char text1[]="{\n\"name\": \"Jack (\\\"Bee\\\") Nimble\", \n\"format\": {\"type\":       \"rect\", \n\"width\":      1920, \n\"height\":     1080, \n\"interlace\":  false,\"frame rate\": 24\n}\n}";	
	//char text2[]="[\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"]";
	//char text3[]="[\n    [0, -1, 0],\n    [1, 0, 0],\n    [0, 0, 1]\n	]\n";
	//char text4[]="{\n		\"Image\": {\n			\"Width\":  800,\n			\"Height\": 600,\n			\"Title\":  \"View from 15th Floor\",\n			\"Thumbnail\": {\n				\"Url\":    \"http:/*www.example.com/image/481989943\",\n				\"Height\": 125,\n				\"Width\":  \"100\"\n			},\n			\"IDs\": [116, 943, 234, 38793]\n		}\n	}";
	//char text5[]="[\n	 {\n	 \"precision\": \"zip\",\n	 \"Latitude\":  37.7668,\n	 \"Longitude\": -122.3959,\n	 \"Address\":   \"\",\n	 \"City\":      \"SAN FRANCISCO\",\n	 \"State\":     \"CA\",\n	 \"Zip\":       \"94107\",\n	 \"Country\":   \"US\"\n	 },\n	 {\n	 \"precision\": \"zip\",\n	 \"Latitude\":  37.371991,\n	 \"Longitude\": -122.026020,\n	 \"Address\":   \"\",\n	 \"City\":      \"SUNNYVALE\",\n	 \"State\":     \"CA\",\n	 \"Zip\":       \"94085\",\n	 \"Country\":   \"US\"\n	 }\n	 ]";

	//char text6[]="[\n    [0,2,3, -1, 0],\n    [1, 0, 0],\n    [0, 0, 1]\n	]\n";

	/* Process each json textblock by parsing, then rebuilding: */
	char a[] = "false";
	doit(a);
	//doit(text1);
	//doit(text6);
	//doit(text2);	
	//doit(text3);
	//doit(text4);
	//doit(text5);

	/* Parse standard testfiles: */
/*	dofile("../../tests/test1"); */
/*	dofile("../../tests/test2"); */
/*	dofile("../../tests/test3"); */
/*	dofile("../../tests/test4"); */
/*	dofile("../../tests/test5"); */

	/* Now some samplecode for building objects concisely: */
	//create_objects();
	
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/littleswan/p/12702944.html
今日推荐