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

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

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

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

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

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

JSON格式举例如下:

 1  对象: 名称/值的集合
 2     例:{"firstName":"Tom"}
 3     数组: 值的序列
 4         例:[310, null, 0.231, -2.3E+5]
 5     字符串:
 6         例:"cJSON"
 7     数字:
 8         例:500
 9     布尔值:
10         例:true false
  • cJSON源码分析

    1)cJSON源码下载,网址为: http://sourceforge.net/projects/cjson/

    2)解压后,主要参看的源码文件为cJSON.h和sJSON.c和test.c,其中test.c为测试函数。

    由于cJSON为JSON格式的解析库,故主要功能是构建和解析JSON格式。其中的结构体,函数定义实现等都是围绕这两个函数实现。下面将对其源码进行分析。

    JSON的内存结构不是树,像广义表,可以认为是有层次的双向链表。

    cJSON中的重要接口函数如下:

     1 解析函数
     2 cJSON * cJSON_Parse(const char *value);
     3 打印函数
     4 char * cJSON_Print(cJSON * item);
     5 删除函数
     6 void  cJSON_Delete(cJSON * c);
     7 构造函数
     8 create系列和add系列
     9 解析字符串
    10 char *parse_string(cJSON*item,const char *str)
    11 解析数字
    12 char *parse_number(cJSON *item,const char *num)
    13 解析数组
    14 char *parse_array(cJSON *item,const char *value)
    15 解析对象
    16 char *parse_object(cJSON *item,const char *value)
    17 ......
  • cJSON程序中的细节点如下:

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

    CJSON的节点结构体如下:

     1 // JSON的一个value的结构体
     2 typedef struct cJSON
     3 {
     4     struct cJSON *next,*prev;    // 同一级的元素使用双向列表存储
     5     struct cJSON *child;           // 如果是一个object或array的话,child为第一个儿子的指针
     6 
     7     int type;                            // value的类型
     8 
     9     char *valuestring;             // 如果这个value是字符串类型,则此处为字符串值
    10     int valueint;                      // 如果是数字的话,整数值
    11     double valuedouble;            // 如果是数字的话,读点数值
    12 
    13     char *string;                      // 如果是对象的key-value元素的话,key值
    14 } cJSON;
    15 
    16 // JSON的类型
    17 #define cJSON_False 0
    18 #define cJSON_True 1
    19 #define cJSON_NULL 2
    20 #define cJSON_Number 3
    21 #define cJSON_String 4
    22 #define cJSON_Array 5
    23 #define cJSON_Object 6
    24 
    25 #define cJSON_IsReference 256
    26 #define cJSON_StringIsConst 512

    cJSON中的内存管理使用了HOOK技术,主要是为了方便使用者自己定义内存管理函数,即用户自定义的malloc和free。下面对其内存管理相关程序分析。

     1 // json内存管理
     2 // 为方便用户自由的管理内存,其使用了Hook技术让使用者可以自定义内存管理函数
     3 typedef struct cJSON_Hooks
     4 {
     5   void *(*malloc_fn)(size_t sz);
     6   void (*free_fn)(void *ptr);
     7 } cJSON_Hooks;
     8 
     9 // 对cJSON提供的分配,再分配,释放内存初始化函数
    10 extern void cJSON_InitHooks(cJSON_Hooks* hooks);
    11 
    12 // 默认将分配和释放空间函数指针指向malloc和free
    13 static void *(*cJSON_malloc)(size_t sz) = malloc;
    14 static void (*cJSON_free)(void *ptr) = free;
    15 // 其使用Hook技术来让使用者可以自定义内存管理函数。其中默认系统使用的内存分配和释放函数是malloc
    16 // 和free函数,利用cJSON_InitHooks函数可以替换成用户自定义的malloc和free函数。
    17 void cJSON_InitHooks(cJSON_Hooks* hooks)
    18 {
    19         // 如果未定义,则使用默认的malloc和free函数
    20     if (!hooks) { /* Reset hooks */
    21         cJSON_malloc = malloc;
    22         cJSON_free = free;
    23         return;
    24     }
    25     // 定义了,则使用用户自定义的malloc和free函数
    26     cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
    27     cJSON_free   = (hooks->free_fn)?hooks->free_fn:free;
    28 }

    构建JSON格式数据,首先调用CJSON_CreateObject()函数,返回一个类型为cJSON_Object的cJSON的结构体,这其中调用了CJSON_CreateNULL()、CJSON_CreateTrue()、…、创建不同类型数据的CJSON结构其。在构建过程中,调用CJSON_New_Item创建对应节点信息;然后调用cJSON_AddItemToObject()并结合不同的对象类型增加节点名称和子节点。然后在其中调用cJSON_AddItemToArray()函数来添加信息,此函数中判断对象孩子结点是否为NULL,如果是NULL,则直接插入,否则找到最后一个孩子,调用suffix_object()函数添加到双向链表的尾部。具体程序如下。

     1 // 利用宏函数来快速增加cJSON相关节点信息
     2 // 创建一个string值为name的cJSON_Null节点,并添加到object
     3 #define cJSON_AddNullToObject(object,name)      cJSON_AddItemToObject(object, name, cJSON_CreateNull())
     4 // 创建一个string值为name的cJSON_True节点,并添加到object
     5 #define cJSON_AddTrueToObject(object,name)      cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
     6 // 创建一个string值为name的cJSON_False节点,并添加到object
     7 #define cJSON_AddFalseToObject(object,name)     cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
     8 // 创建一个string值为name的cJSON_CreateBool节点,并添加到object。b非0为cJSON_True,0为cJSON_False。
     9 #define cJSON_AddBoolToObject(object,name,b)    cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
    10 // 创建一个string值为name,valuedouble为n,valueint为(int)n的cJSON_Number节点,并添加到object。
    11 #define cJSON_AddNumberToObject(object,name,n)  cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
    12 // 创建一个string值为name,valuestring为s的cJSON_String节点,并添加到object。
    13 #define cJSON_AddStringToObject(object,name,s)  cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
    14 
    15 // 函数解析
    16 // 输入参数无
    17 // 返回值:指向一个cJSON_Object类型节点的指针
    18 // 创建一个cJSON节点,并设置节点类型无cJSON_Object
    19 extern cJSON *cJSON_CreateObject(void);
    20 
    21 cJSON *cJSON_CreateObject(void)
    22 {
    23     // 创建节点
    24     cJSON *item=cJSON_New_Item();
    25     if(item)
    26         item->type=cJSON_Object;
    27     return item;
    28 }
    29 
    30 // 创建value节点
    31 static cJSON *cJSON_New_Item(void)
    32 {
    33     // 分配空间
    34     cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
    35     // 分配成功后,初始化为0
    36     if (node) memset(node,0,sizeof(cJSON));
    37     return node;
    38 }
    39 
    40 // object(cJSON *):被添加节点的节点
    41 // string(char *):要添加节点的名称
    42 // item(cJSON *):要添加节点
    43 // 返回值无
    44 // 函数功能:将item节点的名称设置为string。如果object节点没有子节点,就将item设置为object
    45 // 子节点,否则将item添加到object->child链表的尾部,成为object->child的兄弟节点
    46 extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
    47 
    48 // 将字符串添加进对象
    49 void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item)
    50 {
    51     if (!item)
    52      return;
    53     if (item->string)
    54         cJSON_free(item->string);         // 这个儿子之前有key,先清理
    55     item->string=cJSON_strdup(string);    // 设置key值
    56     cJSON_AddItemToArray(object,item);    // 添加儿子
    57 }
    58 
    59 // 将传入的字符串复制一副本并返回新的字符串指针
    60 static char* cJSON_strdup(const char* str)
    61 {
    62       size_t len;
    63       char* copy;
    64 
    65       len = strlen(str) + 1;
    66             // 分配空间
    67       if (!(copy = (char*)cJSON_malloc(len)))
    68                 return 0;
    69             // 执行复制操作
    70       memcpy(copy,str,len);
    71             // 返回复制的副本
    72       return copy;
    73 }
    74 
    75 // 添加节点到object或array中
    76 void cJSON_AddItemToArray(cJSON *array, cJSON *item)
    77 {
    78     cJSON *c=array->child;
    79     if (!item)
    80         return;
    81     if (!c)
    82     {
    83         array->child=item;     // 之前不存在儿子节点,直接添加
    84     }
    85     else
    86     {
    87         while (c && c->next)   // 先找到最后一个儿子
    88             c=c->next;
    89         suffix_object(c,item); // 添加儿子,c是item的兄弟节点
    90     }
    91 }
    92 
    93 // array的处理
    94 static void suffix_object(cJSON *prev,cJSON *item)
    95 {
    96     // 两个兄弟的指针互相指向对方
    97     prev->next=item;
    98     item->prev=prev;
    99 }

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

    首选,调用cJSON_Parse()函数,此函数是一个二次封装函数,其内部为cJSON_ParseWithOpts()函数,该函数用于提取更多的解析选项,如果需要,最后返回解析结束的位置。而在上面的函数中,调用parse_value()函数进行解析,而该函数首先创建cJSON_NewItem()创建节点,用于存放解析的JSON结构数据,然后根据不同的选项,调用解析函数,其为parse_string(),parse_number(),parse_array(),parse_objec()等。其程序解析如下:

      1 // cJSON解析的二次封装函数
      2 cJSON *cJSON_Parse(const char *value)
      3 {
      4     return cJSON_ParseWithOpts(value,0,0);
      5 }   
      6 
      7 // 解析对象,创建一个新的根并初始化,返回一个cJSON类型
      8 cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
      9 {
     10     const char *end=0;
     11     cJSON *c=cJSON_New_Item();
     12     ep=0;
     13     if (!c)
     14         return 0;       /* memory fail */
     15 
     16     end=parse_value(c,skip(value));
     17     if (!end)
     18     {
     19         cJSON_Delete(c);
     20         return 0;
     21     }   /* parse failure. ep is set. */
     22 
     23     /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
     24     if (require_null_terminated)
     25     {
     26         end=skip(end);
     27         if (*end)
     28         {
     29             cJSON_Delete(c);
     30             ep=end;
     31             return 0;
     32         }
     33     }
     34     if (return_parse_end)
     35         *return_parse_end=end;
     36     return c;
     37 }
     38 
     39 // 解析器核心函数
     40 static const char *parse_value(cJSON *item,const char *value)
     41 {
     42     if (!value)
     43         return 0;   /* Fail on null. */
     44     if (!strncmp(value,"null",4))
     45     {
     46         item->type=cJSON_NULL;
     47         return value+4;
     48     }
     49     if (!strncmp(value,"false",5))
     50     {
     51         item->type=cJSON_False;
     52         return value+5;
     53     }
     54     if (!strncmp(value,"true",4))
     55     {
     56         item->type=cJSON_True;
     57         item->valueint=1;
     58         return value+4;
     59     }
     60     if (*value=='"')
     61     {
     62         return parse_string(item,value);
     63     }
     64     if (*value=='-' || (*value>='0' && *value<='9'))
     65     {
     66         return parse_number(item,value);
     67     }
     68     if (*value=='[')
     69     {
     70         return parse_array(item,value);
     71     }
     72     if (*value=='{')
     73     {
     74         return parse_object(item,value);
     75     }
     76 
     77     ep=value;
     78     return 0;   /* failure. */
     79 }
     80 
     81 static const char *parse_string(cJSON *item,const char *str)
     82 {
     83     const char *ptr=str+1;
     84     char *ptr2;
     85     char *out;
     86     int len=0;
     87     unsigned uc,uc2;
     88     if (*str!='"')    // 不是字符串情况
     89     {
     90         ep=str;
     91         return 0;
     92     }   /* not a string! */
     93 
     94     while (*ptr!='"' && *ptr && ++len)
     95         if (*ptr++ == '\')
     96             ptr++;   // 跳出前面的引用
     97 
     98     out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */
     99     if (!out)
    100         return 0;
    101 
    102     ptr=str+1;
    103     ptr2=out;
    104     while (*ptr!='"' && *ptr)
    105     {
    106         if (*ptr!='\')
    107             *ptr2++=*ptr++;
    108         else
    109         {
    110             ptr++;
    111             switch (*ptr)
    112             {
    113                 case 'b': *ptr2++=''; break;
    114                 case 'f': *ptr2++='f'; break;
    115                 case 'n': *ptr2++='
    '; break;
    116                 case 'r': *ptr2++='
    '; break;
    117                 case 't': *ptr2++='	'; break;
    118                 case 'u':    /* transcode utf16 to utf8. */
    119                     uc=parse_hex4(ptr+1);
    120                         ptr+=4; /* get the unicode char. */
    121 
    122                     if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0)
    123                         break;  /* check for invalid.   */
    124 
    125                     if (uc>=0xD800 && uc<=0xDBFF)   /* UTF16 surrogate pairs.   */
    126                     {
    127                         if (ptr[1]!='\' || ptr[2]!='u')
    128                             break;  /* missing second-half of surrogate.    */
    129                         uc2=parse_hex4(ptr+3);ptr+=6;
    130                         if (uc2<0xDC00 || uc2>0xDFFF)
    131                             break;  /* invalid second-half of surrogate.    */
    132                         uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
    133                     }
    134 
    135                     len=4;
    136                     if (uc<0x80)
    137                         len=1;
    138                     else if (uc<0x800)
    139                         len=2;
    140                     else if (uc<0x10000)
    141                         len=3;
    142                     ptr2+=len;
    143 
    144                     switch (len)
    145                     {
    146                         case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
    147                         case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
    148                         case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
    149                         case 1: *--ptr2 =(uc | firstByteMark[len]);
    150                     }
    151                     ptr2+=len;
    152                     break;
    153                 default:  *ptr2++=*ptr; break;
    154             }
    155             ptr++;
    156         }
    157     }
    158     *ptr2=0;
    159     if (*ptr=='"') ptr++;
    160     item->valuestring=out;
    161     item->type=cJSON_String;
    162     return ptr;
    163 }
    164 
    165 // 跳过这些空格
    166 static const char *skip(const char *in)
    167 {
    168     while (in && *in && (unsigned char)*in<=32)
    169         in++;
    170     return in;
    171 }
    172 
    173 // parse_number函数功能:解析数字,对输入的文本生成一个数字,并填充结果项,传入参数有两
    174 // 个,这里先只关注num,返回值是一个字符串
    175 static const char *parse_number(cJSON *item,const char *num)
    176 {
    177     double n=0,sign=1,scale=0;
    178     int subscale=0,signsubscale=1;
    179 
    180     if (*num=='-') sign=-1,num++;      // 判断数字是否是有符号数字
    181     if (*num=='0') num++;                  // 判断数字是否为0
    182     if (*num>='1' && *num<='9')
    183         do                               // 转换数字
    184             n=(n*10.0)+(*num++ -'0');
    185         while (*num>='0' && *num<='9');
    186     if (*num=='.' && num[1]>='0' && num[1]<='9') // 对小数点后边的部分进行处理,scale记录小数点后边的位数
    187     {
    188         num++;
    189         do
    190             n=(n*10.0)+(*num++ -'0'),scale--;       // scale为小数点后的位数
    191         while (*num>='0' && *num<='9');
    192     }
    193     if (*num=='e' || *num=='E')        // 是否为指数,科学计数法
    194     {
    195         num++;
    196         if (*num=='+')                 // 判断指数后边幂的正负号
    197             num++;
    198         else if (*num=='-')
    199             signsubscale=-1,num++;
    200         while (*num>='0' && *num<='9') // 处理指数后边10的幂
    201             subscale=(subscale*10)+(*num++ - '0');
    202     }
    203     // 将字符串转换为相应的数值
    204     n=sign*n*pow(10.0,(scale+subscale*signsubscale));   /* number = +/- number.fraction * 10^+/- exponent */
    205 
    206     item->valuedouble=n;             // 将算出来的值存入缓存
    207     item->valueint=(int)n;           // 将算出来的值存入缓存
    208     item->type=cJSON_Number;         // 目标类型为数字
    209     return num;
    210 }
    211 
    212 // 从输入文本中构建array
    213 static const char *parse_array(cJSON *item,const char *value)
    214 {
    215     cJSON *child;
    216     if (*value!='[')    {ep=value;return 0;}    /* not an array! */
    217 
    218     item->type=cJSON_Array;
    219     value=skip(value+1);
    220     if (*value==']') return value+1;    /* empty array. */
    221 
    222     item->child=child=cJSON_New_Item();
    223     if (!item->child) return 0;      /* memory fail */
    224     value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */
    225     if (!value) return 0;
    226 
    227     while (*value==',')
    228     {
    229         cJSON *new_item;
    230         if (!(new_item=cJSON_New_Item())) return 0;     /* memory fail */
    231         child->next=new_item;new_item->prev=child;child=new_item;
    232         value=skip(parse_value(child,skip(value+1)));
    233         if (!value) return 0;   /* memory fail */
    234     }
    235 
    236     if (*value==']') return value+1;    /* end of array */
    237     ep=value;return 0;  /* malformed. */
    238 }
    239 
    240 // 从输入文本中构建object
    241 static const char *parse_object(cJSON *item,const char *value)
    242 {
    243     cJSON *child;
    244     if (*value!='{')    {ep=value;return 0;}    /* not an object! */
    245 
    246     item->type=cJSON_Object;
    247     value=skip(value+1);
    248     if (*value=='}') return value+1;    /* empty array. */
    249 
    250     item->child=child=cJSON_New_Item();
    251     if (!item->child) return 0;
    252     value=skip(parse_string(child,skip(value)));
    253     if (!value) return 0;
    254     child->string=child->valuestring;child->valuestring=0;
    255     if (*value!=':') {ep=value;return 0;}   /* fail! */
    256     value=skip(parse_value(child,skip(value+1)));   /* skip any spacing, get the value. */
    257     if (!value) return 0;
    258 
    259     while (*value==',')
    260     {
    261         cJSON *new_item;
    262         if (!(new_item=cJSON_New_Item()))   return 0; /* memory fail */
    263         child->next=new_item;new_item->prev=child;child=new_item;
    264         value=skip(parse_string(child,skip(value+1)));
    265         if (!value) return 0;
    266         child->string=child->valuestring;child->valuestring=0;
    267         if (*value!=':') {ep=value;return 0;}   /* fail! */
    268         value=skip(parse_value(child,skip(value+1)));   /* skip any spacing, get the value. */
    269         if (!value) return 0;
    270     }
    271 
    272     if (*value=='}') return value+1;    /* end of array */
    273     ep=value;return 0;  /* malformed. */
    274 }
    275 
    276 // 将十六进制的字符串转换为数字表示!
    277 static unsigned parse_hex4(const char *str)
    278 {
    279     unsigned h=0;
    280     if (*str>='0' && *str<='9')
    281         h+=(*str)-'0';
    282     else if (*str>='A' && *str<='F')
    283         h+=10+(*str)-'A';
    284     else if (*str>='a' && *str<='f')
    285         h+=10+(*str)-'a';
    286     else
    287         return 0;
    288     h=h<<4;str++;
    289     if (*str>='0' && *str<='9')
    290         h+=(*str)-'0';
    291     else if (*str>='A' && *str<='F')
    292         h+=10+(*str)-'A';
    293     else if (*str>='a' && *str<='f')
    294         h+=10+(*str)-'a';
    295     else
    296         return 0;
    297     h=h<<4;str++;
    298     if (*str>='0' && *str<='9')
    299         h+=(*str)-'0';
    300     else if (*str>='A' && *str<='F')
    301         h+=10+(*str)-'A';
    302     else if (*str>='a' && *str<='f')
    303         h+=10+(*str)-'a';
    304     else
    305         return 0;
    306     h=h<<4;str++;
    307     if (*str>='0' && *str<='9')
    308         h+=(*str)-'0';
    309     else if (*str>='A' && *str<='F')
    310         h+=10+(*str)-'A';
    311     else if (*str>='a' && *str<='f')
    312         h+=10+(*str)-'a';
    313     else
    314         return 0;
    315     return h;
    316 }
    317 
    318 打印JSON信息
    319 
    320 // 打印值到文本
    321 static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p)
    322 {
    323     char *out=0;
    324     if (!item) return 0;
    325     if (p)
    326     {
    327         switch ((item->type)&255)
    328         {
    329             case cJSON_NULL:    {out=ensure(p,5);   if (out) strcpy(out,"null");    break;}
    330             case cJSON_False:   {out=ensure(p,6);   if (out) strcpy(out,"false");   break;}
    331             case cJSON_True:    {out=ensure(p,5);   if (out) strcpy(out,"true");    break;}
    332             case cJSON_Number:  out=print_number(item,p);break;
    333             case cJSON_String:  out=print_string(item,p);break;
    334             case cJSON_Array:   out=print_array(item,depth,fmt,p);break;
    335             case cJSON_Object:  out=print_object(item,depth,fmt,p);break;
    336         }
    337     }
    338     else
    339     {
    340         switch ((item->type)&255)
    341         {
    342             case cJSON_NULL:    out=cJSON_strdup("null");   break;
    343             case cJSON_False:   out=cJSON_strdup("false");break;
    344             case cJSON_True:    out=cJSON_strdup("true"); break;
    345             case cJSON_Number:  out=print_number(item,0);break;
    346             case cJSON_String:  out=print_string(item,0);break;
    347             case cJSON_Array:   out=print_array(item,depth,fmt,0);break;
    348             case cJSON_Object:  out=print_object(item,depth,fmt,0);break;
    349         }
    350     }
    351     return out;
    352 }
    353 
    354 // 打印array到文本
    355 static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p)
    356 {
    357     char **entries;
    358     char *out=0,*ptr,*ret;int len=5;
    359     cJSON *child=item->child;
    360     int numentries=0,i=0,fail=0;
    361     size_t tmplen=0;
    362 
    363     /* How many entries in the array? */
    364     while (child) numentries++,child=child->next;
    365     /* Explicitly handle numentries==0 */
    366     if (!numentries)
    367     {
    368         if (p)  out=ensure(p,3);
    369         else    out=(char*)cJSON_malloc(3);
    370         if (out) strcpy(out,"[]");
    371         return out;
    372     }
    373 
    374     if (p)
    375     {
    376         /* Compose the output array. */
    377         i=p->offset;
    378         ptr=ensure(p,1);if (!ptr) return 0; *ptr='[';   p->offset++;
    379         child=item->child;
    380         while (child && !fail)
    381         {
    382             print_value(child,depth+1,fmt,p);
    383             p->offset=update(p);
    384             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;}
    385             child=child->next;
    386         }
    387         ptr=ensure(p,2);if (!ptr) return 0; *ptr++=']';*ptr=0;
    388         out=(p->buffer)+i;
    389     }
    390     else
    391     {
    392         /* Allocate an array to hold the values for each */
    393         entries=(char**)cJSON_malloc(numentries*sizeof(char*));
    394         if (!entries) return 0;
    395         memset(entries,0,numentries*sizeof(char*));
    396         /* Retrieve all the results: */
    397         child=item->child;
    398         while (child && !fail)
    399         {
    400             ret=print_value(child,depth+1,fmt,0);
    401             entries[i++]=ret;
    402             if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
    403             child=child->next;
    404         }
    405 
    406         /* If we didn't fail, try to malloc the output string */
    407         if (!fail)  out=(char*)cJSON_malloc(len);
    408         /* If that fails, we fail. */
    409         if (!out) fail=1;
    410 
    411         /* Handle failure. */
    412         if (fail)
    413         {
    414             for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
    415             cJSON_free(entries);
    416             return 0;
    417         }
    418 
    419         /* Compose the output array. */
    420         *out='[';
    421         ptr=out+1;*ptr=0;
    422         for (i=0;i<numentries;i++)
    423         {
    424             tmplen=strlen(entries[i]);memcpy(ptr,entries[i],tmplen);ptr+=tmplen;
    425             if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}
    426             cJSON_free(entries[i]);
    427         }
    428         cJSON_free(entries);
    429         *ptr++=']';*ptr++=0;
    430     }
    431     return out;
    432 }
    433 
    434 // 打印object到文本中
    435 static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p)
    436 {
    437     char **entries=0,**names=0;
    438     char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
    439     cJSON *child=item->child;
    440     int numentries=0,fail=0;
    441     size_t tmplen=0;
    442     /* Count the number of entries. */
    443     while (child) numentries++,child=child->next;
    444     /* Explicitly handle empty object case */
    445     if (!numentries)
    446     {
    447         if (p) out=ensure(p,fmt?depth+4:3);
    448         else    out=(char*)cJSON_malloc(fmt?depth+4:3);
    449         if (!out)   return 0;
    450         ptr=out;*ptr++='{';
    451         if (fmt) {*ptr++='
    ';for (i=0;i<depth-1;i++) *ptr++='	';}
    452         *ptr++='}';*ptr++=0;
    453         return out;
    454     }
    455     if (p)
    456     {
    457         /* Compose the output: */
    458         i=p->offset;
    459         len=fmt?2:1;    ptr=ensure(p,len+1);    if (!ptr) return 0;
    460         *ptr++='{'; if (fmt) *ptr++='
    ';   *ptr=0; p->offset+=len;
    461         child=item->child;depth++;
    462         while (child)
    463         {
    464             if (fmt)
    465             {
    466                 ptr=ensure(p,depth);    if (!ptr) return 0;
    467                 for (j=0;j<depth;j++) *ptr++='	';
    468                 p->offset+=depth;
    469             }
    470             print_string_ptr(child->string,p);
    471             p->offset=update(p);
    472 
    473             len=fmt?2:1;
    474             ptr=ensure(p,len);  if (!ptr) return 0;
    475             *ptr++=':';if (fmt) *ptr++='	';
    476             p->offset+=len;
    477 
    478             print_value(child,depth,fmt,p);
    479             p->offset=update(p);
    480 
    481             len=(fmt?1:0)+(child->next?1:0);
    482             ptr=ensure(p,len+1); if (!ptr) return 0;
    483             if (child->next) *ptr++=',';
    484             if (fmt) *ptr++='
    ';*ptr=0;
    485             p->offset+=len;
    486             child=child->next;
    487         }
    488         ptr=ensure(p,fmt?(depth+1):2);   if (!ptr) return 0;
    489         if (fmt)    for (i=0;i<depth-1;i++) *ptr++='	';
    490         *ptr++='}';*ptr=0;
    491         out=(p->buffer)+i;
    492     }
    493     else
    494     {
    495         /* Allocate space for the names and the objects */
    496         entries=(char**)cJSON_malloc(numentries*sizeof(char*));
    497         if (!entries) return 0;
    498         names=(char**)cJSON_malloc(numentries*sizeof(char*));
    499         if (!names) {cJSON_free(entries);return 0;}
    500         memset(entries,0,sizeof(char*)*numentries);
    501         memset(names,0,sizeof(char*)*numentries);
    502 
    503         /* Collect all the results into our arrays: */
    504         child=item->child;depth++;if (fmt) len+=depth;
    505         while (child)
    506         {
    507             names[i]=str=print_string_ptr(child->string,0);
    508             entries[i++]=ret=print_value(child,depth,fmt,0);
    509             if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
    510             child=child->next;
    511         }
    512 
    513         /* Try to allocate the output string */
    514         if (!fail)  out=(char*)cJSON_malloc(len);
    515         if (!out) fail=1;
    516 
    517         /* Handle failure */
    518         if (fail)
    519         {
    520             for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}
    521             cJSON_free(names);cJSON_free(entries);
    522             return 0;
    523         }
    524 
    525         /* Compose the output: */
    526         *out='{';ptr=out+1;if (fmt)*ptr++='
    ';*ptr=0;
    527         for (i=0;i<numentries;i++)
    528         {
    529             if (fmt) for (j=0;j<depth;j++) *ptr++='	';
    530             tmplen=strlen(names[i]);memcpy(ptr,names[i],tmplen);ptr+=tmplen;
    531             *ptr++=':';if (fmt) *ptr++='	';
    532             strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
    533             if (i!=numentries-1) *ptr++=',';
    534             if (fmt) *ptr++='
    ';*ptr=0;
    535             cJSON_free(names[i]);cJSON_free(entries[i]);
    536         }
    537 
    538         cJSON_free(names);cJSON_free(entries);
    539         if (fmt) for (i=0;i<depth-1;i++) *ptr++='	';
    540         *ptr++='}';*ptr++=0;
    541     }
    542     return out;
    543 }

    其余函数信息如下:

      1 // 返回节点的个数
      2 int cJSON_GetArraySize(cJSON *array)
      3 {
      4     cJSON *c=array->child;
      5     int i=0;
      6     while(c)
      7         i++,c=c->next;
      8     return i;
      9 }
     10 // 返回array中第item个节点的地址
     11 cJSON *cJSON_GetArrayItem(cJSON *array,int item)
     12 {
     13     cJSON *c=array->child;
     14     while (c && item>0)
     15         item--,c=c->next;
     16     return c;
     17 }
     18 // 返回Object中第item个节点的地址
     19 cJSON *cJSON_GetObjectItem(cJSON *object,const char *string)
     20 {
     21     cJSON *c=object->child;
     22     while (c && cJSON_strcasecmp(c->string,string))
     23         c=c->next;
     24     return c;
     25 }
     26 
     27 // 在链表中插入一个新的节点
     28 void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem)
     29 {
     30     cJSON *c=array->child;
     31     // 找到which位置
     32     while (c && which>0)
     33      c=c->next,which--;
     34     // 添加新的节点到array中
     35     if (!c)
     36     {
     37         cJSON_AddItemToArray(array,newitem);
     38         return;
     39     }
     40     // 将链表节点进行挂接
     41     newitem->next=c;
     42     newitem->prev=c->prev;
     43     c->prev=newitem;
     44     // 处理arrya的孩子节点
     45     if (c==array->child)
     46         array->child=newitem;
     47     else
     48         newitem->prev->next=newitem;
     49 }
     50 // 替换节点操作,用新的节点替换原有的某一个节点
     51 void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem)
     52 {
     53     cJSON *c=array->child;
     54     // 找到which位置
     55     while (c && which>0)
     56         c=c->next,which--;
     57     if (!c)
     58         return;
     59     // 进行挂接
     60     newitem->next=c->next;
     61     newitem->prev=c->prev;
     62     // 处理NULL情况
     63     if (newitem->next)
     64         newitem->next->prev=newitem;
     65     // 处理孩子节点
     66     if (c==array->child)
     67         array->child=newitem;
     68     else
     69         newitem->prev->next=newitem;
     70     c->next=c->prev=0;
     71     // 删除替换的节点
     72     cJSON_Delete(c);
     73 }
     74 // 替换节点操作
     75 // 用原有节点替换现有节点
     76 void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem)
     77 {
     78     int i=0;
     79     cJSON *c=object->child;
     80     while(c && cJSON_strcasecmp(c->string,string))
     81         i++,c=c->next;
     82     if(c)
     83     {
     84         newitem->string=cJSON_strdup(string);
     85         cJSON_ReplaceItemInArray(object,i,newitem);
     86     }
     87 }
     88 
     89 /* Create basic types: */
     90 // 创建基本类型函数
     91 cJSON *cJSON_CreateNull(void)
     92 {
     93     cJSON *item=cJSON_New_Item();
     94     if(item)
     95         item->type=cJSON_NULL;
     96     return item;
     97 }
     98 cJSON *cJSON_CreateTrue(void)
     99 {
    100     cJSON *item=cJSON_New_Item();
    101     if(item)
    102         item->type=cJSON_True;
    103     return item;
    104 }
    105 cJSON *cJSON_CreateFalse(void)
    106 {
    107     cJSON *item=cJSON_New_Item();
    108     if(item)
    109         item->type=cJSON_False;
    110     return item;
    111 }
    112 cJSON *cJSON_CreateBool(int b)
    113 {
    114     cJSON *item=cJSON_New_Item();
    115     if(item)
    116         item->type=b?cJSON_True:cJSON_False;
    117     return item;
    118 }
    119 cJSON *cJSON_CreateNumber(double num)
    120 {
    121     cJSON *item=cJSON_New_Item();
    122     if(item)
    123     {
    124         item->type=cJSON_Number;
    125         item->valuedouble=num;
    126         item->valueint=(int)num;
    127     }
    128     return item;
    129 }
    130 cJSON *cJSON_CreateString(const char *string)
    131 {
    132     cJSON *item=cJSON_New_Item();
    133     if(item)
    134     {
    135         item->type=cJSON_String;
    136         item->valuestring=cJSON_strdup(string);
    137     }
    138     return item;
    139 }
    140 cJSON *cJSON_CreateArray(void)
    141 {
    142     cJSON *item=cJSON_New_Item();
    143     if(item)
    144         item->type=cJSON_Array;
    145     return item;
    146 }
    147 cJSON *cJSON_CreateObject(void)
    148 {
    149     cJSON *item=cJSON_New_Item();
    150     if(item)
    151         item->type=cJSON_Object;
    152     return item;
    153 }
    154 
    155 /* Create Arrays: */
    156 // 创建array
    157 cJSON *cJSON_CreateIntArray(const int *numbers,int count)
    158 {
    159     int i;
    160     cJSON *n=0,*p=0,*a=cJSON_CreateArray();
    161     for(i=0;a && i<count;i++)
    162     {
    163         n=cJSON_CreateNumber(numbers[i]);
    164         if(!i)
    165             a->child=n;
    166         else
    167             suffix_object(p,n);
    168         p=n;
    169     }
    170     return a;
    171 }
    172 cJSON *cJSON_CreateFloatArray(const float *numbers,int count)
    173 {
    174     int i;
    175     cJSON *n=0,*p=0,*a=cJSON_CreateArray();
    176     for(i=0;a && i<count;i++)
    177     {
    178         n=cJSON_CreateNumber(numbers[i]);
    179         if(!i)
    180             a->child=n;
    181         else
    182             suffix_object(p,n);
    183         p=n;
    184     }
    185     return a;
    186 }
    187 cJSON *cJSON_CreateDoubleArray(const double *numbers,int count)
    188 {
    189     int i;
    190     cJSON *n=0,*p=0,*a=cJSON_CreateArray();
    191     for(i=0;a && i<count;i++)
    192     {
    193         n=cJSON_CreateNumber(numbers[i]);
    194         if(!i)
    195             a->child=n;
    196         else
    197             suffix_object(p,n);
    198         p=n;
    199     }
    200     return a;
    201 }
    202 cJSON *cJSON_CreateStringArray(const char **strings,int count)
    203 {
    204     int i;
    205     cJSON *n=0,*p=0,*a=cJSON_CreateArray();
    206     for(i=0;a && i<count;i++)
    207     {
    208         n=cJSON_CreateString(strings[i]);
    209         if(!i)
    210             a->child=n;
    211         else
    212             suffix_object(p,n);
    213         p=n;
    214     }
    215     return a;
    216 }
    217 
    218 /* Duplication */
    219 // 拷贝副本操作
    220 cJSON *cJSON_Duplicate(cJSON *item,int recurse)
    221 {
    222     cJSON *newitem,*cptr,*nptr=0,*newchild;
    223     /* Bail on bad ptr */
    224     if (!item)
    225         return 0;
    226     /* Create new item */
    227     newitem=cJSON_New_Item();
    228     if (!newitem)
    229         return 0;
    230     /* Copy over all vars */
    231     newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble;
    232     if (item->valuestring)
    233     {
    234         newitem->valuestring=cJSON_strdup(item->valuestring);
    235         if (!newitem->valuestring)
    236         {
    237             cJSON_Delete(newitem);
    238             return 0;
    239         }
    240     }
    241     if (item->string)
    242     {
    243         newitem->string=cJSON_strdup(item->string);
    244         if (!newitem->string)
    245         {
    246             cJSON_Delete(newitem);
    247             return 0;
    248         }
    249     }
    250     /* If non-recursive, then we're done! */
    251     if (!recurse)
    252         return newitem;
    253     /* Walk the ->next chain for the child. */
    254     cptr=item->child;
    255     while (cptr)
    256     {
    257         newchild=cJSON_Duplicate(cptr,1);       /* Duplicate (with recurse) each item in the ->next chain */
    258         if (!newchild)
    259         {
    260             cJSON_Delete(newitem);
    261             return 0;
    262         }
    263         if (nptr)
    264         {
    265             nptr->next=newchild,newchild->prev=nptr;
    266             nptr=newchild;
    267         }   /* If newitem->child already set, then crosswire ->prev and ->next and move on */
    268         else
    269         {
    270             newitem->child=newchild;
    271             nptr=newchild;
    272         }                   /* Set newitem->child and move to it */
    273         cptr=cptr->next;
    274     }
    275     return newitem;
    276 }
    277 
    278 void cJSON_Minify(char *json)
    279 {
    280     char *into=json;
    281     while (*json)
    282     {
    283         if (*json==' ') json++;
    284         else if (*json=='	') json++;   /* Whitespace characters. */
    285         else if (*json=='
    ') json++;
    286         else if (*json=='
    ') json++;
    287         else if (*json=='/' && json[1]=='/')  while (*json && *json!='
    ') json++;  /* double-slash comments, to end of line. */
    288         else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;}   /* multiline comments. */
    289         else if (*json=='"'){*into++=*json++;while (*json && *json!='"'){if (*json=='\') *into++=*json++;*into++=*json++;}*into++=*json++;} /* string literals, which are " sensitive. */
    290         else *into++=*json++;           /* All other characters. */
    291     }
    292     *into=0;    /* and null-terminate. */
    293 }
  • 参考文献

    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/

原文出处

原文地址:https://www.cnblogs.com/skullboyer/p/8152011.html