【转】cJSON 源码分析

时间:2023-03-09 03:17:31
【转】cJSON 源码分析

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具有的形式如下:

    对象是一个无序的“名称/值”对集合。一个对象以“{”(左括号)开始,“}”(右括号)结束。每个“名称”后跟一个“:”(冒号);“‘名称/值’”对之间使用“,”(逗号)分割。其具体形式如下图:

    【转】cJSON 源码分析

    数值是值(value)的有序集合。一个数组以“[”(左中括号)开始,“]”(右中括号)结束。值之间使用“,”(逗号)分割。其具体形式如下图:

    【转】cJSON 源码分析

    值(value)可以是双引号括起来的字符串(string)、数值(number)、true、false、null、对象(object)或者数组(array)。这些结构可以嵌套。其具体形式如下:

    【转】cJSON 源码分析

    字符串(string)是由双引号包围的任意数量Unicode字符的集合,使用反斜线转义。一个字符(character)即一个单独的字符馋(character string)。字符串(string)与C或者Java的字符串非常相似。其具体形式如下:

    【转】cJSON 源码分析

    数值(number)也与C或者Java的数值非常相似。除去未曾使用的八进制与十六进制格式。除去一些编码细节。其具体形式如下:

    【转】cJSON 源码分析

JSON格式举例如下:

  对象: 名称/值的集合
例:{"firstName":"Tom"}
数组: 值的序列
例:[, null, 0.231, -2.3E+5]
字符串:
例:"cJSON"
数字:
例:
布尔值:
例: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和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,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_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,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) + ;
    // 分配空间
    if (!(copy = (char*)cJSON_malloc(len)))
    return ;
    // 执行复制操作
    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,,);
    } // 解析对象,创建一个新的根并初始化,返回一个cJSON类型
    cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
    {
    const char *end=;
    cJSON *c=cJSON_New_Item();
    ep=;
    if (!c)
    return ; /* memory fail */ end=parse_value(c,skip(value));
    if (!end)
    {
    cJSON_Delete(c);
    return ;
    } /* 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 ;
    }
    }
    if (return_parse_end)
    *return_parse_end=end;
    return c;
    } // 解析器核心函数
    static const char *parse_value(cJSON *item,const char *value)
    {
    if (!value)
    return ; /* Fail on null. */
    if (!strncmp(value,"null",))
    {
    item->type=cJSON_NULL;
    return value+;
    }
    if (!strncmp(value,"false",))
    {
    item->type=cJSON_False;
    return value+;
    }
    if (!strncmp(value,"true",))
    {
    item->type=cJSON_True;
    item->valueint=;
    return value+;
    }
    if (*value=='\"')
    {
    return parse_string(item,value);
    }
    if (*value=='-' || (*value>='' && *value<=''))
    {
    return parse_number(item,value);
    }
    if (*value=='[')
    {
    return parse_array(item,value);
    }
    if (*value=='{')
    {
    return parse_object(item,value);
    } ep=value;
    return ; /* failure. */
    } static const char *parse_string(cJSON *item,const char *str)
    {
    const char *ptr=str+;
    char *ptr2;
    char *out;
    int len=;
    unsigned uc,uc2;
    if (*str!='\"') // 不是字符串情况
    {
    ep=str;
    return ;
    } /* not a string! */ while (*ptr!='\"' && *ptr && ++len)
    if (*ptr++ == '\\')
    ptr++; // 跳出前面的引用 out=(char*)cJSON_malloc(len+); /* This is how long we need for the string, roughly. */
    if (!out)
    return ; ptr=str+;
    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+);
    ptr+=; /* get the unicode char. */ if ((uc>=0xDC00 && uc<=0xDFFF) || uc==)
    break; /* check for invalid. */ if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */
    {
    if (ptr[]!='\\' || ptr[]!='u')
    break; /* missing second-half of surrogate. */
    uc2=parse_hex4(ptr+);ptr+=;
    if (uc2<0xDC00 || uc2>0xDFFF)
    break; /* invalid second-half of surrogate. */
    uc=0x10000 + (((uc&0x3FF)<<) | (uc2&0x3FF));
    } len=;
    if (uc<0x80)
    len=;
    else if (uc<0x800)
    len=;
    else if (uc<0x10000)
    len=;
    ptr2+=len; switch (len)
    {
    case : *--ptr2 =((uc | 0x80) & 0xBF); uc >>= ;
    case : *--ptr2 =((uc | 0x80) & 0xBF); uc >>= ;
    case : *--ptr2 =((uc | 0x80) & 0xBF); uc >>= ;
    case : *--ptr2 =(uc | firstByteMark[len]);
    }
    ptr2+=len;
    break;
    default: *ptr2++=*ptr; break;
    }
    ptr++;
    }
    }
    *ptr2=;
    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<=)
    in++;
    return in;
    } // parse_number函数功能:解析数字,对输入的文本生成一个数字,并填充结果项,传入参数有两
    // 个,这里先只关注num,返回值是一个字符串
    static const char *parse_number(cJSON *item,const char *num)
    {
    double n=,sign=,scale=;
    int subscale=,signsubscale=; if (*num=='-') sign=-,num++; // 判断数字是否是有符号数字
    if (*num=='') num++; // 判断数字是否为0
    if (*num>='' && *num<='')
    do // 转换数字
    n=(n*10.0)+(*num++ -'');
    while (*num>='' && *num<='');
    if (*num=='.' && num[]>='' && num[]<='') // 对小数点后边的部分进行处理,scale记录小数点后边的位数
    {
    num++;
    do
    n=(n*10.0)+(*num++ -''),scale--; // scale为小数点后的位数
    while (*num>='' && *num<='');
    }
    if (*num=='e' || *num=='E') // 是否为指数,科学计数法
    {
    num++;
    if (*num=='+') // 判断指数后边幂的正负号
    num++;
    else if (*num=='-')
    signsubscale=-,num++;
    while (*num>='' && *num<='') // 处理指数后边10的幂
    subscale=(subscale*)+(*num++ - '');
    }
    // 将字符串转换为相应的数值
    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 ;} /* not an array! */ item->type=cJSON_Array;
    value=skip(value+);
    if (*value==']') return value+; /* empty array. */ item->child=child=cJSON_New_Item();
    if (!item->child) return ; /* memory fail */
    value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */
    if (!value) return ; while (*value==',')
    {
    cJSON *new_item;
    if (!(new_item=cJSON_New_Item())) return ; /* memory fail */
    child->next=new_item;new_item->prev=child;child=new_item;
    value=skip(parse_value(child,skip(value+)));
    if (!value) return ; /* memory fail */
    } if (*value==']') return value+; /* end of array */
    ep=value;return ; /* malformed. */
    } // 从输入文本中构建object
    static const char *parse_object(cJSON *item,const char *value)
    {
    cJSON *child;
    if (*value!='{') {ep=value;return ;} /* not an object! */ item->type=cJSON_Object;
    value=skip(value+);
    if (*value=='}') return value+; /* empty array. */ item->child=child=cJSON_New_Item();
    if (!item->child) return ;
    value=skip(parse_string(child,skip(value)));
    if (!value) return ;
    child->string=child->valuestring;child->valuestring=;
    if (*value!=':') {ep=value;return ;} /* fail! */
    value=skip(parse_value(child,skip(value+))); /* skip any spacing, get the value. */
    if (!value) return ; while (*value==',')
    {
    cJSON *new_item;
    if (!(new_item=cJSON_New_Item())) return ; /* memory fail */
    child->next=new_item;new_item->prev=child;child=new_item;
    value=skip(parse_string(child,skip(value+)));
    if (!value) return ;
    child->string=child->valuestring;child->valuestring=;
    if (*value!=':') {ep=value;return ;} /* fail! */
    value=skip(parse_value(child,skip(value+))); /* skip any spacing, get the value. */
    if (!value) return ;
    } if (*value=='}') return value+; /* end of array */
    ep=value;return ; /* malformed. */
    } // 将十六进制的字符串转换为数字表示!
    static unsigned parse_hex4(const char *str)
    {
    unsigned h=;
    if (*str>='' && *str<='')
    h+=(*str)-'';
    else if (*str>='A' && *str<='F')
    h+=+(*str)-'A';
    else if (*str>='a' && *str<='f')
    h+=+(*str)-'a';
    else
    return ;
    h=h<<;str++;
    if (*str>='' && *str<='')
    h+=(*str)-'';
    else if (*str>='A' && *str<='F')
    h+=+(*str)-'A';
    else if (*str>='a' && *str<='f')
    h+=+(*str)-'a';
    else
    return ;
    h=h<<;str++;
    if (*str>='' && *str<='')
    h+=(*str)-'';
    else if (*str>='A' && *str<='F')
    h+=+(*str)-'A';
    else if (*str>='a' && *str<='f')
    h+=+(*str)-'a';
    else
    return ;
    h=h<<;str++;
    if (*str>='' && *str<='')
    h+=(*str)-'';
    else if (*str>='A' && *str<='F')
    h+=+(*str)-'A';
    else if (*str>='a' && *str<='f')
    h+=+(*str)-'a';
    else
    return ;
    return h;
    } 打印JSON信息 // 打印值到文本
    static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p)
    {
    char *out=;
    if (!item) return ;
    if (p)
    {
    switch ((item->type)&)
    {
    case cJSON_NULL: {out=ensure(p,); if (out) strcpy(out,"null"); break;}
    case cJSON_False: {out=ensure(p,); if (out) strcpy(out,"false"); break;}
    case cJSON_True: {out=ensure(p,); 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)&)
    {
    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,);break;
    case cJSON_String: out=print_string(item,);break;
    case cJSON_Array: out=print_array(item,depth,fmt,);break;
    case cJSON_Object: out=print_object(item,depth,fmt,);break;
    }
    }
    return out;
    } // 打印array到文本
    static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p)
    {
    char **entries;
    char *out=,*ptr,*ret;int len=;
    cJSON *child=item->child;
    int numentries=,i=,fail=;
    size_t tmplen=; /* How many entries in the array? */
    while (child) numentries++,child=child->next;
    /* Explicitly handle numentries==0 */
    if (!numentries)
    {
    if (p) out=ensure(p,);
    else out=(char*)cJSON_malloc();
    if (out) strcpy(out,"[]");
    return out;
    } if (p)
    {
    /* Compose the output array. */
    i=p->offset;
    ptr=ensure(p,);if (!ptr) return ; *ptr='['; p->offset++;
    child=item->child;
    while (child && !fail)
    {
    print_value(child,depth+,fmt,p);
    p->offset=update(p);
    if (child->next) {len=fmt?:;ptr=ensure(p,len+);if (!ptr) return ;*ptr++=',';if(fmt)*ptr++=' ';*ptr=;p->offset+=len;}
    child=child->next;
    }
    ptr=ensure(p,);if (!ptr) return ; *ptr++=']';*ptr=;
    out=(p->buffer)+i;
    }
    else
    {
    /* Allocate an array to hold the values for each */
    entries=(char**)cJSON_malloc(numentries*sizeof(char*));
    if (!entries) return ;
    memset(entries,,numentries*sizeof(char*));
    /* Retrieve all the results: */
    child=item->child;
    while (child && !fail)
    {
    ret=print_value(child,depth+,fmt,);
    entries[i++]=ret;
    if (ret) len+=strlen(ret)++(fmt?:); else fail=;
    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=; /* Handle failure. */
    if (fail)
    {
    for (i=;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
    cJSON_free(entries);
    return ;
    } /* Compose the output array. */
    *out='[';
    ptr=out+;*ptr=;
    for (i=;i<numentries;i++)
    {
    tmplen=strlen(entries[i]);memcpy(ptr,entries[i],tmplen);ptr+=tmplen;
    if (i!=numentries-) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=;}
    cJSON_free(entries[i]);
    }
    cJSON_free(entries);
    *ptr++=']';*ptr++=;
    }
    return out;
    } // 打印object到文本中
    static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p)
    {
    char **entries=,**names=;
    char *out=,*ptr,*ret,*str;int len=,i=,j;
    cJSON *child=item->child;
    int numentries=,fail=;
    size_t tmplen=;
    /* 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+:);
    else out=(char*)cJSON_malloc(fmt?depth+:);
    if (!out) return ;
    ptr=out;*ptr++='{';
    if (fmt) {*ptr++='\n';for (i=;i<depth-;i++) *ptr++='\t';}
    *ptr++='}';*ptr++=;
    return out;
    }
    if (p)
    {
    /* Compose the output: */
    i=p->offset;
    len=fmt?:; ptr=ensure(p,len+); if (!ptr) return ;
    *ptr++='{'; if (fmt) *ptr++='\n'; *ptr=; p->offset+=len;
    child=item->child;depth++;
    while (child)
    {
    if (fmt)
    {
    ptr=ensure(p,depth); if (!ptr) return ;
    for (j=;j<depth;j++) *ptr++='\t';
    p->offset+=depth;
    }
    print_string_ptr(child->string,p);
    p->offset=update(p); len=fmt?:;
    ptr=ensure(p,len); if (!ptr) return ;
    *ptr++=':';if (fmt) *ptr++='\t';
    p->offset+=len; print_value(child,depth,fmt,p);
    p->offset=update(p); len=(fmt?:)+(child->next?:);
    ptr=ensure(p,len+); if (!ptr) return ;
    if (child->next) *ptr++=',';
    if (fmt) *ptr++='\n';*ptr=;
    p->offset+=len;
    child=child->next;
    }
    ptr=ensure(p,fmt?(depth+):); if (!ptr) return ;
    if (fmt) for (i=;i<depth-;i++) *ptr++='\t';
    *ptr++='}';*ptr=;
    out=(p->buffer)+i;
    }
    else
    {
    /* Allocate space for the names and the objects */
    entries=(char**)cJSON_malloc(numentries*sizeof(char*));
    if (!entries) return ;
    names=(char**)cJSON_malloc(numentries*sizeof(char*));
    if (!names) {cJSON_free(entries);return ;}
    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,);
    entries[i++]=ret=print_value(child,depth,fmt,);
    if (str && ret) len+=strlen(ret)+strlen(str)++(fmt?+depth:); else fail=;
    child=child->next;
    } /* Try to allocate the output string */
    if (!fail) out=(char*)cJSON_malloc(len);
    if (!out) fail=; /* Handle failure */
    if (fail)
    {
    for (i=;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}
    cJSON_free(names);cJSON_free(entries);
    return ;
    } /* Compose the output: */
    *out='{';ptr=out+;if (fmt)*ptr++='\n';*ptr=;
    for (i=;i<numentries;i++)
    {
    if (fmt) for (j=;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-) *ptr++=',';
    if (fmt) *ptr++='\n';*ptr=;
    cJSON_free(names[i]);cJSON_free(entries[i]);
    } cJSON_free(names);cJSON_free(entries);
    if (fmt) for (i=;i<depth-;i++) *ptr++='\t';
    *ptr++='}';*ptr++=;
    }
    return out;
    }

    其余函数信息如下:

     // 返回节点的个数
    int cJSON_GetArraySize(cJSON *array)
    {
    cJSON *c=array->child;
    int i=;
    while(c)
    i++,c=c->next;
    return i;
    }
    // 返回array中第item个节点的地址
    cJSON *cJSON_GetArrayItem(cJSON *array,int item)
    {
    cJSON *c=array->child;
    while (c && item>)
    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>)
    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>)
    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=;
    // 删除替换的节点
    cJSON_Delete(c);
    }
    // 替换节点操作
    // 用原有节点替换现有节点
    void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem)
    {
    int i=;
    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=,*p=,*a=cJSON_CreateArray();
    for(i=;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=,*p=,*a=cJSON_CreateArray();
    for(i=;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=,*p=,*a=cJSON_CreateArray();
    for(i=;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=,*p=,*a=cJSON_CreateArray();
    for(i=;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=,*newchild;
    /* Bail on bad ptr */
    if (!item)
    return ;
    /* Create new item */
    newitem=cJSON_New_Item();
    if (!newitem)
    return ;
    /* 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 ;
    }
    }
    if (item->string)
    {
    newitem->string=cJSON_strdup(item->string);
    if (!newitem->string)
    {
    cJSON_Delete(newitem);
    return ;
    }
    }
    /* 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,); /* Duplicate (with recurse) each item in the ->next chain */
    if (!newchild)
    {
    cJSON_Delete(newitem);
    return ;
    }
    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[]=='/') while (*json && *json!='\n') json++; /* double-slash comments, to end of line. */
    else if (*json=='/' && json[]=='*') {while (*json && !(*json=='*' && json[]=='/')) json++;json+=;} /* 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=; /* 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/

原文出处