cjson 源码阅读笔记

文章目录

  • 基本信息
  • json结构体
  • 内存管理
  • 创建和释放节点
    • 申请节点
    • 创建具体节点
    • 释放节点
  • 节点 增删改查
    • 增加节点
    • 删除节点
    • 查找节点
    • 修改节点
  • json字符串解析
    • json解析器
    • 解析字符串
    • 解析数字
    • 解析数组
    • 解析对象
  • json序列化

源码下载

基本信息

JSON 数据的书写格式是:名称/值对。
JSON 值可以是:

  • 数字(整数或浮点数)
  • 字符串(在双引号中)
  • 逻辑值(true 或 false)
  • 数组(在中括号中)
  • 对象(在大括号中)
  • null

其中对象可以包含多个名称/值对。

cjson中的基本类型:

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

其中
cJSON_IsReference代表子节点指向的child/valuestring不属于此项目,只是一个引用。cJSON_Delete和其他函数只会解除分配这个项目,而不释放child/valuestring。
cJSON_StringIsConst代表该string指向一个常量string。表明cJSON_Delete和其他函数不能尝试释放该string。
cJSON_IsReference 和cJSON_StringIsConst 的值的设置可以让这两个类型和其他的基础类型共存(用位运算)。

json结构体

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

	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;
  • *next,*prev是想做成双链表
  • *child是指向子节点的
  • type就是cjson中的基本类型
  • valuestring是字符串节点的值
  • valueint和valuedouble是数值类型的值
  • string为对象的key

内存管理

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

static void *(*cJSON_malloc)(size_t sz) = malloc;
static void (*cJSON_free)(void *ptr) = 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;
}

cjson 使用 Hook 技术来让使用者可以自定义内存管理函数。
默认使用系统的 malloc 和 free 函数,cJSON_InitHooks 函数可以替换成用户自定义的 malloc 和 free 函数,cJSON_InitHooks 参数为空则使用系统的 malloc 和 free 函数。

创建和释放节点

申请节点

/* Internal constructor. */
static cJSON *cJSON_New_Item(void)
{
	cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
	if (node) 
	{
		memset(node, 0, sizeof(cJSON));
	}
	return node;
}

申请空间并且初始化为0。

创建具体节点

/* Create basic types: */
cJSON *cJSON_CreateNull(void)
{
	cJSON *item = cJSON_New_Item();
	if(item)
	{
		item->type = cJSON_NULL;
	}
	return item;
}

创建NULL类型节点

cJSON *cJSON_CreateTrue(void)
{
	cJSON *item = cJSON_New_Item();
	if(item)
	{
		item->type = cJSON_True;
	}
	return item;
}

创建True类型节点

cJSON *cJSON_CreateFalse(void)
{
	cJSON *item = cJSON_New_Item();
	if(item)
	{
		item->type = cJSON_False;
	}
	return item;
}

创建False类型节点

cJSON *cJSON_CreateBool(int b)
{
	cJSON *item = cJSON_New_Item();
	if(item)
	{
		item->type = b ? cJSON_True : cJSON_False;
	}
	return item;
}

创建True和False类型节点

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)
{
	cJSON *item = cJSON_New_Item();
	if(item)
	{
		item->type = cJSON_Object;
	}
	return item;
}

创建对象类型节点

其中创建字符串类型的时候用到了cJSON_strdup:

static char* cJSON_strdup(const char* str)
{
      size_t len;
      char* copy;
      len = strlen(str) + 1;
      if (!(copy = (char*)cJSON_malloc(len))) 
      {
      		return NULL;
      }
      memcpy(copy, str, len);
      return copy;
}

可以看出来是创建一个字符串的深拷贝。
还提供了四种数组的创建

cJSON *cJSON_CreateIntArray(const int *numbers, int count)
{
	cJSON *n = NULL, *p = NULL, *a = cJSON_CreateArray();
	for (int 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)
cJSON *cJSON_CreateDoubleArray(const double *numbers,int count)
cJSON *cJSON_CreateStringArray(const char **strings,int count)

其中suffix_object是用来连接前后两个节点的。

static void suffix_object(cJSON *prev, cJSON *item)
{
	prev->next = item;
	item->prev = prev;
}

释放节点

/* Delete a cJSON structure. */
void cJSON_Delete(cJSON *c)
{
	cJSON *next;
	while (c)
	{
		next = c->next;
		if (!(c->type & cJSON_IsReference) && c->child)
		{
			cJSON_Delete(c->child);
		}
		if (!(c->type & cJSON_IsReference) && c->valuestring)
		{
			cJSON_free(c->valuestring);
		}
		if (!(c->type & cJSON_StringIsConst) && c->string)
		{
			cJSON_free(c->string);
		}
		cJSON_free(c);
		c = next;
	}
}

如果没有cJSON_IsReference标志并且有子节点则递归释放子节点,
如果没有cJSON_IsReference标志并且有字符串资源则释放字符串,
如果没有cJSON_StringIsConst标志并且有key资源则释放key,
释放自身节点,如果有next节点则进入下一次循环,释放下一个节点。

节点 增删改查

增加节点

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

给数组添加节点,在数组子节点链表最后添加节点。

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

给对象添加节点,先设置要添加节点的key值(使用深复制),再添加到子节点链表的最后。

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

给对象添加节点,不同的是key值只是常量字符串的引用。

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

给数组/对象添加引用节点,其中create_reference

static cJSON *create_reference(cJSON *item)
{
	cJSON *ref = cJSON_New_Item();
	if (!ref)
	{
		return 0;
	}
	memcpy(ref, item, sizeof(cJSON));
	ref->string = NULL;
	ref->type |= cJSON_IsReference;
	ref->next = ref->prev = NULL;
	return ref;
}

完全复制一个节点后,string next prevs设置为空,添加cJSON_IsReference标志,也就是说valuestring和child还是原来节点的资源。
因为当我们要添加的节点已经在一个树上的时候, 再向另一个树中添加这个节点时, 这个节点的 pre 和 next 指针会被覆盖。

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

定义了一些宏用来快速构建对象。

删除节点

cJSON *cJSON_DetachItemFromArray(cJSON *array, int which)
{
	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 = NULL;
	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;
}

从对象中移除节点,其中cJSON_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 *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))
	{
		c = c->next;
	}
	return c;
}

查找对象的节点

int cJSON_GetArraySize(cJSON *array)
{
	cJSON *c = array->child;
	int i = 0;
	while(c)
	{
		i++;
		c = c->next;
	}
	return i;
}

计算子节点数量。

修改节点

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 = NULL;
	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);
	}
}

就是链表的替换操作。

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

在指定位置插入节点,如果位置非法就在最后插入节点。

json字符串解析

json解析器

/* Default options for cJSON_Parse */
cJSON *cJSON_Parse(const char *value)
{
	return cJSON_ParseWithOpts(value, 0, 0);
}

/* Parse an object - create a new root, and populate. */
cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated)
{
	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 */
	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;
}

其中skip

/* Utility to jump whitespace and cr/lf */
static const char *skip(const char *in)
{
	while (in && *in && (unsigned char)*in <= 32)
	{
		in++;
	}
	return in;
}

就是跳过开头空白部分。
cJSON_ParseWithOpts的参数return_parse_end判断是否需要返回解析的尾,require_null_terminated判断是否需要以null结束。
函数里的ep可以用来提供错误信息,指向出错的字符串的位置。

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

然后就是parse_value函数了

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

根据前几个字符来判断写一个类型是什么。如果是 null, false 或 true 设置类型,并返回偏移指针。
如果是其他的,则进入对应的处理函数中。

解析字符串

/* Parse the input text into an unescaped cstring, and populate item. */
static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
static const char *parse_string(cJSON *item, const char *str)
{
	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)
	{
		if (*ptr++ == '\\')
		{
			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 = 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;
}

首先是遍历了一次整个string,统计出一共的字符个数,存在了len里,中间遇到转义的部分跳过了后面的字符。
然后申请足够数量的内存,重新从头遍历整个string,特殊处理转义的部分,也包括 utf8字符,这些字符在字符串中会编码为 \uXXXX 的字符串, 将他它还原为 0-255 的一个字符。

解析数字

/* Parse the input text to generate a number, and populate the result into item. */
static const char *parse_number(cJSON *item, const char *num)
{
	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 */
	
	item->valuedouble = n;
	item->valueint = (int)n;
	item->type = cJSON_Number;
	return num;
}

提取负号,去掉前导0,读取数字,有"."代表有小数位,有’e’/'E’表示为科学计数法。
最后通过number = +/- number.fraction * 10^+/- exponent式子计算出结果。

解析数组

/* Build an array from input text. */
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. */
}

先判断是否为数组,然后判断是否为空数组,申请空间,解析下一个节点,如果有",",继续解析,直道解析到数组尾部。

解析对象

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

先判断是否为对象,然后判断是否为空对象,申请空间,解析下一个节点(通过":“分割键和值对),如果有”,",继续解析,直道解析到对象尾部。

json序列化

/* Render a cJSON item/entity/structure to text. */
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);
}

cJSON_Print是格式化输出,
cJSON_PrintUnformatted是压缩输出,
cJSON_PrintBuffered是格式化输出,并且预先估计了输出字符串的大小。
其中看到了printbuffer,是一个输出字符串结构体:

typedef struct
{
	char *buffer;
	int length;
	int offset;
}
printbuffer;

buffer指向申请的空间,length为总长度,offset为使用的长度。
三个函数都是调用的print_value

/* Render a value to text. */
static char *print_value(cJSON *item, int depth, int fmt, printbuffer *p)
{
	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;
		}
	}
	return out;
}

其中ensure

static char* ensure(printbuffer *p, int needed)
{
	char *newbuffer;
	int newsize;
	if (!p || !p->buffer)
	{
		return 0;
	}
	needed += p->offset;
	if (needed <= p->length)
	{
		return p->buffer + p->offset;
	}
	newsize = pow2gt(needed);
	newbuffer = (char*)cJSON_malloc(newsize);
	if (!newbuffer)
	{
		cJSON_free(p->buffer);
		p->length = 0;
		p->buffer = 0;
		return 0;
	}
	if (newbuffer)
	{
		memcpy(newbuffer, p->buffer, p->length);
	]
	cJSON_free(p->buffer);
	p->length = newsize;
	p->buffer = newbuffer;
	return newbuffer + p->offset;
}

用来确保printbuffer剩余空间是否能容纳接下来的字符串,如果不能就扩容。
其中计算扩容大小的函数pow2gt

static int pow2gt(int x)
{
	--x;
	x |= x >> 1;
	x |= x >> 2;
	x |= x >> 4;
	x |= x >> 8;
	x |= x >> 16;
	return x + 1;
}

这函数就是计算的大于等于x的2的n次方,这也是cjson扩容的机制。

基本类型的输出就是字符串的复制,
Number的输出是先确定数字的范围,然后分配对应的大小,
String的输出主要是替换一些转义字符,
打印数组和对象就有一个深度的问题了,每次递归都会增加一层深度。

最后想吐槽一句,源代码的格式是真的不适合阅读。。。。

你可能感兴趣的:(c)