zoukankan      html  css  js  c++  java
  • cjson库的使用以及源码阅读

    cjson是一个用c语言开发的json解析库,免费开源只有一个c文件和一个h文件。
    json和xml功能相似,可以用来传输数据,存储数据以及表达程序当前的状态。
    1、下载cjson的源码
    2、阅读readme文件可以大概的了解一下cjson的介绍以及使用方法,我尝试着把readme文件做了一下翻译,水平有限,大概意思写在了“cjson工程的readme文件翻译”,可以参考原文来对照看,如果只是想快速应用一下cjson库的话,看完应该能知道如何使用这个cjson库了。
    3、源码分析
        如果本着不了解其实现无法安心使用的心态的话,可以看一下下面的源码解析。
        将头文件和源码进行分开,然后注释都添加在了代码里(基本上都是根据自己对英文的理解进行翻译的),至于测试例程,其实cjson的源码提供了一个test.c。这个文件里面里面提供了一个比较全面的测试用例。附件里面是整理完格式和加了注释后的cJSON源码

    cJSON.h:
    1. #ifndef cJSON__h
    2. #define cJSON__h
    3. #ifdef __cplusplus
    4. extern "C"
    5. {
    6. #endif
    7. //以宏的方式定义出的几种cJson对象的类型
    8. #define cJSON_False 0
    9. #define cJSON_True 1
    10. #define cJSON_NULL 2
    11. #define cJSON_Number 3
    12. #define cJSON_String 4
    13. #define cJSON_Array 5
    14. #define cJSON_Object 6
    15. #define cJSON_IsReference 256
    16. #define cJSON_StringIsConst 512
    17. //cJSON的数据结构
    18. typedef struct cJSON
    19. {
    20. /* next/prev 用来遍历所有的数组或者对象链表. 一般来说可以调用GetArraySize/GetArrayItem/GetObjectItem 进行操作*/
    21. struct cJSON *next,*prev;
    22. /* 一个数组或者对象会有一个孩子节点指针指向一个对象或者数组链 */
    23. struct cJSON *child;
    24. /* 这个节点的类型, 为上面定义的宏 */
    25. int type;
    26. /* 是节点的值 如果节点的类型是cJSON_String的话 */
    27. char *valuestring;
    28. /* 是节点的值 如果节点的类型是cJSON_Number的话 */
    29. int valueint;
    30. /* 是节点的值 如果节点的类型是cJSON_Number的话 */
    31. double valuedouble;
    32. /* 节点的名字*/
    33. char *string;
    34. } cJSON;
    35. //钩子?将申请内存和释放内存的接口进行管理。
    36. typedef struct cJSON_Hooks {
    37. void *(*malloc_fn)(size_t sz);
    38. void (*free_fn)(void *ptr);
    39. } cJSON_Hooks;
    40. //为cJSON提供 malloc realloc 和 free函数
    41. extern void cJSON_InitHooks(cJSON_Hooks* hooks);
    42. //提供一个JSON的内存块,返回出从value传入的字符串中携带的json信息使你后续可以进行提取。在完成工作之后要使用cJSON_Delete进行释放
    43. extern cJSON *cJSON_Parse(const char *value);
    44. //将一个json数据转换为文本数据,用来方便转发和存储。在完成工作之后要释放char *
    45. extern char *cJSON_Print(cJSON *item);
    46. //将一个json数据转换为不含有任何格式的文本数据,用来方便转发和存储。在完成工作之后要释放char *
    47. extern char *cJSON_PrintUnformatted(cJSON *item);
    48. /* 使用缓存的策略将json数据打印到缓冲区中. prebuffer是预测的缓存大小. 认为可以很好的减少内存重复分配.
    49. * fmt=0 不含有任何格式,
    50. * fmt=1 含有格式
    51. */
    52. extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt);
    53. /* 删除整个json结构体和其所有子项 */
    54. extern void cJSON_Delete(cJSON *c);
    55. /* 返回一个对象或者数组中所有的元素个数*/
    56. extern int cJSON_GetArraySize(cJSON *array);
    57. /* 检索数组array中第item个元素,不成功则返回NULL */
    58. extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
    59. /*获取"string"指定的对象. 不区分大小写. */
    60. extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
    61. /* 用来分析错误的解析.返回一个指向解析错误位置的指针。你可能需要从这个位置往回检查几个字符. 解析成功则返回0. */
    62. extern const char *cJSON_GetErrorPtr(void);
    63. /*下面的这些调用用来根据指定的类型创建cjson的节点。*/
    64. extern cJSON *cJSON_CreateNull(void);
    65. extern cJSON *cJSON_CreateTrue(void);
    66. extern cJSON *cJSON_CreateFalse(void);
    67. extern cJSON *cJSON_CreateBool(int b);
    68. extern cJSON *cJSON_CreateNumber(double num);
    69. extern cJSON *cJSON_CreateString(const char *string);
    70. extern cJSON *cJSON_CreateArray(void);
    71. extern cJSON *cJSON_CreateObject(void);
    72. /*下面的这些用来建立count个节点*/
    73. extern cJSON *cJSON_CreateIntArray(const int *numbers,int count);
    74. extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count);
    75. extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count);
    76. extern cJSON *cJSON_CreateStringArray(const char **strings,int count);
    77. /*将指定的节点添加到数组或者对象中 */
    78. extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
    79. extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
    80. /* 当字符串是常量的时候使用下面这个接口 */
    81. extern void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item);
    82. /*添加指定的节点到指定的对象或者数组中. 把一个存在的cJSON添加到一个新的cJSON但是又不想销毁已经存在的这个cJSON使用这一组接口*/
    83. extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
    84. extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
    85. /* 从一个数组或者对象中删除指定的节点 */
    86. extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
    87. extern void cJSON_DeleteItemFromArray(cJSON *array,int which);
    88. extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
    89. extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string);
    90. /* 更新数组中的节点. */
    91. extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem); /* 将原有的节点右移. */
    92. extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
    93. extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
    94. /* 复制一个cJSON对象 */
    95. extern cJSON *cJSON_Duplicate(cJSON *item,int recurse);
    96. /* Duplicate会创建一个与传入参数完全相同的对象, 在新的内存中需要释放。
    97. *当recurse!=0,将会复制这个对象中的所有的孩子节点。
    98. *返回对象中的item->next 和 ->prev指针通常是0。
    99. */
    100. /* ParseWithOpts允许你去指定或者检查字符串是否以NULL结尾, 同时可以检索解析后的字符串的最后一个位置. */
    101. extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);
    102. //一个精简后的解析框架
    103. extern void cJSON_Minify(char *json);
    104. /* 宏,用来做快速建立并添加操作. */
    105. #define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
    106. #define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
    107. #define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
    108. #define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
    109. #define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
    110. #define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
    111. /* 当赋值一个整数的时候, 需要对浮点数也进行同时赋值. */
    112. #define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
    113. #define cJSON_SetNumberValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
    114. #ifdef __cplusplus
    115. }
    116. #endif
    117. #endif

        以上为cjson的头文件中的内容,其中定义cjson结构体以及操作json数据的接口,对于cjson结构体来说通过之前的readme文件可以大致的根据一个样例数据进行示例其在内存中的组织方式,而各个接口的实现则在后续的cjson.c的分析中进行展开。
        在绘图时,对于cjson结构的组织如下图所示:

    图一:cjson的数据结构示意图
    1. {
    2. "name": "Jack ("Bee") Nimble",
    3. "format": {
    4. "type": "rect",
    5. "width": 1920,
    6. "height": 1080,
    7. "interlace": false,
    8. "frame rate": 24
    9. }
    10. }
        cjson将上面所示例的json数据在内存中组织方式如下图所示(char*实际情况应为指向动态申请的内存的指针,但为了方便起见图中约定char*使用值直接替换):

    图二:示例json的组织方式
        下面是对于cJSON.c中的源码分析。
    cJSON.c
    1. /* cJSON */
    2. /* JSON parser in C. */
    3. #include <string.h>
    4. #include <stdio.h>
    5. #include <math.h>
    6. #include <stdlib.h>
    7. #include <float.h>
    8. #include <limits.h>
    9. #include <ctype.h>
    10. #include "cJSON.h"
    11. /* ep静态全局指针,指向字符串,*/
    12. static const char *ep;
    13. /*返回ep所指向字符串的地址,使用const修饰返回值,说明ep所指向的字符串是常量,
    14. 应该是写死在出错方式上。所以不需要释放其返回的指针的*/
    15. const char *cJSON_GetErrorPtr(void)
    16. {
    17. return ep;
    18. }
    19. /*忽略大小写比较字符串s1和s2, 参数使用const进行修饰,说明内部不会修改这两个值。
    20. *static说明文件内作用域,返回整数,
    21. *=0 - 相等;
    22. *>0 - s1>s2;
    23. *<0 - s1<s2;
    24. */
    25. static int cJSON_strcasecmp(const char *s1,const char *s2)
    26. {
    27. //s1==NULL的情况下,如果s2也是NULL就相等,不然就是s1<s2;
    28. if (!s1)
    29. return (s1==s2)?0:1;
    30. //s1不是NULL,但是s2是NULL,那么s1>s2
    31. if (!s2)
    32. return 1;
    33. //不区分大小写,即都以小写形式进行比较,循环比较每个字符。不相等则跳出循环。
    34. for(; tolower(*s1) == tolower(*s2); ++s1, ++s2)
    35. if(*s1 == 0)//如果这个条件为真,说明s1==s2,s1==NULL。即,两个字串不区分大小写相同
    36. return 0;
    37. //将不相同的那个字符的小写形式进行相减,可以得到两个串的大小。
    38. //强制转换防止报错吧。
    39. return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
    40. }
    41. /*对静态全局函数指针变量进行赋值,使cJSON_malloc=malloc,使cJSON_free=free*/
    42. static void *(*cJSON_malloc)(size_t sz) = malloc;
    43. static void (*cJSON_free)(void *ptr) = free;
    44. /*静态作用域,返回char*类型指针,该指针指向从str中复制出内容的一块新申请的内存地址,str为const,不可修改*/
    45. static char* cJSON_strdup(const char* str)
    46. {
    47. size_t len;
    48. char* copy;
    49. //获取字符串长度,并考虑了最后一个结束符号。
    50. len = strlen(str) + 1;
    51. //申请len个长度内存并类型转换和测试是否申请成功,不成功就返回NULL。
    52. if (!(copy = (char*)cJSON_malloc(len))) return 0;
    53. //申请成功就拷贝len长度个串进去。然后将首地址返回
    54. memcpy(copy,str,len);
    55. return copy;
    56. }
    57. /*初始化钩子,其实所谓钩子在这里也就是内存申请和释放接口*/
    58. void cJSON_InitHooks(cJSON_Hooks* hooks)
    59. {
    60. //判断传入的指针为NULL,那么就使用系统的申请和释放接口
    61. if (!hooks) { /* Reset hooks */
    62. cJSON_malloc = malloc;
    63. cJSON_free = free;
    64. return;
    65. }
    66. //然后根据传入参数中是否携带指定的申请和释放接口,进行选择使用哪一个内存接口。
    67. cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
    68. cJSON_free = (hooks->free_fn)?hooks->free_fn:free;
    69. }
    70. /*申请一个cJSON结构体大小的内存,初始化为0,静态作用域*/
    71. static cJSON *cJSON_New_Item(void)
    72. {
    73. //申请内存,测试,赋值为0,返回指针。
    74. cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
    75. if (node)
    76. memset(node,0,sizeof(cJSON));
    77. return node;
    78. }
    79. /*删除一个cJSON结构体,还应该循环将它的所有子项进行删除清理*/
    80. /*对于c->type的0、1、2、3、4、5、6和256以及512做与预算到底是为什么要这么做呢?*/
    81. void cJSON_Delete(cJSON *c)
    82. {
    83. cJSON *next;
    84. while (c)
    85. {
    86. //记录c节点的下一个节点。
    87. next=c->next;
    88. //c->type&cJSON_IsReference将type与256做与运算,判断有孩子节点则进行递归
    89. if (!(c->type&cJSON_IsReference) && c->child)
    90. cJSON_Delete(c->child);
    91. //valuestring不为NULL,需要释放内存
    92. if (!(c->type&cJSON_IsReference) && c->valuestring)
    93. cJSON_free(c->valuestring);
    94. //string不为NULL,需要释放内存
    95. if (!(c->type&cJSON_StringIsConst) && c->string)
    96. cJSON_free(c->string);
    97. //删除这个节点
    98. cJSON_free(c);
    99. //继续下一个节点
    100. c=next;
    101. }
    102. }
    103. /*将输入的num解析成一个数字,然后将结果填充到节点中
    104. *静态作用域,const返回值为传入字串解析完后第一个不为数值的位置,解析num到item中
    105. */
    106. static const char *parse_number(cJSON *item,const char *num)
    107. {
    108. double n=0,sign=1,scale=0;
    109. int subscale=0,signsubscale=1;
    110. //是否为负数
    111. if (*num=='-')
    112. sign=-1,num++;
    113. //是否为0
    114. if (*num=='0')
    115. num++;
    116. //如果是十进制就进行解析,临时变量存到n中
    117. if (*num>='1' && *num<='9')
    118. do
    119. n=(n*10.0)+(*num++ -'0');
    120. while (*num>='0' && *num<='9');
    121. //如果存在小数点,将数字继续转存到n的末尾以整数方式,但是使用scale记录有几位小数
    122. if (*num=='.' && num[1]>='0' && num[1]<='9')
    123. {
    124. num++;
    125. do
    126. n=(n*10.0)+(*num++ -'0'),scale--;
    127. while (*num>='0' && *num<='9');
    128. }
    129. //如果是指数计数方式,记录指数符号,然后将数字进行转存到subscale中
    130. if (*num=='e' || *num=='E')
    131. {
    132. num++;
    133. if (*num=='+')
    134. num++;
    135. else if (*num=='-')
    136. signsubscale=-1,num++;
    137. while (*num>='0' && *num<='9')
    138. subscale=(subscale*10)+(*num++ - '0');
    139. }
    140. /* number = +/- number.fraction * 10^+/- exponent */
    141. n=sign*n*pow(10.0,(scale+subscale*signsubscale));
    142. //将计算到的值赋值到item中,int和double项都要赋值。类型赋值为NUM
    143. item->valuedouble=n;
    144. item->valueint=(int)n;
    145. item->type=cJSON_Number;
    146. return num;
    147. }
    148. /*返回大于x的最小的2的幂,静态作用域*/
    149. /*在实现上就是把x占用到的最高位为1的位到第0位,都置位为1*/
    150. static int pow2gt (int x)
    151. {
    152. //--x是为了防止x直接就是2的幂的情况。
    153. --x;
    154. x|=x>>1; x|=x>>2; x|=x>>4; x|=x>>8; x|=x>>16;
    155. return x+1;
    156. }
    157. //定义一个printbuffer类型,主要是用来将json数据打印到缓冲区时,进行提供缓存空间的信息。
    158. typedef struct
    159. {
    160. char *buffer; //缓存地址指针
    161. int length; //缓存当前的长度
    162. int offset; //缓存当前已经使用到的位置。
    163. } printbuffer;
    164. /*
    165. *ensure 意为确保的意思,这里可以理解为,确保p所指向的缓冲区中能够提供needed大小的缓冲给打印功能使用
    166. *静态作用域,返回缓冲区中可以继续使用的空间的位置。needed在里面做了局部变量,修改使用均无碍,
    167. *减少了一个中间变量。
    168. */
    169. static char* ensure(printbuffer *p,int needed)
    170. {
    171. char *newbuffer;int newsize;
    172. //如果p=NULL,或者p->buffer=NULL,那么为运行时检查错误,返回空指针
    173. if (!p || !p->buffer)
    174. return 0;
    175. //计算将当前所需的空间加上之前已用的空间一共需要内存的数目
    176. needed+=p->offset;
    177. //如果现在p->buffer足够容下所有的值,那么就返回当前缓存中最后一个可用的位置
    178. if (needed<=p->length)
    179. return p->buffer+p->offset;
    180. /*下面为处理当前缓存不能存下所有的信息的时候*/
    181. //计算大于当前所需数目的最小2de幂,用来分配内存数目
    182. newsize=pow2gt(needed);
    183. //申请内存并做错误检查,如果失败那么就置空后返回空指针。
    184. newbuffer=(char*)cJSON_malloc(newsize);
    185. if (!newbuffer)
    186. {
    187. cJSON_free(p->buffer);
    188. p->length=0,
    189. p->buffer=0;
    190. return 0;
    191. }
    192. //申请成功后将原有数据拷贝到新空间中。
    193. if (newbuffer)
    194. memcpy(newbuffer,p->buffer,p->length);
    195. //释放原指针,并更新新的缓存信息,然后返回缓存中第一个可用的内存位置。
    196. cJSON_free(p->buffer);
    197. p->length=newsize;
    198. p->buffer=newbuffer;
    199. return newbuffer+p->offset;
    200. }
    201. /*静态作用域函数,意为更新,传入参数为缓存结构,返回当前缓存区已使用的内存偏移量*/
    202. static int update(printbuffer *p)
    203. {
    204. char *str;
    205. //运行时错误检查
    206. if (!p || !p->buffer)
    207. return 0;
    208. //将str定义到新加入缓存的数据的首地址。然后使用strlen计算新添加长度后加上原有的偏移量进行返回。
    209. str=p->buffer+p->offset;
    210. return p->offset+strlen(str);
    211. }
    212. /*静态作用域,将item中的数字打印成字符串,
    213. *当p不为NULL时,使用的是p所指向的内存缓冲区,当p为NULL时,使用的是单独申请的内存
    214. */
    215. static char *print_number(cJSON *item,printbuffer *p)
    216. {
    217. char *str=0;
    218. double d=item->valuedouble;
    219. //如果item的数值为0,使用两个字节,根据p是否为空,决定使用从哪里分配的缓存,并将字符串"0"拷贝到缓存中。
    220. if (d==0)
    221. {
    222. if (p) str=ensure(p,2);
    223. else str=(char*)cJSON_malloc(2); /* special case for 0. */
    224. if (str) strcpy(str,"0");
    225. }
    226. //如果item的数值为整数,21个char肯定装的下,并验证数值的正确性。
    227. //(fabs(((double)item->valueint)-d)<=DBL_EPSILON,标示差小于最小误差值,即可以理解为整数,并用INT_MAX、INT_MIN,验证合法性数据。
    228. else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
    229. {
    230. if (p) str=ensure(p,21);
    231. else str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */
    232. if (str) sprintf(str,"%d",item->valueint);
    233. }
    234. //走到这里,肯定是小数,选用64个字节较为合适。
    235. else
    236. {
    237. if (p) str=ensure(p,64);
    238. else str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */
    239. if (str)
    240. {
    241. //如果小数值特别接近零,并且整数部分值特别大,那么就以xxxxx.0方式输出
    242. if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d);
    243. //如果数值比1.0e-6小或者比1.0e9数值大,那么比较适合用科学计数法标示
    244. else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d);
    245. //剩余部分直接用小数点形式进行输出
    246. else sprintf(str,"%f",d);
    247. }
    248. }
    249. return str;
    250. }
    251. /*从16进制整数的字符串表达方式转换成无符号整数*/
    252. /*静态作用域,返回无符号整数,参数不可修改*/
    253. static unsigned parse_hex4(const char *str)
    254. {
    255. //将字符串的字符逐个取出进行分析,然后计算到整数中。然后将h左移一个直接再进行下一个数字的解析。最后完成4个字节的整数解析
    256. unsigned h=0;
    257. 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;
    258. h=h<<4;str++;
    259. 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;
    260. h=h<<4;str++;
    261. 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;
    262. h=h<<4;str++;
    263. 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;
    264. return h;
    265. }
    266. /*将输入的文本解析为非转意的c的字符串,然后填充到item中,应该保证str是已经去除开头空字符的串,
    267. *,此处的静态字符数组,是用来做utf格式转换的,返回值为解析出一个字符串之后的首地址
    268. */
    269. static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
    270. static const char *parse_string(cJSON *item,const char *str)
    271. {
    272. const char *ptr=str+1;
    273. char *ptr2;
    274. char *out;
    275. int len=0;
    276. unsigned uc,uc2;
    277. //如果str不以"引号,开头,那么不是一个字符串。
    278. if (*str!='"') {ep=str;return 0;} /* not a string! */
    279. while (*ptr!='"' && *ptr && ++len)
    280. if (*ptr++ == '\')
    281. ptr++; /* Skip escaped quotes. */
    282. //分配内存并进行检查
    283. out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */
    284. if (!out) return 0;
    285. ptr=str+1;ptr2=out;
    286. while (*ptr!='"' && *ptr)
    287. {
    288. if (*ptr!='\')
    289. *ptr2++=*ptr++;
    290. else
    291. {//如果以反斜杠开头的转义字符,则进行下诉的语义转换。只有utf格式转换不是很了解。
    292. ptr++;
    293. switch (*ptr)
    294. {
    295. case 'b': *ptr2++=''; break;
    296. case 'f': *ptr2++='f'; break;
    297. case 'n': *ptr2++=' '; break;
    298. case 'r': *ptr2++=' '; break;
    299. case 't': *ptr2++=' '; break;
    300. case 'u': /* transcode utf16 to utf8. */
    301. uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */
    302. //utf16和utf8之间格式的转换
    303. if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */
    304. if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */
    305. {
    306. if (ptr[1]!='\' || ptr[2]!='u') break; /* missing second-half of surrogate. */
    307. uc2=parse_hex4(ptr+3);ptr+=6;
    308. if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */
    309. uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
    310. }
    311. len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
    312. switch (len) {
    313. case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
    314. case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
    315. case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
    316. case 1: *--ptr2 =(uc | firstByteMark[len]);
    317. }
    318. ptr2+=len;
    319. break;
    320. default: *ptr2++=*ptr; break;
    321. }
    322. ptr++;
    323. }
    324. }
    325. //在结尾填充上'',然后将ptr结尾的引号跳过,并返回跳过后所处的位置。也做了对item中相应值的赋值操作。
    326. *ptr2=0;
    327. if (*ptr=='"') ptr++;
    328. item->valuestring=out;
    329. item->type=cJSON_String;
    330. return ptr;
    331. }
    332. /* Render the cstring provided to an escaped version that can be printed. */
    333. /*将提供的c字符串打印成可输出的无转意的版本,str为传入字符串,p为缓存指针,返回解析出的字串地址*/
    334. static char *print_string_ptr(const char *str,printbuffer *p)
    335. {
    336. const char *ptr;
    337. char *ptr2,*out;
    338. int len=0,flag=0;
    339. unsigned char token;
    340. //测试str中是否携带着空格,引号,以及转义字符反斜杠,结果用flag进行标识
    341. for (ptr=str;*ptr;ptr++)
    342. flag|=((*ptr>0 && *ptr<32)||(*ptr=='"')||(*ptr=='\'))?1:0;
    343. //如果没有携带上诉的字符,那么根据p指针使用ensure检查内存或者执行分配内存,并进行内存检查。
    344. //然后将str中的字符串前后加上引号,存储到out所指向的内存中,并将地址进行返回。
    345. if (!flag)
    346. {
    347. len=ptr-str;
    348. if (p)
    349. out=ensure(p,len+3);
    350. else
    351. out=(char*)cJSON_malloc(len+3);
    352. if (!out)
    353. return 0;
    354. ptr2=out;*ptr2++='"';
    355. strcpy(ptr2,str);
    356. ptr2[len]='"';
    357. ptr2[len+1]=0;
    358. return out;
    359. }
    360. //如果str为NULL,那么就只填上一个双引号间填充空的打印到内存或者缓存。
    361. if (!str)
    362. {
    363. if (p) out=ensure(p,3);
    364. else out=(char*)cJSON_malloc(3);
    365. if (!out) return 0;
    366. strcpy(out,"""");
    367. return out;
    368. }
    369. ptr=str;
    370. while ((token=*ptr) && ++len)
    371. {
    372. if (strchr(""\f ",token))
    373. len++;
    374. else if (token<32)
    375. len+=5;ptr++;
    376. }
    377. if (p) out=ensure(p,len+3);
    378. else out=(char*)cJSON_malloc(len+3);
    379. if (!out) return 0;
    380. //就是转义字符的处理基本上是按照原样输出到输出结果中的。
    381. ptr2=out;ptr=str;
    382. *ptr2++='"';
    383. while (*ptr)
    384. {
    385. if ((unsigned char)*ptr>31 && *ptr!='"' && *ptr!='\') *ptr2++=*ptr++;
    386. else
    387. {
    388. *ptr2++='\';
    389. switch (token=*ptr++)
    390. {
    391. case '\': *ptr2++='\'; break;
    392. case '"': *ptr2++='"'; break;
    393. case '': *ptr2++='b'; break;
    394. case 'f': *ptr2++='f'; break;
    395. case ' ': *ptr2++='n'; break;
    396. case ' ': *ptr2++='r'; break;
    397. case ' ': *ptr2++='t'; break;
    398. default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */
    399. }
    400. }
    401. }
    402. *ptr2++='"';*ptr2++=0;
    403. return out;
    404. }
    405. /* 使用一个对象调用 print_string_ptr (很有用的). */
    406. /*将item中的valuestring打印到分配的内存中或者是缓存p中。局部作用域,返回输出值*/
    407. static char *print_string(cJSON *item,printbuffer *p) {return print_string_ptr(item->valuestring,p);}
    408. /* 声明一些函数原型解析一个值,与打印一个值成对存在。. */
    409. static const char *parse_value(cJSON *item,const char *value);
    410. static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p);
    411. static const char *parse_array(cJSON *item,const char *value);
    412. static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p);
    413. static const char *parse_object(cJSON *item,const char *value);
    414. static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p);
    415. /* Utility to jump whitespace and cr/lf */
    416. /*跳过空字符或者一个控制字符,即在ascii码中小于等于32的字符*/
    417. /*静态作用域,常量返回值,其实还是这个串里面的地址。*/
    418. static const char *skip(const char *in)
    419. {
    420. while (in && *in && (unsigned char)*in<=32)
    421. in++;
    422. return in;
    423. }
    424. /*解析一个对象-创建一个新的根节点,然后进行填充*/
    425. cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
    426. {
    427. const char *end=0;
    428. //新建一个根节点,初始化错误标识,以及检测内存申请状态
    429. cJSON *c=cJSON_New_Item();
    430. ep=0;
    431. if (!c) return 0; /* memory fail */
    432. //先将传入的值,进行去除开头的不可见字符后,调用parse_value。
    433. end=parse_value(c,skip(value));
    434. //如果返回值为NULL,说明解析不成功,删除新创建的节点。
    435. if (!end)
    436. {
    437. cJSON_Delete(c);
    438. return 0;
    439. } /*如果解析失败,ep已经被指向了错误原因了。 */
    440. /* 如果我们要求以NULL结尾,那么检测是否以NULL进行结尾的。不然就释放内存并将ep指向出错的位置*/
    441. if (require_null_terminated)
    442. {
    443. end=skip(end);
    444. if (*end)
    445. {
    446. cJSON_Delete(c);
    447. ep=end;
    448. return 0;
    449. }
    450. }
    451. //将当前的结束位置进行赋值回传。
    452. if (return_parse_end)
    453. *return_parse_end=end;
    454. return c;
    455. }
    456. /* cJSON_Parse 调用缺省的选项进行解析*/
    457. cJSON *cJSON_Parse(const char *value)
    458. {
    459. return cJSON_ParseWithOpts(value,0,0);
    460. }
    461. /* 打印cJSON到文本中调用. print_value*/
    462. char *cJSON_Print(cJSON *item) {return print_value(item,0,1,0);}
    463. /* 打印无格式的cJSON到文本中调用. print_value*/
    464. char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0,0);}
    465. /* 打印cJSON到缓存中 调用. print_value*/
    466. /*item为待解析打印的json数据,prebuffer为预分配到缓存的大小,fmt控制是否需要json格式*/
    467. char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt)
    468. {
    469. printbuffer p;
    470. p.buffer=(char*)cJSON_malloc(prebuffer);
    471. p.length=prebuffer;
    472. p.offset=0;
    473. return print_value(item,0,fmt,&p);
    474. return p.buffer;
    475. }
    476. /*解析器的核心,遇到什么格式就进行什么格式的解析,从这里进入的解析一般还会递归回来调用这里的功能。*/
    477. static const char *parse_value(cJSON *item,const char *value)
    478. {
    479. if (!value) return 0; /* Fail on null. */
    480. //三种特定的数据类型,直接赋值item->type,并返回之后的数据。
    481. if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; }
    482. if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; }
    483. if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; }
    484. //如果是引号开头的值传入,那么就进行解析字符串。
    485. if (*value=='"') { return parse_string(item,value); }
    486. //解析数字
    487. if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); }
    488. //解析数组,
    489. if (*value=='[') { return parse_array(item,value); }
    490. //解析一个对象,递归着
    491. if (*value=='{') { return parse_object(item,value); }
    492. //如果到了这里,那么就置ep指针到出错的字串位置,然后返回0;
    493. ep=value;return 0; /* failure. */
    494. }
    495. /*打印一个值到文本方式中. */
    496. /*item为待打印的对象,depth 当前对象到根节点的深度 fmt 是否打印json格式, p为缓存入口*/
    497. /*返回将item中数据组织成一个串的起始地址,也会被递归的调用,一般情况下*/
    498. static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p)
    499. {
    500. char *out=0;
    501. if (!item) return 0;
    502. if (p)
    503. {//使用缓存模式进行打印,验证类型进入不同的打印方式cJSON_Object,cJSON_Array会递归调用的
    504. switch ((item->type)&255)
    505. {
    506. case cJSON_NULL: {out=ensure(p,5); if (out) strcpy(out,"null"); break;}
    507. case cJSON_False: {out=ensure(p,6); if (out) strcpy(out,"false"); break;}
    508. case cJSON_True: {out=ensure(p,5); if (out) strcpy(out,"true"); break;}
    509. case cJSON_Number: out=print_number(item,p);break;
    510. case cJSON_String: out=print_string(item,p);break;
    511. case cJSON_Array: out=print_array(item,depth,fmt,p);break;
    512. case cJSON_Object: out=print_object(item,depth,fmt,p);break;
    513. }
    514. }
    515. else
    516. {
    517. switch ((item->type)&255)
    518. {//不适用缓存方式进行打印值,cJSON_Object,cJSON_Array会递归调用的
    519. case cJSON_NULL: out=cJSON_strdup("null"); break;
    520. case cJSON_False: out=cJSON_strdup("false");break;
    521. case cJSON_True: out=cJSON_strdup("true"); break;
    522. case cJSON_Number: out=print_number(item,0);break;
    523. case cJSON_String: out=print_string(item,0);break;
    524. case cJSON_Array: out=print_array(item,depth,fmt,0);break;
    525. case cJSON_Object: out=print_object(item,depth,fmt,0);break;
    526. }
    527. }
    528. return out;
    529. }
    530. /* 根据输入的文本,建立一个数组 */
    531. static const char *parse_array(cJSON *item,const char *value)
    532. {
    533. cJSON *child;
    534. if (*value!='[') {ep=value;return 0;} /* not an array! */
    535. //验证为数组的value,对类型进行赋值,对value进行去除不可见字符,并判断空对象数组。
    536. item->type=cJSON_Array;
    537. value=skip(value+1);
    538. if (*value==']') return value+1; /* empty array. */
    539. //为数组建立一个孩子节点。并检查内存分配,跳过不可见字符,并调用parse_value取得值
    540. item->child=child=cJSON_New_Item();
    541. if (!item->child) return 0; /* memory fail */
    542. value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */
    543. if (!value) return 0;
    544. //如果还有兄弟节点,即数组有多个元素,那么进行循环创建,链接,解析值。
    545. while (*value==',')
    546. {
    547. cJSON *new_item;
    548. if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
    549. child->next=new_item;new_item->prev=child;child=new_item;
    550. value=skip(parse_value(child,skip(value+1)));
    551. if (!value) return 0; /* memory fail */
    552. }
    553. //检查是否存在数组结束的右括号,然后返回结束位置,或者置位错误指向出错位置,然后返回0
    554. if (*value==']') return value+1; /* end of array */
    555. ep=value;return 0; /* malformed. */
    556. }
    557. /* 将对象数组打印成文本 */
    558. static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p)
    559. {
    560. char **entries;
    561. char *out=0,*ptr,*ret;int len=5;
    562. //获得数组的孩子,即第一个元素
    563. cJSON *child=item->child;
    564. int numentries=0,i=0,fail=0;
    565. size_t tmplen=0;
    566. //计算有多少个元素在这个数组里。
    567. /* How many entries in the array? */
    568. while (child) numentries++,child=child->next;
    569. /*如果这个数组为空,那么就打印一个[]出来就好了。*/
    570. if (!numentries)
    571. {
    572. if (p) out=ensure(p,3);
    573. else out=(char*)cJSON_malloc(3);
    574. if (out) strcpy(out,"[]");
    575. return out;
    576. }
    577. //如果是以缓存方式打印出来的话进这个分支
    578. if (p)
    579. {
    580. /* Compose the output array. */
    581. //先将[括号写进缓存中
    582. i=p->offset;
    583. ptr=ensure(p,1);if (!ptr) return 0; *ptr='['; p->offset++;
    584. //从第一个孩子开始进行遍历
    585. child=item->child;
    586. while (child && !fail)
    587. { //打印这个孩子值到缓存中,并更新缓存中offset值。
    588. print_value(child,depth+1,fmt,p);
    589. p->offset=update(p);
    590. //判断是否需要格式打印,并根据此进行分配空间,格式化的会在有空格符号插入
    591. if (child->next)
    592. {
    593. len=fmt?2:1;ptr=ensure(p,len+1);
    594. if (!ptr)
    595. return 0;
    596. *ptr++=',';
    597. if(fmt)
    598. *ptr++=' ';
    599. *ptr=0;
    600. p->offset+=len;
    601. }
    602. //遍历传递
    603. child=child->next;
    604. }
    605. //输出右括号,并将out指向这次填充的最开始处
    606. ptr=ensure(p,2);if (!ptr) return 0; *ptr++=']';*ptr=0;
    607. out=(p->buffer)+i;
    608. }
    609. else
    610. {//不使用缓存,那么就根据元素个数申请二维字符指针,并检查内存申请,初始化指针为NULL。
    611. /* Allocate an array to hold the values for each */
    612. entries=(char**)cJSON_malloc(numentries*sizeof(char*));
    613. if (!entries) return 0;
    614. memset(entries,0,numentries*sizeof(char*));
    615. /* 遍历所有的元素 */
    616. child=item->child;
    617. while (child && !fail)
    618. {
    619. //使用中间变量进行遍历并将结果全都放入二维指针中。
    620. ret=print_value(child,depth+1,fmt,0);
    621. entries[i++]=ret;
    622. //判断是否解析值出错。并计算长度
    623. if (ret)
    624. len+=strlen(ret)+2+(fmt?1:0);
    625. else
    626. fail=1;
    627. child=child->next;
    628. }
    629. //如果没有解析错误,那么尝试分配一个输出的数组。
    630. /* If we didn't fail, try to malloc the output string */
    631. if (!fail) out=(char*)cJSON_malloc(len);
    632. /* If that fails, we fail. */
    633. //如果分配失败,那么这次打印就失败了。
    634. if (!out) fail=1;
    635. /* 处理错误情况,将之前申请的所有内存进行释放*/
    636. if (fail)
    637. {
    638. for (i=0;i<numentries;i++)
    639. if (entries[i])
    640. cJSON_free(entries[i]);
    641. cJSON_free(entries);
    642. return 0;
    643. }
    644. //没有错误情况,那么就将所有的字符串全都复制到新开辟的大的串中,准备输出。
    645. /* Compose the output array. */
    646. *out='[';
    647. ptr=out+1;*ptr=0;
    648. for (i=0;i<numentries;i++)
    649. {
    650. tmplen=strlen(entries[i]);memcpy(ptr,entries[i],tmplen);ptr+=tmplen;
    651. if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}
    652. cJSON_free(entries[i]);
    653. }
    654. cJSON_free(entries);
    655. *ptr++=']';*ptr++=0;
    656. }
    657. return out;
    658. }
    659. /* 根据文本输入,创建一个json对象. */
    660. static const char *parse_object(cJSON *item,const char *value)
    661. {
    662. cJSON *child;
    663. if (*value!='{') {ep=value;return 0;} /* 文本不是对象格式 */
    664. //设置类型,跳过不可见字符,并检查是否为空的数组
    665. item->type=cJSON_Object;
    666. value=skip(value+1);
    667. if (*value=='}') return value+1; /* empty array. */
    668. //创建一个孩子对象,检查内存,
    669. item->child=child=cJSON_New_Item();
    670. if (!item->child) return 0;
    671. //使用child->valuestring获得待解析的字符串,然后将child->valuestring的值给child->string
    672. value=skip(parse_string(child,skip(value)));
    673. if (!value) return 0;
    674. child->string=child->valuestring;child->valuestring=0;
    675. //检查时候对应有值,成对,不然就错误
    676. if (*value!=':') {ep=value;return 0;} /* fail! */
    677. //将:后的值获取出来赋值给child,并且指针移到获取该值后字串的第一个可见字符处
    678. value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
    679. if (!value) return 0;
    680. //如果存在,号 那么说明后续还要继续进行解析。并进行循环。
    681. while (*value==',')
    682. {//创建对象,并链接到链表中,然后进行解析值。如果出现了object,那么还是要递归调用。
    683. cJSON *new_item;
    684. if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
    685. child->next=new_item;new_item->prev=child;child=new_item;
    686. value=skip(parse_string(child,skip(value+1)));
    687. if (!value) return 0;
    688. child->string=child->valuestring;child->valuestring=0;
    689. if (*value!=':') {ep=value;return 0;} /* fail! */
    690. value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
    691. if (!value) return 0;
    692. }
    693. //检查是否出现结束的右大括号。返回最后一个值结束的位置,或者返回0并置位ep
    694. if (*value=='}') return value+1; /* end of array */
    695. ep=value;return 0; /* malformed. */
    696. }
    697. /* 将一个对象,打印到文本中 */
    698. static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p)
    699. {
    700. char **entries=0,**names=0;
    701. char *out=0,*ptr,*ret,*str;
    702. int len=7,i=0,j;
    703. //获取根节点的孩子节点
    704. cJSON *child=item->child;
    705. int numentries=0,fail=0;
    706. size_t tmplen=0;
    707. /* Count the number of entries. */
    708. //计算其内包含的节点个数
    709. while (child) numentries++,child=child->next;
    710. /* Explicitly handle empty object case */
    711. //如果是个空的json对象,那么就打印一个空的花括号对。根据是否有格式选择转义字符
    712. //根据p决定将这个字符串输出的位置。
    713. //这里depth可以计算应该缩进的字符数
    714. if (!numentries)
    715. {
    716. if (p) out=ensure(p,fmt?depth+4:3);
    717. else out=(char*)cJSON_malloc(fmt?depth+4:3);
    718. if (!out) return 0;
    719. ptr=out;*ptr++='{';
    720. if (fmt) {*ptr++=' ';for (i=0;i<depth-1;i++) *ptr++=' ';}
    721. *ptr++='}';*ptr++=0;
    722. return out;
    723. }
    724. //如果是要求打印到缓存中去,那么进入这个处理逻辑
    725. if (p)
    726. {
    727. /* Compose the output: */
    728. //计算内训需求,将左括号和换行符输出到缓存中
    729. i=p->offset;
    730. len=fmt?2:1; ptr=ensure(p,len+1); if (!ptr) return 0;
    731. *ptr++='{'; if (fmt) *ptr++=' '; *ptr=0; p->offset+=len;
    732. //遍历孩子节点的子节点
    733. child=item->child;depth++;
    734. while (child)
    735. {//fmt格式输出,那么先打印应该输入的缩进再说。
    736. if (fmt)
    737. {
    738. ptr=ensure(p,depth); if (!ptr) return 0;
    739. for (j=0;j<depth;j++) *ptr++=' ';
    740. p->offset+=depth;
    741. }
    742. //打印字符串到缓存中,并更新offset值
    743. print_string_ptr(child->string,p);
    744. p->offset=update(p);
    745. //处理冒号和格式
    746. len=fmt?2:1;
    747. ptr=ensure(p,len); if (!ptr) return 0;
    748. *ptr++=':';if (fmt) *ptr++=' ';
    749. p->offset+=len;
    750. //将值解析出来放到p指向的缓存中,然后更新offset
    751. print_value(child,depth,fmt,p);
    752. p->offset=update(p);
    753. //计算长度,确保内存容量,检查是否还有后续节点,然后换行后进行下一个节点的遍历
    754. len=(fmt?1:0)+(child->next?1:0);
    755. ptr=ensure(p,len+1); if (!ptr) return 0;
    756. if (child->next) *ptr++=',';
    757. if (fmt) *ptr++=' ';*ptr=0;
    758. p->offset+=len;
    759. child=child->next;
    760. }
    761. //将右括号合上
    762. ptr=ensure(p,fmt?(depth+1):2); if (!ptr) return 0;
    763. if (fmt) for (i=0;i<depth-1;i++) *ptr++=' ';
    764. *ptr++='}';*ptr=0;
    765. out=(p->buffer)+i;
    766. }
    767. else
    768. {//不使用缓存的情况下,先分配二维字符指针出来,并检查内存。初始化为0
    769. /* Allocate space for the names and the objects */
    770. entries=(char**)cJSON_malloc(numentries*sizeof(char*));
    771. if (!entries) return 0;
    772. names=(char**)cJSON_malloc(numentries*sizeof(char*));
    773. if (!names) {cJSON_free(entries);return 0;}
    774. memset(entries,0,sizeof(char*)*numentries);
    775. memset(names,0,sizeof(char*)*numentries);
    776. /* Collect all the results into our arrays: */
    777. //循环递归将所有的值都挂载在二维数组上
    778. child=item->child;depth++;if (fmt) len+=depth;
    779. while (child)
    780. {
    781. names[i]=str=print_string_ptr(child->string,0);
    782. entries[i++]=ret=print_value(child,depth,fmt,0);
    783. if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
    784. child=child->next;
    785. }
    786. /* Try to allocate the output string */
    787. //申请一个总的输出字串数组,检查内存
    788. if (!fail) out=(char*)cJSON_malloc(len);
    789. if (!out) fail=1;
    790. /* Handle failure */
    791. //分配失败,那么将所有的已分配的内存均进行释放
    792. if (fail)
    793. {
    794. for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}
    795. cJSON_free(names);cJSON_free(entries);
    796. return 0;
    797. }
    798. //将打印到各个子内存中的数据都拷贝一份到要返回的大内存中。并将原有的子内存进行释放
    799. /* Compose the output: */
    800. *out='{';ptr=out+1;if (fmt)*ptr++=' ';*ptr=0;
    801. for (i=0;i<numentries;i++)
    802. {
    803. if (fmt) for (j=0;j<depth;j++) *ptr++=' ';
    804. tmplen=strlen(names[i]);memcpy(ptr,names[i],tmplen);ptr+=tmplen;
    805. *ptr++=':';if (fmt) *ptr++=' ';
    806. strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
    807. if (i!=numentries-1) *ptr++=',';
    808. if (fmt) *ptr++=' ';*ptr=0;
    809. cJSON_free(names[i]);cJSON_free(entries[i]);
    810. }
    811. //补齐右括号
    812. cJSON_free(names);cJSON_free(entries);
    813. if (fmt) for (i=0;i<depth-1;i++) *ptr++=' ';
    814. *ptr++='}';*ptr++=0;
    815. }
    816. return out;
    817. }
    818. /* Get Array size/item / object item. */
    819. //获取数组的元素个数
    820. int cJSON_GetArraySize(cJSON *array)
    821. {
    822. cJSON *c=array->child;
    823. int i=0;
    824. while(c)
    825. i++,c=c->next;
    826. return i;
    827. }
    828. //获取array中第item个元素的入口
    829. cJSON *cJSON_GetArrayItem(cJSON *array,int item)
    830. {
    831. cJSON *c=array->child;
    832. while (c && item>0)
    833. item--,c=c->next;
    834. return c;
    835. }
    836. //获取对象object中名字为string的item。
    837. cJSON *cJSON_GetObjectItem(cJSON *object,const char *string)
    838. {
    839. cJSON *c=object->child;
    840. while (c && cJSON_strcasecmp(c->string,string))
    841. c=c->next;
    842. return c;
    843. }
    844. /* Utility for array list handling. */
    845. //将item链接到prev之后
    846. static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
    847. /* Utility for handling references. */
    848. //创建一个参照对象,复制一个item,新item的type为cJSON_IsReference
    849. static cJSON *create_reference(cJSON *item)
    850. {
    851. cJSON *ref=cJSON_New_Item();
    852. if (!ref)
    853. return 0;
    854. memcpy(ref,item,sizeof(cJSON));
    855. ref->string=0;
    856. ref->type|=cJSON_IsReference;
    857. ref->next=ref->prev=0;
    858. return ref;
    859. }
    860. /* Add item to array/object. */
    861. /*添加项目到数组或者对象之中*/
    862. //将item添加到array中
    863. void cJSON_AddItemToArray(cJSON *array, cJSON *item)
    864. {//获得array的第一个节点
    865. cJSON *c=array->child;
    866. if (!item)
    867. return;
    868. if (!c)//如果原本就是空的数组
    869. {array->child=item;}
    870. else
    871. {//找到最后一个节点,然后将item挂上
    872. while (c && c->next)
    873. c=c->next;
    874. suffix_object(c,item);
    875. }
    876. }
    877. /*将一个项目item,名字为string,添加到object中*/
    878. void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item)
    879. {
    880. if (!item) return;
    881. if (item->string) //清理原有的名字
    882. cJSON_free(item->string);
    883. item->string=cJSON_strdup(string);
    884. cJSON_AddItemToArray(object,item);//将object当成一个array来看待
    885. }
    886. //将一个名字为字符串常量的item,添加到object中,设置type为cJSON_StringIsConst
    887. void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item)
    888. {
    889. if (!item) return;
    890. if (!(item->type&cJSON_StringIsConst) && item->string)
    891. cJSON_free(item->string);
    892. item->string=(char*)string;
    893. item->type|=cJSON_StringIsConst;
    894. cJSON_AddItemToArray(object,item);
    895. }
    896. //将item复制一份出来,添加到array中
    897. void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));}
    898. //将名字为string的item复制一份出来,添加到object中
    899. void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));}
    900. //将array中的第which个item从array中摘取下来,作为返回值。
    901. cJSON *cJSON_DetachItemFromArray(cJSON *array,int which)
    902. {
    903. cJSON *c=array->child;
    904. while (c && which>0)
    905. c=c->next,which--;
    906. if (!c) return 0;
    907. if (c->prev)//找到第which个item,从链中摘下来
    908. c->prev->next=c->next;
    909. if (c->next)
    910. c->next->prev=c->prev;
    911. if (c==array->child) //如果是第一个孩子节点
    912. array->child=c->next;
    913. c->prev=c->next=0;
    914. return c;
    915. }
    916. //从array中删除第which个元素
    917. void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
    918. //从object中摘除名字为string的item,返回这个item
    919. cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string)
    920. {
    921. int i=0;
    922. cJSON *c=object->child;
    923. while (c && cJSON_strcasecmp(c->string,string))
    924. i++,c=c->next;//遍历找到这个string名字的item
    925. if (c)//找到了就从object中把它移除。
    926. return cJSON_DetachItemFromArray(object,i);
    927. return 0;
    928. }
    929. //将指定名字string的item从object中删除
    930. void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
    931. /* 插入一个newitem到第which个位置,如果不存在这个位置,那么就随意加到一个位置*/
    932. void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem)
    933. {
    934. cJSON *c=array->child;
    935. while (c && which>0)
    936. c=c->next,which--;
    937. if (!c)
    938. {//如果遍历完或者which个,没有找到有效的item,那么就将newitem插入到array中
    939. cJSON_AddItemToArray(array,newitem);
    940. return;
    941. }
    942. //将newitem挂载节点c的前面
    943. newitem->next=c;
    944. newitem->prev=c->prev;
    945. c->prev=newitem;
    946. if (c==array->child) //为第一个节点
    947. array->child=newitem;
    948. else
    949. newitem->prev->next=newitem;
    950. }
    951. void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem)
    952. {
    953. cJSON *c=array->child;
    954. while (c && which>0)
    955. c=c->next,which--;
    956. if (!c)//找不到第which个item
    957. return;
    958. //将newitem插入到第which个item个位置,将原有的item摘下来(c)。
    959. newitem->next=c->next;
    960. newitem->prev=c->prev;
    961. if (newitem->next)
    962. newitem->next->prev=newitem;
    963. if (c==array->child)
    964. array->child=newitem;
    965. else
    966. newitem->prev->next=newitem;
    967. c->next=c->prev=0;
    968. cJSON_Delete(c);//将摘下来的c节点清除掉
    969. }
    970. //将object中名字为string的item替换为newitem
    971. void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem)
    972. {
    973. int i=0;
    974. cJSON *c=object->child;
    975. while(c && cJSON_strcasecmp(c->string,string))
    976. i++,c=c->next;//找到名字为string的这个item
    977. if(c)
    978. {
    979. newitem->string=cJSON_strdup(string);//需要重新分配一个内存作为名字string的值
    980. cJSON_ReplaceItemInArray(object,i,newitem);//插入到前文找到的第i个位置
    981. }
    982. }
    983. /* Create basic types: */
    984. //创建一个NULL类型的cjson对象object
    985. cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
    986. //创建一个True类型的cjson对象object
    987. cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
    988. //创建一个False类型的cjson对象object
    989. cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
    990. //创建一个Bool类型的cjson对象object,然后根据b的值决定item->type是等于cJSON_True还是cJSON_False
    991. cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
    992. //创建一个cJSON_Number类型的cjson对象object,其值为num
    993. 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;}
    994. //创建一个cJSON_String类型的cjson对象object,其值为string
    995. cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;}
    996. //创建一个cJSON_Array类型的cjson对象object
    997. cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
    998. //创建一个cJSON_Object类型的cjson对象object
    999. cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}
    1000. /* Create Arrays: */
    1001. /*创建数组*/
    1002. //创建一个int类型的array,array中有count个元素,值分别为number
    1003. cJSON *cJSON_CreateIntArray(const int *numbers,int count)
    1004. {
    1005. int i;
    1006. cJSON *n=0,*p=0,*a=cJSON_CreateArray();//创建一个array
    1007. for(i=0;a && i<count;i++)
    1008. {//创建number类型的对象,并赋值
    1009. n=cJSON_CreateNumber(numbers[i]);
    1010. if(!i)//第一个元素为孩子节点
    1011. a->child=n;
    1012. else //其他为兄弟节点挂接方式
    1013. suffix_object(p,n);
    1014. p=n;
    1015. }
    1016. return a;
    1017. }
    1018. //创建一个float类型的array,array中有count个元素,值分别为number
    1019. 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;}
    1020. //创建一个double类型的array,array中有count个元素,值分别为number
    1021. 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;}
    1022. //创建一个string类型的array,array中有count个元素,值分别为number
    1023. 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;}
    1024. /* 复制item并返回,recurse决定是否递归的将item的子节点也都复制一份 */
    1025. cJSON *cJSON_Duplicate(cJSON *item,int recurse)
    1026. {
    1027. cJSON *newitem,*cptr,*nptr=0,*newchild;
    1028. /* Bail on bad ptr */
    1029. //item值非法
    1030. if (!item) return 0;
    1031. /* Create new item */
    1032. //创建一个新的item,并检查内存
    1033. newitem=cJSON_New_Item();
    1034. if (!newitem) return 0;
    1035. /* Copy over all vars */
    1036. //拷贝所有的值到newitem中
    1037. newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble;
    1038. if (item->valuestring)
    1039. {
    1040. newitem->valuestring=cJSON_strdup(item->valuestring);
    1041. if (!newitem->valuestring)
    1042. {
    1043. cJSON_Delete(newitem);
    1044. return 0;
    1045. }
    1046. }//如果是valuestring的值
    1047. if (item->string)
    1048. {
    1049. newitem->string=cJSON_strdup(item->string);
    1050. if (!newitem->string)
    1051. {cJSON_Delete(newitem);return 0;}
    1052. }//名字name的值
    1053. /* If non-recursive, then we're done! */
    1054. //判断是否需要递归的进行复制子节点
    1055. if (!recurse) return newitem;
    1056. /* Walk the ->next chain for the child. */
    1057. //走到子节点上,然后遍历整个链表进行递归的复制。
    1058. cptr=item->child;
    1059. while (cptr)
    1060. {//是个递归的过程,可以尝试gdb单步跟踪理解。
    1061. newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */
    1062. if (!newchild) {cJSON_Delete(newitem);return 0;}//如果没有成功申请子节点内存,那么就报错返回
    1063. if (nptr)
    1064. {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* 是兄弟节点则挂链*/
    1065. else
    1066. {newitem->child=newchild;nptr=newchild;} /* 是孩子节点则设置指针 */
    1067. cptr=cptr->next;
    1068. }
    1069. return newitem;
    1070. }
    1071. //一个mini版本的json数据遍历功能
    1072. void cJSON_Minify(char *json)
    1073. {
    1074. char *into=json;
    1075. while (*json)
    1076. {
    1077. if (*json==' ') json++;
    1078. else if (*json==' ') json++; /* Whitespace characters. */
    1079. else if (*json==' ') json++;
    1080. else if (*json==' ') json++;
    1081. else if (*json=='/' && json[1]=='/') while (*json && *json!=' ') json++; /* double-slash comments, to end of line. */
    1082. else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} /* multiline comments. */
    1083. else if (*json=='"'){*into++=*json++;while (*json && *json!='"'){if (*json=='\') *into++=*json++;*into++=*json++;}*into++=*json++;} /* string literals, which are " sensitive. */
    1084. else *into++=*json++; /* All other characters. */
    1085. }
    1086. *into=0; /* and null-terminate. */
    1087. }









        

    附件列表

    • 相关阅读:
      [Swift]LeetCode374. 猜数字大小 | Guess Number Higher or Lower
      [Swift]LeetCode371. 两整数之和 | Sum of Two Integers
      [Swift]LeetCode367. 有效的完全平方数 | Valid Perfect Square
      [Swift]LeetCode350. 两个数组的交集 II | Intersection of Two Arrays II
      [Swift]LeetCode349. 两个数组的交集 | Intersection of Two Arrays
      [Swift实际操作]七、常见概念-(9)使用定时组件Timer执行定时任务
      [Swift实际操作]七、常见概念-(8)日历Calendar和时区TimerZone
      浅谈广告交易系统
      浅谈广告交易系统
      6种排序算法的简洁实现:冒泡、选择、插入、归并、快速、堆
    • 原文地址:https://www.cnblogs.com/cfzhang/p/99da02ab2f02520d458c415a5314f83d.html
    Copyright © 2011-2022 走看看