cJSON源码分析

来源:互联网 发布:linux黑客技术 编辑:程序博客网 时间:2024/06/04 15:08

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程序中的细节点如下:

    • 大量宏替换
    • 大量静态函数
    • 错误处理机制
    • 字符串处理时存在utf16转utf9,编码转换
    • 用函数指针封装malloc,free,方便用于处理,比如在申请后初始化,或者释放前进行一些处理等。

    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和freestatic 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,name)      cJSON_AddItemToObject(object, name, cJSON_CreateTrue())// 创建一个string值为name的cJSON_False节点,并添加到object#define cJSON_AddFalseToObject(object,name)     cJSON_AddItemToObject(object, name, cJSON_CreateFalse())// 创建一个string值为name的cJSON_CreateBool节点,并添加到object。b非0为cJSON_True,0为cJSON_False。#define cJSON_AddBoolToObject(object,name,b)    cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))// 创建一个string值为name,valuedouble为n,valueint为(int)n的cJSON_Number节点,并添加到object。#define cJSON_AddNumberToObject(object,name,n)  cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))// 创建一个string值为name,valuestring为s的cJSON_String节点,并添加到object。#define cJSON_AddStringToObject(object,name,s)  cJSON_AddItemToObject(object, name, cJSON_CreateString(s))// 函数解析// 输入参数无// 返回值:指向一个cJSON_Object类型节点的指针// 创建一个cJSON节点,并设置节点类型无cJSON_Objectextern 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,0,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,const char *string,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;}

    JSON解析数据格式时所调用的函数过程如下:

    首选,调用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,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;}// 从输入文本中构建arraystatic 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. */}// 从输入文本中构建objectstatic 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. */}// 将十六进制的字符串转换为数字表示!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,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;}// 打印array到文本static char *print_array(cJSON *item,int depth,int fmt,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,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) 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,int depth,int fmt,printbuffer *p){    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;    /* 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,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);            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;}

    其余函数信息如下:

    // 返回节点的个数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,int which,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,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){    cJSON *item=cJSON_New_Item();    if(item)        item->type=cJSON_Object;    return item;}/* Create Arrays: */// 创建arraycJSON *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;}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. */}
  • 参考文献

    http://www.0xffffff.org/2014/02/10/29-cjson-analyse/

    http://github.tiankonguse.com/blog/2014/12/18/cjson-source.html

    http://www.codexiu.cn/javascript/blog/21402/

    http://www.json.org/

1 0
原创粉丝点击