当前位置:网站首页>cJSON源码阅读笔记
cJSON源码阅读笔记
2022-07-22 11:03:00 【panfei263031】
数据结构
cjson中有三个重要的结构体:
- json节点,用来存储单个key、value对,节点中有prev和next指针,可以形成链表,也有child指针,可以用来指向object中的子节点。有多少个key、value对,就有多少个节点。
typedef struct cJSON
{
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON* next;
struct cJSON* prev;
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
struct cJSON* child;
/* The type of the item, as above. */
int type;
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
char* valuestring;
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
int valueint;
/* The item's number, if type==cJSON_Number */
double valuedouble;
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
char* string;
} cJSON;
此结构体描述了json中每一个键值对。其中string记录了节点的key,value则记录在valuestring、valueint或者valuedouble中。type表示节点的类型,便于在调用cJSON_Parse后判断节点类型以及在打印json时根据type打印不同的类型的节点。
简单的节点,例如数字节点、字符串节点、bool节点等,可以直接用该结构体描述,复杂的节点,例如object、数组,则是通过结构体中的next、prev、child指针来记录的。
举个最简单的json的例子:
{
"aa": true,
"name": "xiaoming",
"score": 90,
"height": 150,
"age": 11
}
最外层的{}是一个object,也就是一个节点,这里把它命名为root,只不过root的type是object。被{}括起来的5个节点,都是root节点的儿子节点。这5个儿子节点是并列关系,相互之间通过next和prev指针相互指向,将这5个节点串在一起成为一个双向链表。aa这个节点作为此链表的head节点,将root的child指针指向aa节点,就表示了父子关系,于是通过根(父)节点root就能访问整个json。
对于包含object的情况,稍有复杂,但是基本原理和上面的例子一样。举个例子:
{
"aa": true,
"name": "xiaoming",
"score": {
"chinese": 80,
"math": 80,
"english": 80,
},
"height": 150,
"age": 11
}
此例中,score节点从一个数字节点变成了一个object,其type也从number变成了object。此object和根节点root的区别是,此object有key值,但是root节点没有key。在这里,score节点和其他四个节点依然是并列关系,他们都是root的子节点,score节点依然和其他四个节点依然形成一个双向链表。那score节点中的三个子节点如何表示呢?同样,这三个子节点通过彼此的next和prev指针相互串联,形成一个双向链表,chinese作为此链表的head节点。score的child指针指向chinese节点,于是通过根节点root就可以访问整个json。
再来看看包含数组的情况。数组中,我们分两种情况来描述:
- 数组中只有普通节点的情况:
{
"aa": true,
"name": "xiaoming",
"classmate": ["piter", "tony", "andy"],
"height": 150,
"age": 11
}
这种情况下,数组中的三个元素,虽然没有key,但是在cjson中,依然把他们当做三个节点来处理。这三个元素是字符串节点,字符串被存放在节点的valuestring中,key即结构体中的string为空。这三个节点被解析后,处理方式和object类似,三个元素被当做父节点classmate的儿子节点,三个儿子节点形成双向链表,classmate的child指针指向piter节点。
- 数组中包含结构体的情况:
{
"aa": true,
"name": "xiaoming",
"classmate": [{
"name": "piter",
"age": 12
}, {
"name": "tony",
"age": 11
}, {
"name": "andy",
"age": 12
}
],
"height": 150,
"age": 11
}
不管是普通的数字节点、字符串节点,还是复杂的结构、数组,还是数组中包含结构体,都是有基本的链表数据结构表示的。整个json被解析后,就相当于一颗数,root节点就是整棵树的跟。
上述描述了cjson中组织数据的基本形式,在复杂的json也都是由上面几种基本形式组成的,理解了上述基本的json结构的数据组织形式,就可以轻松阅读cjson的源码
- 用于解码的时候,存放被解析的字符串的属性的结构体,
以下两个结构体是在解码和编码的时候高频使用的结构体,记录了解码和编码的基本信息。
typedef struct
{
const unsigned char* content; //指向被解析字符串
size_t length; //被解析字符串总长度。可用于判断解析是否结束,以及json是否合法。
size_t offset; //当前解析位置,此值随着解析的过程不断增加对应的字符串长度,直到解析完后,offset等于lenth。
size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */
internal_hooks hooks;
} parse_buffer;
解码的入口函数是parse_value,此函数中会根据不同类型的value值例如bool、字符串、数字、object等进入不同的处理。由于根节点是{},相当于一个没有kay的object,所以一开始调用parse_value就会进入object的解析中。结构体parse_buffer的offset成员记录了解析的当前位置,解析完之后,offset等于lenth。
- 用于编码的时候,存放编码字符串的结构体:
typedef struct
{
unsigned char* buffer;
size_t length;
size_t offset;
size_t depth; /* current nesting depth (for formatted printing) */
cJSON_bool noalloc;
cJSON_bool format; /* is this print a formatted print */
internal_hooks hooks;
} printbuffer;
编码的入口函数是print_value,此函数中会根据不同的值的类型,调用不同的打印接口。由于根节点{}相当于一个没有key的object,所以一开始就会进入object的打印。
高频使用的小工具函数
- can_read
- buffer_at_offset
- can_access_at_index
- cannot_access_at_index
- buffer_skip_whitespace
- ensure
总之,cjson的源码还是很容易读懂的。是目前为止本人感觉最简单的开源项目代码。
其他网友的cjson源码分析笔记:
https://blog.csdn.net/coding__madman/article/details/51304093文末有更多链接。
边栏推荐
猜你喜欢
Buuctf breakthrough diary -- [ciscn2019 North China division Day2 web1]hack world
Learning notes of wechat applet introduction tutorial - operation feedback of UI chapter
【PyTorch深度学习实践】学习笔记 第三节 梯度下降
Buuctf breakthrough diary -- [netding cup 2020 Qinglong group]areuserialz
【PyTorch深度学习实践】学习笔记 第四节 反向传播
8. Memory and disk management
[lttng learning journey] - a preliminary study of trace view
毕设路线—pytorch环境下的深度学习的高光谱图像分类问题
[lttng learning journey] - trace control -- advanced
Buuctf breakthrough diary 04 -- [strong net cup 2019] casual note 1
随机推荐
[LTTng学习之旅]------开始之前
5. Network and security
Recent research directions
YOLO9000: Better, Faster, Stronger
Buuctf entry diary -- [mrctf2020] how about you (super detailed)
Juc-7.2-thread collaboration condition
BUUCTF闯关日记--[极客大挑战 2019]HardSQL1
Process control - if statement
英语四六级听力有线传输无线发射系统方案
Buuctf breakthrough diary 03 -- [geek challenge 2019] havefun1
pkg-config 查找库和用于编译
1.虚拟化和容器技术
Buuctf entry diary -- [nctf2019]fake XML Cookbook
大喇叭疫情防控广播解决方案
简单句(Simple sentences)-one
Interview of 2020 Central South University information and communication summer camp
On the characteristics of filter pseudo protocol
(7) Vulhub column: log4j Remote Code Execution Vulnerability recurrence
Chapter 4: Minio's pre signed URLs upload files
How to do research and development lean demand management well