cJSON源码分析
简介
由于C语言汇总,没有直接的字典,字符串数组等数据结构,所以要借助结构体定义,处理json。
JSON是一种轻量级的数据交换格式。JSON采用完全独立与语言的文本格式,易于人阅读和编写。同时也易于机器解析和生成。它是基于JavaScript,Programming Language,Standard ECMA-262 3rd Edition -December 1999的一个子集。JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(如C,C++,C++,JavaScript,Perl,Python等)。这些特性使用JSON成为理想的数据交换语言。
JSON作用:在数据传输时能够更好地提取出需要的数据,可以用于客户端和服务器端的数据交互。
JSON建构与两种结构:
- “名称/值”对的集合。不同的语言中,它被理解为对象(Object),记录(Record),结构(struct),字典(dictionary),哈希表(hash table),有键列表(Key list),或者关联数组(Associative array)。
- 值的有序列表(An ordered list of values)。在大部分语言中,它被理解为数组(array)。
JSON的结构可以理解成无序的、可嵌套的key-value键值对集合,这些key-value键值对是以结构体或数组的形式来组织的。同一级的key-value键值对之间是用以个“,”(逗号)隔开,每个key-value键值对是由一个key后面紧接一个“:”(冒号),冒号后面是这个key对应的value。Key是一个word,由大小写字母、下划线及数字组成,可以由双引号封闭,也可以不加双引号;而value值的取值为:字符串(string),数值(number),true,false,null,对象(object)或者数组(array)。这些结构可以嵌套。
实质:JSON是一种信息交换格式,而cJSON就是对JSON格式的字符串进行构建和解析的一个C语言函数库。此外,cJSON作为JSON格式的解析库,其主要功能就是构建和解析JSON格式。
JSON具有的形式如下:
对象是一个无序的“名称/值”对集合。一个对象以“{”(左括号)开始,“}”(右括号)结束。每个“名称”后跟一个“:”(冒号);“‘名称/值’”对之间使用“,”(逗号)分割。其具体形式如下图:
数值是值(value)的有序集合。一个数组以“[”(左中括号)开始,“]”(右中括号)结束。值之间使用“,”(逗号)分割。其具体形式如下图:
值(value)可以是双引号括起来的字符串(string)、数值(number)、true、false、null、对象(object)或者数组(array)。这些结构可以嵌套。其具体形式如下:
字符串(string)是由双引号包围的任意数量Unicode字符的集合,使用反斜线转义。一个字符(character)即一个单独的字符馋(character string)。字符串(string)与C或者Java的字符串非常相似。其具体形式如下:
数值(number)也与C或者Java的数值非常相似。除去未曾使用的八进制与十六进制格式。除去一些编码细节。其具体形式如下:
JSON格式举例如下:
对象: 名称/值的集合 例:{"firstName":"Tom"} 数组: 值的序列 例:[310,null,0.231,-2.3E+5] 字符串: 例:"cJSON" 数字: 例:500 布尔值: 例:true false
cJSON源码分析
1)cJSON源码下载,网址为: http://sourceforge.net/projects/cjson/。
2)解压后,主要参看的源码文件为cJSON.h和sJSON.c和test.c,其中test.c为测试函数。
由于cJSON为JSON格式的解析库,故主要功能是构建和解析JSON格式。其中的结构体,函数定义实现等都是围绕这两个函数实现。下面将对其源码进行分析。
JSON的内存结构不是树,像广义表,可以认为是有层次的双向链表。
cJSON中的重要接口函数如下:
解析函数 cJSON * cJSON_Parse(const char *value); 打印函数 char * cJSON_Print(cJSON * item); 删除函数 void cJSON_Delete(cJSON * c); 构造函数 create系列和add系列 解析字符串 char *parse_string(cJSON*item,const char *str) 解析数字 char *parse_number(cJSON *item,const char *num) 解析数组 char *parse_array(cJSON *item,const char *value) 解析对象 char *parse_object(cJSON *item,const char *value) ......
cJSON程序中的细节点如下:
CJSON的节点结构体如下:
// JSON的一个value的结构体 typedef struct cJSON { struct cJSON *next,*prev; // 同一级的元素使用双向列表存储 struct cJSON *child; // 如果是一个object或array的话,child为第一个儿子的指针 int type; // value的类型 char *valuestring; // 如果这个value是字符串类型,则此处为字符串值 int valueint; // 如果是数字的话,整数值 double valuedouble; // 如果是数字的话,读点数值 char *string; // 如果是对象的key-value元素的话,key值 } cJSON; // JSON的类型 #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中的内存管理使用了HOOK技术,主要是为了方便使用者自己定义内存管理函数,即用户自定义的malloc和free。下面对其内存管理相关程序分析。
// json内存管理 // 为方便用户自由的管理内存,其使用了Hook技术让使用者可以自定义内存管理函数 typedef struct cJSON_Hooks { void *(*malloc_fn)(size_t sz); void (*free_fn)(void *ptr); } cJSON_Hooks; // 对cJSON提供的分配,再分配,释放内存初始化函数 extern void cJSON_InitHooks(cJSON_Hooks* hooks); // 默认将分配和释放空间函数指针指向malloc和free static void *(*cJSON_malloc)(size_t sz) = malloc; static void (*cJSON_free)(void *ptr) = free; // 其使用Hook技术来让使用者可以自定义内存管理函数。其中默认系统使用的内存分配和释放函数是malloc // 和free函数,利用cJSON_InitHooks函数可以替换成用户自定义的malloc和free函数。 void cJSON_InitHooks(cJSON_Hooks* hooks) { // 如果未定义,则使用默认的malloc和free函数 if (!hooks) { /* Reset hooks */ cJSON_malloc = malloc; cJSON_free = free; return; } // 定义了,则使用用户自定义的malloc和free函数 cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc; cJSON_free = (hooks->free_fn)?hooks->free_fn:free; }
构建JSON格式数据,首先调用CJSON_CreateObject()函数,返回一个类型为cJSON_Object的cJSON的结构体,这其中调用了CJSON_CreateNULL()、CJSON_CreateTrue()、…、创建不同类型数据的CJSON结构其。在构建过程中,调用CJSON_New_Item创建对应节点信息;然后调用cJSON_AddItemToObject()并结合不同的对象类型增加节点名称和子节点。然后在其中调用cJSON_AddItemToArray()函数来添加信息,此函数中判断对象孩子结点是否为NULL,如果是NULL,则直接插入,否则找到最后一个孩子,调用suffix_object()函数添加到双向链表的尾部。具体程序如下。
// 利用宏函数来快速增加cJSON相关节点信息 // 创建一个string值为name的cJSON_Null节点,并添加到object #define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object,name,cJSON_CreateNull()) // 创建一个string值为name的cJSON_True节点,并添加到object #define cJSON_AddTrueToObject(object,cJSON_CreateTrue()) // 创建一个string值为name的cJSON_False节点,并添加到object #define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object,cJSON_CreateFalse()) // 创建一个string值为name的cJSON_CreateBool节点,并添加到object。b非0为cJSON_True,0为cJSON_False。 #define cJSON_AddBoolToObject(object,b) cJSON_AddItemToObject(object,cJSON_CreateBool(b)) // 创建一个string值为name,valuedouble为n,valueint为(int)n的cJSON_Number节点,并添加到object。 #define cJSON_AddNumberToObject(object,n) cJSON_AddItemToObject(object,cJSON_CreateNumber(n)) // 创建一个string值为name,valuestring为s的cJSON_String节点,并添加到object。 #define cJSON_AddStringToObject(object,s) cJSON_AddItemToObject(object,cJSON_CreateString(s)) // 函数解析 // 输入参数无 // 返回值:指向一个cJSON_Object类型节点的指针 // 创建一个cJSON节点,并设置节点类型无cJSON_Object extern cJSON *cJSON_CreateObject(void); cJSON *cJSON_CreateObject(void) { // 创建节点 cJSON *item=cJSON_New_Item(); if(item) item->type=cJSON_Object; return item; } // 创建value节点 static cJSON *cJSON_New_Item(void) { // 分配空间 cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); // 分配成功后,初始化为0 if (node) memset(node,sizeof(cJSON)); return node; } // object(cJSON *):被添加节点的节点 // string(char *):要添加节点的名称 // item(cJSON *):要添加节点 // 返回值无 // 函数功能:将item节点的名称设置为string。如果object节点没有子节点,就将item设置为object // 子节点,否则将item添加到object->child链表的尾部,成为object->child的兄弟节点 extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); // 将字符串添加进对象 void cJSON_AddItemToObject(cJSON *object,cJSON *item) { if (!item) return; if (item->string) cJSON_free(item->string); // 这个儿子之前有key,先清理 item->string=cJSON_strdup(string); // 设置key值 cJSON_AddItemToArray(object,item); // 添加儿子 } // 将传入的字符串复制一副本并返回新的字符串指针 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; } // 添加节点到object或array中 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); // 添加儿子,c是item的兄弟节点 } } // array的处理 static void suffix_object(cJSON *prev,cJSON *item) { // 两个兄弟的指针互相指向对方 prev->next=item; item->prev=prev; }
首选,调用cJSON_Parse()函数,此函数是一个二次封装函数,其内部为cJSON_ParseWithOpts()函数,该函数用于提取更多的解析选项,如果需要,最后返回解析结束的位置。而在上面的函数中,调用parse_value()函数进行解析,而该函数首先创建cJSON_NewItem()创建节点,用于存放解析的JSON结构数据,然后根据不同的选项,调用解析函数,其为parse_string(),parse_number(),parse_array(),parse_objec()等。其程序解析如下:
// cJSON解析的二次封装函数 cJSON *cJSON_Parse(const char *value) { return cJSON_ParseWithOpts(value,0); } // 解析对象,创建一个新的根并初始化,返回一个cJSON类型 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; } // 解析器核心函数 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. */ } 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++; // 跳出前面的引用 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; } // 跳过这些空格 static const char *skip(const char *in) { while (in && *in && (unsigned char)*in<=32) in++; return in; } // parse_number函数功能:解析数字,对输入的文本生成一个数字,并填充结果项,传入参数有两 // 个,这里先只关注num,返回值是一个字符串 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++; // 判断数字是否是有符号数字 if (*num=='0') num++; // 判断数字是否为0 if (*num>='1' && *num<='9') do // 转换数字 n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); if (*num=='.' && num[1]>='0' && num[1]<='9') // 对小数点后边的部分进行处理,scale记录小数点后边的位数 { num++; do n=(n*10.0)+(*num++ -'0'),scale--; // scale为小数点后的位数 while (*num>='0' && *num<='9'); } if (*num=='e' || *num=='E') // 是否为指数,科学计数法 { num++; if (*num=='+') // 判断指数后边幂的正负号 num++; else if (*num=='-') signsubscale=-1,num++; while (*num>='0' && *num<='9') // 处理指数后边10的幂 subscale=(subscale*10)+(*num++ - '0'); } // 将字符串转换为相应的数值 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; } // 从输入文本中构建array 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. */ } // 从输入文本中构建object 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,') { 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,get the value. */ if (!value) return 0; } if (*value=='}') return value+1; /* end of array */ ep=value;return 0; /* malformed. */ } // 将十六进制的字符串转换为数字表示! static unsigned parse_hex4(const char *str) { 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++; 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; } 打印JSON信息 // 打印值到文本 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,"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,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,0);break; case cJSON_Object: out=print_object(item,0);break; } } return out; } // 打印array到文本 static char *print_array(cJSON *item,printbuffer *p) { 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 */ 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,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,numentries*sizeof(char*)); /* Retrieve all the results: */ child=item->child; while (child && !fail) { ret=print_value(child,0); entries[i++]=ret; if (ret) 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; } // 打印object到文本中 static char *print_object(cJSON *item,printbuffer *p) { char **entries=0,**names=0; char *out=0,*ret,*str;int len=7,j; cJSON *child=item->child; int numentries=0,fail=0; size_t tmplen=0; /* 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); 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';} *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,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,sizeof(char*)*numentries); memset(names,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); entries[i++]=ret=print_value(child,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; }
其余函数信息如下:
// 返回节点的个数 int cJSON_GetArraySize(cJSON *array) { cJSON *c=array->child; int i=0; while(c) i++,c=c->next; return i; } // 返回array中第item个节点的地址 cJSON *cJSON_GetArrayItem(cJSON *array,int item) { cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c; } // 返回Object中第item个节点的地址 cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) { cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c; } // 在链表中插入一个新的节点 void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem) { cJSON *c=array->child; // 找到which位置 while (c && which>0) c=c->next,which--; // 添加新的节点到array中 if (!c) { cJSON_AddItemToArray(array,newitem); return; } // 将链表节点进行挂接 newitem->next=c; newitem->prev=c->prev; c->prev=newitem; // 处理arrya的孩子节点 if (c==array->child) array->child=newitem; else newitem->prev->next=newitem; } // 替换节点操作,用新的节点替换原有的某一个节点 void cJSON_ReplaceItemInArray(cJSON *array,cJSON *newitem) { cJSON *c=array->child; // 找到which位置 while (c && which>0) c=c->next,which--; if (!c) return; // 进行挂接 newitem->next=c->next; newitem->prev=c->prev; // 处理NULL情况 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,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) { cJSON *item=cJSON_New_Item(); if(item) item->type=cJSON_Object; return item; } /* Create Arrays: */ // 创建array 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,n); p=n; } return a; } cJSON *cJSON_CreateDoubleArray(const double *numbers,n); p=n; } return a; } cJSON *cJSON_CreateStringArray(const char **strings,*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. */ }
参考文献
http://www.0xffffff.org/2014/02/10/29-cjson-analyse/
http://github.tiankonguse.com/blog/2014/12/18/cjson-source.html