├── .gitattributes ├── LICENSE ├── demo └── cson_test.c ├── readme.md └── src ├── cJSON.c ├── cJSON.h ├── cson.c └── cson.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Letter 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /demo/cson_test.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cson_test.c 3 | * @author Letter (NevermindZZT@gmail.com) 4 | * @brief 5 | * @version 0.1 6 | * @date 2019-08-27 7 | * 8 | * @copyright (c) 2019 Letter 9 | * 10 | */ 11 | 12 | #include "shell.h" 13 | #include "log.h" 14 | #include "cson.h" 15 | 16 | 17 | struct subtest 18 | { 19 | int id; 20 | char *test; 21 | }; 22 | 23 | struct test 24 | { 25 | char id; 26 | short num; 27 | int max; 28 | double value; 29 | char *name; 30 | struct subtest *sub; 31 | CsonList *list; 32 | char *str[2]; 33 | CsonList *charList; 34 | CsonList *strList; 35 | char *subjson; 36 | }; 37 | 38 | CsonModel subModel[] = 39 | { 40 | CSON_MODEL_OBJ(struct subtest), 41 | CSON_MODEL_INT(struct subtest, id), 42 | CSON_MODEL_STRING(struct subtest, test) 43 | }; 44 | 45 | 46 | CsonModel model[] = 47 | { 48 | CSON_MODEL_OBJ(struct test), 49 | CSON_MODEL_CHAR(struct test, id), 50 | CSON_MODEL_SHORT(struct test, num), 51 | CSON_MODEL_INT(struct test, max), 52 | CSON_MODEL_DOUBLE(struct test, value), 53 | CSON_MODEL_STRING(struct test, name), 54 | CSON_MODEL_STRUCT(struct test, sub, subModel, sizeof(subModel)/sizeof(CsonModel)), 55 | CSON_MODEL_LIST(struct test, list, subModel, sizeof(subModel)/sizeof(CsonModel)), 56 | CSON_MODEL_ARRAY(struct test, str, CSON_TYPE_STRING, 2), 57 | CSON_MODEL_LIST(struct test, charList, CSON_MODEL_INT_LIST, CSON_BASIC_LIST_MODEL_SIZE), 58 | CSON_MODEL_LIST(struct test, strList, CSON_MODEL_STRING_LIST, CSON_BASIC_LIST_MODEL_SIZE), 59 | CSON_MODEL_JSON(struct test, subjson) 60 | }; 61 | 62 | 63 | 64 | 65 | void csonTest(void) 66 | { 67 | char *jsonStr = "{\"id\": 1, \"num\": 300, \"max\": 1000, \"value\": 10.3, \"name\": \"letter\", " 68 | "\"sub\": {\"id\": 20, \"test\": \"hello world\"}," 69 | " \"list\": [{\"id\": 21, \"test\": \"hello cson\"}, {\"id\": 22, \"test\": \"hello letter\"}]," 70 | "\"str\": [\"array1\", \"array2\"]," 71 | "\"charList\": [1, 12, 52], " 72 | "\"strList\": [\"str1\", \"str2\"]," 73 | "\"subjson\":{\"test\": \"hello\"}}"; 74 | 75 | struct test *st = csonDecode(jsonStr, model, sizeof(model)/sizeof(CsonModel)); 76 | logDebug("json 0x%08x, id: %d, num: %d, max: %d, value: %f, name: %s\r\nsub: id: %d, test: %s", 77 | st, st->id, st->num, st->max, st->value, st->name, st->sub ? st->sub->id : 0, st->sub ? st->sub->test : "null"); 78 | logDebug("str: %s %s", st->str[0], st->str[1]); 79 | CsonList *p = st->list; 80 | while (p) 81 | { 82 | struct subtest *sst = p->obj; 83 | if (p->obj) 84 | { 85 | logDebug("list: id: %d, test: %s", sst->id, sst->test); 86 | } 87 | else 88 | { 89 | logDebug("list: null"); 90 | } 91 | p = p->next; 92 | } 93 | p = st->charList; 94 | while (p) 95 | { 96 | int sst = (int)(p->obj); 97 | if (p->obj) 98 | { 99 | logDebug("list: int: %d", sst); 100 | } 101 | p = p->next; 102 | } 103 | p = st->strList; 104 | while (p) 105 | { 106 | char *sst = p->obj; 107 | if (p->obj) 108 | { 109 | logDebug("list: str: %s", sst); 110 | } 111 | p = p->next; 112 | } 113 | logDebug("subjson: %s", st->subjson); 114 | 115 | char *root = csonEncode(st, model, sizeof(model)/sizeof(CsonModel), 512, 0); 116 | printf("encode: %s", root); 117 | 118 | csonFreeJson(root); 119 | csonFree(st, model, sizeof(model)/sizeof(CsonModel)); 120 | } 121 | SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC), 122 | csonTest, csonTest, test); 123 | 124 | 125 | /** 项目结构体 */ 126 | struct project 127 | { 128 | int id; 129 | char *name; 130 | }; 131 | 132 | /** 仓库结构体 */ 133 | struct hub 134 | { 135 | int id; 136 | char *user; 137 | struct project *cson; 138 | }; 139 | 140 | /** 项目结构体数据模型 */ 141 | CsonModel projectModel[] = 142 | { 143 | CSON_MODEL_OBJ(struct project), 144 | CSON_MODEL_INT(struct project, id), 145 | CSON_MODEL_STRING(struct project, name), 146 | }; 147 | 148 | /** 仓库结构体数据模型 */ 149 | CsonModel hubModel[] = 150 | { 151 | CSON_MODEL_OBJ(struct hub), 152 | CSON_MODEL_INT(struct hub, id), 153 | CSON_MODEL_STRING(struct hub, user), 154 | CSON_MODEL_STRUCT(struct hub, cson, projectModel, sizeof(projectModel)/sizeof(CsonModel)) 155 | }; 156 | 157 | 158 | void csonDemo(void) 159 | { 160 | char *jsonDemo = "{\"id\": 1, \"user\": \"Letter\", \"cson\": {\"id\": 2, \"name\": \"cson\"}}"; 161 | 162 | /** 解析json */ 163 | struct hub *pHub = csonDecode(jsonDemo, hubModel, sizeof(hubModel)/sizeof(CsonModel)); 164 | printf("hub: id: %d, user: %s, project id: %d, project name: %s\r\n", 165 | pHub->id, pHub->user, pHub->cson->id, pHub->cson->name); 166 | 167 | /** 序列化对象 */ 168 | char *formatJson = csonEncode(pHub, hubModel, sizeof(hubModel)/sizeof(CsonModel), 512, 1); 169 | printf("format json: %s\r\n", formatJson); 170 | 171 | /** 释放结构体对象 */ 172 | csonFree(pHub, hubModel, sizeof(hubModel)/sizeof(CsonModel)); 173 | 174 | /** 释放序列化生成的json字符串 */ 175 | csonFreeJson(formatJson); 176 | } 177 | SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC), 178 | csonDemo, csonDemo, test); 179 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # CSON 2 | 3 | ![version](https://img.shields.io/badge/version-1.0.4-brightgreen.svg) 4 | ![build](https://img.shields.io/badge/build-2020.09.13-brightgreen.svg) 5 | ![license](https://img.shields.io/badge/license-MIT-brightgreen.svg) 6 | 7 | 基于[cJSON](https://github.com/kbranigan/cJSON),运行于C语言平台的json-struct模型解析工具 8 | 9 | - [CSON](#cson) 10 | - [简介](#简介) 11 | - [使用](#使用) 12 | - [声明结构体](#声明结构体) 13 | - [定义数据模型](#定义数据模型) 14 | - [使用CSON解析](#使用cson解析) 15 | - [结构体数据类型](#结构体数据类型) 16 | - [数据模型映射](#数据模型映射) 17 | - [API](#api) 18 | - [初始化](#初始化) 19 | - [反序列化](#反序列化) 20 | - [序列化](#序列化) 21 | - [空间释放](#空间释放) 22 | - [释放结构体对象](#释放结构体对象) 23 | - [释放json字符串](#释放json字符串) 24 | - [注意](#注意) 25 | 26 | ## 简介 27 | 28 | [CSON](https://github.com/NevermindZZT/cson)是一个简单的cJSON的二次封装,相比于使用原生cJSON一层一层解析的方式,CSON采用模型映射的方式,使用模型将结构体的特征进行描述,然后根据模型,将json数据直接解析成结构体,免去使用原生cJSON需要多次调用API的复杂性,可以很大程度减少代码冗余,增加代码逻辑性。 29 | 30 | CSON的模型映射借鉴了高级语言(比如说Java)的反射机制,通过建立数据模型,记录结构体的元素,类型,偏移,然后直接在内存层面进行操作,对C语言提供类似于[gson](https://github.com/google/gson)这样的高效json解析工具 31 | 32 | ## 使用 33 | 34 | CSON通过数据模型将结构体和json建立映射关系,因此,你需要做的就是在声明结构体的时候同时,使用数据模型对结构体进行描述,之后,只需要直接调用CSON的api即可 35 | 36 | ### 声明结构体 37 | 38 | ```C 39 | /** 项目结构体 */ 40 | struct project 41 | { 42 | int id; 43 | char *name; 44 | }; 45 | 46 | /** 仓库结构体 */ 47 | struct hub 48 | { 49 | int id; 50 | char *user; 51 | struct project *cson; 52 | }; 53 | ``` 54 | 55 | ### 定义数据模型 56 | 57 | 对每一个需要使用cson的结构体,都需要定义相对应的数据模型 58 | 59 | ```C 60 | /** 项目结构体数据模型 */ 61 | CsonModel projectModel[] = 62 | { 63 | CSON_MODEL_OBJ(struct project), 64 | CSON_MODEL_INT(struct project, id), 65 | CSON_MODEL_STRING(struct project, name), 66 | }; 67 | 68 | /** 仓库结构体数据模型 */ 69 | CsonModel hubModel[] = 70 | { 71 | CSON_MODEL_OBJ(struct hub), 72 | CSON_MODEL_INT(struct hub, id), 73 | CSON_MODEL_STRING(struct hub, user), 74 | CSON_MODEL_STRUCT(struct hub, cson, projectModel, sizeof(projectModel)/sizeof(CsonModel)) 75 | }; 76 | ``` 77 | 78 | ### 使用CSON解析 79 | 80 | 只需要定义好数据模型,就可以使用CSON读json进行序列化和反序列化 81 | 82 | ```C 83 | void csonDemo(void) 84 | { 85 | char *jsonDemo = "{\"id\": 1, \"user\": \"Letter\", \"cson\": {\"id\": 2, \"name\": \"cson\"}}"; 86 | 87 | /** 解析json */ 88 | struct hub *pHub = csonDecode(jsonDemo, hubModel, sizeof(hubModel)/sizeof(CsonModel)); 89 | printf("hub: id: %d, user: %s, project id: %d, project name: %s\r\n", 90 | pHub->id, pHub->user, pHub->cson->id, pHub->cson->name); 91 | 92 | /** 序列化对象 */ 93 | char *formatJson = csonEncodeFormatted(pHub, hubModel, sizeof(hubModel)/sizeof(CsonModel)); 94 | printf("format json: %s\r\n", formatJson); 95 | 96 | /** 释放结构体对象 */ 97 | csonFree(pHub, hubModel, sizeof(hubModel)/sizeof(CsonModel)); 98 | 99 | /** 释放序列化生成的json字符串 */ 100 | csonFreeJson(formatJson); 101 | } 102 | ``` 103 | 104 | 运行结果: 105 | 106 | ```plain 107 | hub: id: 1, user: Letter, project id: 2, project name: cson 108 | format json: { 109 | "id": 1, 110 | "user": "Letter", 111 | "cson": { 112 | "id": 2, 113 | "name": "cson" 114 | } 115 | } 116 | ``` 117 | 118 | 可以看到,无论是解析json,还是序列化结构体到json,在使用CSON的情况下,都只需要一行代码就可以解决,同样的操作,在使用原生cJSON的情况下,你可能需要多次判断,解析元素 119 | 120 | ## 结构体数据类型 121 | 122 | CSON采用数据模型对结构体进行解析,在方便json操作的同时,也给结构体的定义带来了一些限制,目前,CSON所支持在结构体中定义的数据类型包括: 123 | 124 | 1. 整数(char, short, int, long) 125 | 2. 浮点数(float, double) 126 | 3. 字符串(char *) 127 | 4. 基本类型数组(char[], short[], int[], long[], float[], double[], *char[]) 128 | 5. 子结构体(指针形式) 129 | 6. 链表(CsonList) 130 | 7. 子json(char *) 131 | 132 | 其中,为了方便解析,CSON定义了一个专用的链表(CsonList),用于对json中复杂结构的数组映射 133 | 134 | CSON支持的数据类型基本包括绝大多数使用场景,对于一些之前就定义好的结构体,可能需要稍微做一点修改 135 | 136 | ## 数据模型映射 137 | 138 | CSON采用数据模型建立结构体同json之间的映射,数据模型通过结构体数组进行定义,数据模型定义如下: 139 | 140 | ```C 141 | /** 142 | * @brief CSON数据模型定义 143 | * 144 | */ 145 | typedef struct cson_model 146 | { 147 | CsonType type; /**< 数据类型 */ 148 | char *key; /**< 元素键值 */ 149 | short offset; /**< 元素偏移 */ 150 | union 151 | { 152 | struct 153 | { 154 | struct cson_model *model; /**< 子结构体模型 */ 155 | short size; /**< 子结构体模型大小 */ 156 | } sub; /**< 子结构体 */ 157 | struct 158 | { 159 | CsonType eleType; /**< 数组元素类型 */ 160 | short size; /**< 数组大小 */ 161 | } array; /**< 数组 */ 162 | int objSize; /**< 对象大小 */ 163 | CsonType basicListType; /**< 基础数据链表类型 */ 164 | } param; 165 | } CsonModel; 166 | ``` 167 | 168 | 对于每一个需要使用CSON的结构体,都需要定义一个数据模型,每一个数据模型都需要包含一条结构体描述`CSON_MODEL_OBJ(type)`以及若干个数据描述,取决于结构体的成员数量 169 | 170 | 一般情况下,你只需要使用CSON提供的宏进行数据模型条目的定义,数据模型宏与对应的数据类型对应如下: 171 | 172 | | 数据模型宏 | 数据类型 | 备注 | 173 | | --------------------------------------------------- | -------- | ------------------------------------------------------ | 174 | | CSON_MODEL_OBJ(type) | 结构体 | 用于描述整个结构体,每一个数据模型都需要包含此条目 | 175 | | CSON_MODEL_CHAR(type, key) | char | | 176 | | CSON_MODEL_SHORT(type, key) | short | | 177 | | CSON_MODEL_INT(type, key) | int | | 178 | | CSON_MODEL_LONG(type, key) | long | | 179 | | CSON_MODEL_FLOAT(type, key) | float | | 180 | | CSON_MODEL_DOUBLE(type, key) | double | | 181 | | CSON_MODEL_BOOL(type, key) | bool | C没有bool,对应为char | 182 | | CSON_MODEL_STRING(type, key) | char * | | 183 | | CSON_MODEL_STRUCT(type, key, submodel, subsize) | 子结构体 | 子结构体必须是结构体指针的形式 | 184 | | CSON_MODEL_LIST(type, key, submodel, subsize) | CsonList | CSON定义的链表 | 185 | | CSON_MODEL_ARRAY(type, key, elementType, arraySize) | 数组 | 支持基本数据类型, 数组的每一个元素必须合法 | 186 | | CSON_MODEL_JSON(type, key) | 子json | 将子json直接以字符串解析,或者将json字符串转化为子json | 187 | 188 | ## API 189 | 190 | CSON源文件有完整的注释,可以通过Doxygen等工具导出完整的API文档,以下是几个关键API的说明 191 | 192 | ### 初始化 193 | 194 | 初始化CSON,提供内存分配和内存释放函数,对于标准C库可以使用`malloc`和`free` 195 | 196 | ```C 197 | void csonInit(void *malloc, void *free) 198 | ``` 199 | 200 | - 参数 201 | - `malloc` 内存分配函数 202 | - `free` 内存释放函数 203 | 204 | ### 反序列化 205 | 206 | 解析json,将json字符串反序列化成结构体对象 207 | 208 | ```C 209 | void *csonDecode(const char *jsonStr, CsonModel *model, int modelSize) 210 | ``` 211 | 212 | - 参数 213 | - `jsonStr` json字符串 214 | - `model` 描述目标结构体的数据模型 215 | - `modelSize` 数据模型大小 216 | - 返回 217 | - `void *` 反序列化得到的结构体对象 218 | 219 | ### 序列化 220 | 221 | 编码结构体,将结构体对象序列化成json字符串 222 | 223 | ```C 224 | char* csonEncode(void *obj, CsonModel *model, int modelSize, int bufferSize, int fmt) 225 | ``` 226 | 227 | - 参数 228 | - `obj` 源结构体对象 229 | - `model` 描述源结构体的数据模型 230 | - `modelSize` 数据模型大小 231 | - `bufferSize` 可分配给json字符串的空间大小,需要根据内容估计大小 232 | - `fmt` 是否格式化json字符串 233 | - 返回 234 | - `char *` 序列化得到的json字符串 235 | 236 | ### 空间释放 237 | 238 | CSON提供了两个释放内存的函数,用于释放CSON生成的结构体对象和json字符串 239 | 240 | #### 释放结构体对象 241 | 242 | ```C 243 | void csonFree(void *obj, CsonModel *model, int modelSize) 244 | ``` 245 | 246 | - 参数 247 | - `obj` 待释放的结构体对象 248 | - `model` 待释放的结构体数据模型 249 | - `modelSize` 待释放的结构体数据模型大小 250 | 251 | #### 释放json字符串 252 | 253 | ```C 254 | void csonFreeJson(const char *jsonStr) 255 | ``` 256 | 257 | - 参数 258 | - `jsonStr` 待释放的json字符串 259 | 260 | ## 注意 261 | 262 | - 数据模型根据结构体不同而不同,数据模型的数量=结构体成员数量+1,多出来的一条是定义结构体`CSON_MODEL_OBJ(type)` 263 | - 数组类型映射时会处理给进去的数组大小,所以请确保每一个数组元素都是合法的 264 | - 基本数据类型链表采用类似子结构体的方式,CSON默认定义了基本数据类型链表元素的数据模型,通过类似`CSON_MODEL_LIST(struct test, strList, CSON_MODEL_STRING_LIST, CSON_BASIC_LIST_MODEL_SIZE)`进行定义即可 265 | -------------------------------------------------------------------------------- /src/cJSON.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2009 Dave Gamble 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | /* cJSON */ 24 | /* JSON parser in C. */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "cJSON.h" 34 | 35 | static const char *ep; 36 | 37 | const char *cJSON_GetErrorPtr(void) {return ep;} 38 | 39 | static int cJSON_strcasecmp(const char *s1,const char *s2) 40 | { 41 | if (!s1) return (s1==s2)?0:1;if (!s2) return 1; 42 | for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0; 43 | return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); 44 | } 45 | 46 | static void *(*cJSON_malloc)(size_t sz) = malloc; 47 | static void (*cJSON_free)(void *ptr) = free; 48 | 49 | static char* cJSON_strdup(const char* str) 50 | { 51 | size_t len; 52 | char* copy; 53 | 54 | len = strlen(str) + 1; 55 | if (!(copy = (char*)cJSON_malloc(len))) return 0; 56 | memcpy(copy,str,len); 57 | return copy; 58 | } 59 | 60 | void cJSON_InitHooks(cJSON_Hooks* hooks) 61 | { 62 | if (!hooks) { /* Reset hooks */ 63 | cJSON_malloc = malloc; 64 | cJSON_free = free; 65 | return; 66 | } 67 | 68 | cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc; 69 | cJSON_free = (hooks->free_fn)?hooks->free_fn:free; 70 | } 71 | 72 | /* Internal constructor. */ 73 | static cJSON *cJSON_New_Item(void) 74 | { 75 | cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); 76 | if (node) memset(node,0,sizeof(cJSON)); 77 | return node; 78 | } 79 | 80 | /* Delete a cJSON structure. */ 81 | void cJSON_Delete(cJSON *c) 82 | { 83 | cJSON *next; 84 | while (c) 85 | { 86 | next=c->next; 87 | if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child); 88 | if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring); 89 | if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string); 90 | cJSON_free(c); 91 | c=next; 92 | } 93 | } 94 | 95 | /* Parse the input text to generate a number, and populate the result into item. */ 96 | static const char *parse_number(cJSON *item,const char *num) 97 | { 98 | double n=0,sign=1,scale=0;int subscale=0,signsubscale=1; 99 | 100 | if (*num=='-') sign=-1,num++; /* Has sign? */ 101 | if (*num=='0') num++; /* is zero */ 102 | if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */ 103 | if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */ 104 | if (*num=='e' || *num=='E') /* Exponent? */ 105 | { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */ 106 | while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */ 107 | } 108 | 109 | n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */ 110 | 111 | item->valuedouble=n; 112 | item->valueint=(int)n; 113 | item->type=cJSON_Number; 114 | return num; 115 | } 116 | 117 | static int pow2gt (int x) { --x; x|=x>>1; x|=x>>2; x|=x>>4; x|=x>>8; x|=x>>16; return x+1; } 118 | 119 | typedef struct {char *buffer; int length; int offset; } printbuffer; 120 | 121 | static char* ensure(printbuffer *p,int needed) 122 | { 123 | char *newbuffer;int newsize; 124 | if (!p || !p->buffer) return 0; 125 | needed+=p->offset; 126 | if (needed<=p->length) return p->buffer+p->offset; 127 | 128 | newsize=pow2gt(needed); 129 | newbuffer=(char*)cJSON_malloc(newsize); 130 | if (!newbuffer) {cJSON_free(p->buffer);p->length=0,p->buffer=0;return 0;} 131 | if (newbuffer) memcpy(newbuffer,p->buffer,p->length); 132 | cJSON_free(p->buffer); 133 | p->length=newsize; 134 | p->buffer=newbuffer; 135 | return newbuffer+p->offset; 136 | } 137 | 138 | static int update(printbuffer *p) 139 | { 140 | char *str; 141 | if (!p || !p->buffer) return 0; 142 | str=p->buffer+p->offset; 143 | return p->offset+strlen(str); 144 | } 145 | 146 | /* Render the number nicely from the given item into a string. */ 147 | static char *print_number(cJSON *item,printbuffer *p) 148 | { 149 | char *str=0; 150 | double d=item->valuedouble; 151 | if (d==0) 152 | { 153 | if (p) str=ensure(p,2); 154 | else str=(char*)cJSON_malloc(2); /* special case for 0. */ 155 | if (str) strcpy(str,"0"); 156 | } 157 | else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN) 158 | { 159 | if (p) str=ensure(p,21); 160 | else str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */ 161 | if (str) sprintf(str,"%d",item->valueint); 162 | } 163 | else 164 | { 165 | if (p) str=ensure(p,64); 166 | else str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */ 167 | if (str) 168 | { 169 | if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d); 170 | else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); 171 | else sprintf(str,"%f",d); 172 | } 173 | } 174 | return str; 175 | } 176 | 177 | static unsigned parse_hex4(const char *str) 178 | { 179 | unsigned h=0; 180 | 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; 181 | h=h<<4;str++; 182 | 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; 183 | h=h<<4;str++; 184 | 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; 185 | h=h<<4;str++; 186 | 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; 187 | return h; 188 | } 189 | 190 | /* Parse the input text into an unescaped cstring, and populate item. */ 191 | static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; 192 | static const char *parse_string(cJSON *item,const char *str) 193 | { 194 | const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2; 195 | if (*str!='\"') {ep=str;return 0;} /* not a string! */ 196 | 197 | while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */ 198 | 199 | out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */ 200 | if (!out) return 0; 201 | 202 | ptr=str+1;ptr2=out; 203 | while (*ptr!='\"' && *ptr) 204 | { 205 | if (*ptr!='\\') *ptr2++=*ptr++; 206 | else 207 | { 208 | ptr++; 209 | switch (*ptr) 210 | { 211 | case 'b': *ptr2++='\b'; break; 212 | case 'f': *ptr2++='\f'; break; 213 | case 'n': *ptr2++='\n'; break; 214 | case 'r': *ptr2++='\r'; break; 215 | case 't': *ptr2++='\t'; break; 216 | case 'u': /* transcode utf16 to utf8. */ 217 | uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */ 218 | 219 | if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */ 220 | 221 | if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */ 222 | { 223 | if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */ 224 | uc2=parse_hex4(ptr+3);ptr+=6; 225 | if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */ 226 | uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF)); 227 | } 228 | 229 | len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; 230 | 231 | switch (len) { 232 | case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; 233 | case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; 234 | case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; 235 | case 1: *--ptr2 =(uc | firstByteMark[len]); 236 | } 237 | ptr2+=len; 238 | break; 239 | default: *ptr2++=*ptr; break; 240 | } 241 | ptr++; 242 | } 243 | } 244 | *ptr2=0; 245 | if (*ptr=='\"') ptr++; 246 | item->valuestring=out; 247 | item->type=cJSON_String; 248 | return ptr; 249 | } 250 | 251 | /* Render the cstring provided to an escaped version that can be printed. */ 252 | static char *print_string_ptr(const char *str,printbuffer *p) 253 | { 254 | const char *ptr;char *ptr2,*out;int len=0,flag=0;unsigned char token; 255 | 256 | for (ptr=str;*ptr;ptr++) flag|=((*ptr>0 && *ptr<32)||(*ptr=='\"')||(*ptr=='\\'))?1:0; 257 | if (!flag) 258 | { 259 | len=ptr-str; 260 | if (p) out=ensure(p,len+3); 261 | else out=(char*)cJSON_malloc(len+3); 262 | if (!out) return 0; 263 | ptr2=out;*ptr2++='\"'; 264 | strcpy(ptr2,str); 265 | ptr2[len]='\"'; 266 | ptr2[len+1]=0; 267 | return out; 268 | } 269 | 270 | if (!str) 271 | { 272 | if (p) out=ensure(p,3); 273 | else out=(char*)cJSON_malloc(3); 274 | if (!out) return 0; 275 | strcpy(out,"\"\""); 276 | return out; 277 | } 278 | ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;} 279 | 280 | if (p) out=ensure(p,len+3); 281 | else out=(char*)cJSON_malloc(len+3); 282 | if (!out) return 0; 283 | 284 | ptr2=out;ptr=str; 285 | *ptr2++='\"'; 286 | while (*ptr) 287 | { 288 | if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; 289 | else 290 | { 291 | *ptr2++='\\'; 292 | switch (token=*ptr++) 293 | { 294 | case '\\': *ptr2++='\\'; break; 295 | case '\"': *ptr2++='\"'; break; 296 | case '\b': *ptr2++='b'; break; 297 | case '\f': *ptr2++='f'; break; 298 | case '\n': *ptr2++='n'; break; 299 | case '\r': *ptr2++='r'; break; 300 | case '\t': *ptr2++='t'; break; 301 | default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */ 302 | } 303 | } 304 | } 305 | *ptr2++='\"';*ptr2++=0; 306 | return out; 307 | } 308 | /* Invote print_string_ptr (which is useful) on an item. */ 309 | static char *print_string(cJSON *item,printbuffer *p) {return print_string_ptr(item->valuestring,p);} 310 | 311 | /* Predeclare these prototypes. */ 312 | static const char *parse_value(cJSON *item,const char *value); 313 | static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p); 314 | static const char *parse_array(cJSON *item,const char *value); 315 | static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p); 316 | static const char *parse_object(cJSON *item,const char *value); 317 | static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p); 318 | 319 | /* Utility to jump whitespace and cr/lf */ 320 | static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;} 321 | 322 | /* Parse an object - create a new root, and populate. */ 323 | cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated) 324 | { 325 | const char *end=0; 326 | cJSON *c=cJSON_New_Item(); 327 | ep=0; 328 | if (!c) return 0; /* memory fail */ 329 | 330 | end=parse_value(c,skip(value)); 331 | if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */ 332 | 333 | /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ 334 | if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}} 335 | if (return_parse_end) *return_parse_end=end; 336 | return c; 337 | } 338 | /* Default options for cJSON_Parse */ 339 | cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);} 340 | 341 | /* Render a cJSON item/entity/structure to text. */ 342 | char *cJSON_Print(cJSON *item) {return print_value(item,0,1,0);} 343 | char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0,0);} 344 | 345 | char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt) 346 | { 347 | printbuffer p; 348 | p.buffer=(char*)cJSON_malloc(prebuffer); 349 | p.length=prebuffer; 350 | p.offset=0; 351 | return print_value(item,0,fmt,&p); 352 | return p.buffer; 353 | } 354 | 355 | 356 | /* Parser core - when encountering text, process appropriately. */ 357 | static const char *parse_value(cJSON *item,const char *value) 358 | { 359 | if (!value) return 0; /* Fail on null. */ 360 | if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; } 361 | if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; } 362 | if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; } 363 | if (*value=='\"') { return parse_string(item,value); } 364 | if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); } 365 | if (*value=='[') { return parse_array(item,value); } 366 | if (*value=='{') { return parse_object(item,value); } 367 | 368 | ep=value;return 0; /* failure. */ 369 | } 370 | 371 | /* Render a value to text. */ 372 | static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p) 373 | { 374 | char *out=0; 375 | if (!item) return 0; 376 | if (p) 377 | { 378 | switch ((item->type)&255) 379 | { 380 | case cJSON_NULL: {out=ensure(p,5); if (out) strcpy(out,"null"); break;} 381 | case cJSON_False: {out=ensure(p,6); if (out) strcpy(out,"false"); break;} 382 | case cJSON_True: {out=ensure(p,5); if (out) strcpy(out,"true"); break;} 383 | case cJSON_Number: out=print_number(item,p);break; 384 | case cJSON_String: out=print_string(item,p);break; 385 | case cJSON_Array: out=print_array(item,depth,fmt,p);break; 386 | case cJSON_Object: out=print_object(item,depth,fmt,p);break; 387 | } 388 | } 389 | else 390 | { 391 | switch ((item->type)&255) 392 | { 393 | case cJSON_NULL: out=cJSON_strdup("null"); break; 394 | case cJSON_False: out=cJSON_strdup("false");break; 395 | case cJSON_True: out=cJSON_strdup("true"); break; 396 | case cJSON_Number: out=print_number(item,0);break; 397 | case cJSON_String: out=print_string(item,0);break; 398 | case cJSON_Array: out=print_array(item,depth,fmt,0);break; 399 | case cJSON_Object: out=print_object(item,depth,fmt,0);break; 400 | } 401 | } 402 | return out; 403 | } 404 | 405 | /* Build an array from input text. */ 406 | static const char *parse_array(cJSON *item,const char *value) 407 | { 408 | cJSON *child; 409 | if (*value!='[') {ep=value;return 0;} /* not an array! */ 410 | 411 | item->type=cJSON_Array; 412 | value=skip(value+1); 413 | if (*value==']') return value+1; /* empty array. */ 414 | 415 | item->child=child=cJSON_New_Item(); 416 | if (!item->child) return 0; /* memory fail */ 417 | value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */ 418 | if (!value) return 0; 419 | 420 | while (*value==',') 421 | { 422 | cJSON *new_item; 423 | if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ 424 | child->next=new_item;new_item->prev=child;child=new_item; 425 | value=skip(parse_value(child,skip(value+1))); 426 | if (!value) return 0; /* memory fail */ 427 | } 428 | 429 | if (*value==']') return value+1; /* end of array */ 430 | ep=value;return 0; /* malformed. */ 431 | } 432 | 433 | /* Render an array to text */ 434 | static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p) 435 | { 436 | char **entries; 437 | char *out=0,*ptr,*ret;int len=5; 438 | cJSON *child=item->child; 439 | int numentries=0,i=0,fail=0; 440 | size_t tmplen=0; 441 | 442 | /* How many entries in the array? */ 443 | while (child) numentries++,child=child->next; 444 | /* Explicitly handle numentries==0 */ 445 | if (!numentries) 446 | { 447 | if (p) out=ensure(p,3); 448 | else out=(char*)cJSON_malloc(3); 449 | if (out) strcpy(out,"[]"); 450 | return out; 451 | } 452 | 453 | if (p) 454 | { 455 | /* Compose the output array. */ 456 | i=p->offset; 457 | ptr=ensure(p,1);if (!ptr) return 0; *ptr='['; p->offset++; 458 | child=item->child; 459 | while (child && !fail) 460 | { 461 | print_value(child,depth+1,fmt,p); 462 | p->offset=update(p); 463 | 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;} 464 | child=child->next; 465 | } 466 | ptr=ensure(p,2);if (!ptr) return 0; *ptr++=']';*ptr=0; 467 | out=(p->buffer)+i; 468 | } 469 | else 470 | { 471 | /* Allocate an array to hold the values for each */ 472 | entries=(char**)cJSON_malloc(numentries*sizeof(char*)); 473 | if (!entries) return 0; 474 | memset(entries,0,numentries*sizeof(char*)); 475 | /* Retrieve all the results: */ 476 | child=item->child; 477 | while (child && !fail) 478 | { 479 | ret=print_value(child,depth+1,fmt,0); 480 | entries[i++]=ret; 481 | if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; 482 | child=child->next; 483 | } 484 | 485 | /* If we didn't fail, try to malloc the output string */ 486 | if (!fail) out=(char*)cJSON_malloc(len); 487 | /* If that fails, we fail. */ 488 | if (!out) fail=1; 489 | 490 | /* Handle failure. */ 491 | if (fail) 492 | { 493 | for (i=0;itype=cJSON_Object; 520 | value=skip(value+1); 521 | if (*value=='}') return value+1; /* empty array. */ 522 | 523 | item->child=child=cJSON_New_Item(); 524 | if (!item->child) return 0; 525 | value=skip(parse_string(child,skip(value))); 526 | if (!value) return 0; 527 | child->string=child->valuestring;child->valuestring=0; 528 | if (*value!=':') {ep=value;return 0;} /* fail! */ 529 | value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ 530 | if (!value) return 0; 531 | 532 | while (*value==',') 533 | { 534 | cJSON *new_item; 535 | if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ 536 | child->next=new_item;new_item->prev=child;child=new_item; 537 | value=skip(parse_string(child,skip(value+1))); 538 | if (!value) return 0; 539 | child->string=child->valuestring;child->valuestring=0; 540 | if (*value!=':') {ep=value;return 0;} /* fail! */ 541 | value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ 542 | if (!value) return 0; 543 | } 544 | 545 | if (*value=='}') return value+1; /* end of array */ 546 | ep=value;return 0; /* malformed. */ 547 | } 548 | 549 | /* Render an object to text. */ 550 | static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p) 551 | { 552 | char **entries=0,**names=0; 553 | char *out=0,*ptr,*ret,*str;int len=7,i=0,j; 554 | cJSON *child=item->child; 555 | int numentries=0,fail=0; 556 | size_t tmplen=0; 557 | /* Count the number of entries. */ 558 | while (child) numentries++,child=child->next; 559 | /* Explicitly handle empty object case */ 560 | if (!numentries) 561 | { 562 | if (p) out=ensure(p,fmt?depth+4:3); 563 | else out=(char*)cJSON_malloc(fmt?depth+4:3); 564 | if (!out) return 0; 565 | ptr=out;*ptr++='{'; 566 | if (fmt) {*ptr++='\n';for (i=0;ioffset; 574 | len=fmt?2:1; ptr=ensure(p,len+1); if (!ptr) return 0; 575 | *ptr++='{'; if (fmt) *ptr++='\n'; *ptr=0; p->offset+=len; 576 | child=item->child;depth++; 577 | while (child) 578 | { 579 | if (fmt) 580 | { 581 | ptr=ensure(p,depth); if (!ptr) return 0; 582 | for (j=0;joffset+=depth; 584 | } 585 | print_string_ptr(child->string,p); 586 | p->offset=update(p); 587 | 588 | len=fmt?2:1; 589 | ptr=ensure(p,len); if (!ptr) return 0; 590 | *ptr++=':';if (fmt) *ptr++='\t'; 591 | p->offset+=len; 592 | 593 | print_value(child,depth,fmt,p); 594 | p->offset=update(p); 595 | 596 | len=(fmt?1:0)+(child->next?1:0); 597 | ptr=ensure(p,len+1); if (!ptr) return 0; 598 | if (child->next) *ptr++=','; 599 | if (fmt) *ptr++='\n';*ptr=0; 600 | p->offset+=len; 601 | child=child->next; 602 | } 603 | ptr=ensure(p,fmt?(depth+1):2); if (!ptr) return 0; 604 | if (fmt) for (i=0;ibuffer)+i; 607 | } 608 | else 609 | { 610 | /* Allocate space for the names and the objects */ 611 | entries=(char**)cJSON_malloc(numentries*sizeof(char*)); 612 | if (!entries) return 0; 613 | names=(char**)cJSON_malloc(numentries*sizeof(char*)); 614 | if (!names) {cJSON_free(entries);return 0;} 615 | memset(entries,0,sizeof(char*)*numentries); 616 | memset(names,0,sizeof(char*)*numentries); 617 | 618 | /* Collect all the results into our arrays: */ 619 | child=item->child;depth++;if (fmt) len+=depth; 620 | while (child) 621 | { 622 | names[i]=str=print_string_ptr(child->string,0); 623 | entries[i++]=ret=print_value(child,depth,fmt,0); 624 | if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1; 625 | child=child->next; 626 | } 627 | 628 | /* Try to allocate the output string */ 629 | if (!fail) out=(char*)cJSON_malloc(len); 630 | if (!out) fail=1; 631 | 632 | /* Handle failure */ 633 | if (fail) 634 | { 635 | for (i=0;ichild;int i=0;while(c)i++,c=c->next;return i;} 662 | cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;} 663 | cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} 664 | 665 | /* Utility for array list handling. */ 666 | static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} 667 | /* Utility for handling references. */ 668 | static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;} 669 | 670 | /* Add item to array/object. */ 671 | void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} 672 | void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} 673 | void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (!(item->type&cJSON_StringIsConst) && item->string) cJSON_free(item->string);item->string=(char*)string;item->type|=cJSON_StringIsConst;cJSON_AddItemToArray(object,item);} 674 | void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} 675 | void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} 676 | 677 | cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; 678 | if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;} 679 | void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} 680 | cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;} 681 | void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} 682 | 683 | /* Replace array/object items with new ones. */ 684 | void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) {cJSON_AddItemToArray(array,newitem);return;} 685 | newitem->next=c;newitem->prev=c->prev;c->prev=newitem;if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;} 686 | void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; 687 | newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; 688 | if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} 689 | void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}} 690 | 691 | /* Create basic types: */ 692 | cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} 693 | cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} 694 | cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} 695 | cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} 696 | 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;} 697 | cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} 698 | cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} 699 | cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} 700 | 701 | /* Create Arrays: */ 702 | cJSON *cJSON_CreateIntArray(const int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} 703 | cJSON *cJSON_CreateFloatArray(const float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} 704 | cJSON *cJSON_CreateDoubleArray(const double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} 705 | cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} 706 | 707 | /* Duplication */ 708 | cJSON *cJSON_Duplicate(cJSON *item,int recurse) 709 | { 710 | cJSON *newitem,*cptr,*nptr=0,*newchild; 711 | /* Bail on bad ptr */ 712 | if (!item) return 0; 713 | /* Create new item */ 714 | newitem=cJSON_New_Item(); 715 | if (!newitem) return 0; 716 | /* Copy over all vars */ 717 | newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble; 718 | if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}} 719 | if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}} 720 | /* If non-recursive, then we're done! */ 721 | if (!recurse) return newitem; 722 | /* Walk the ->next chain for the child. */ 723 | cptr=item->child; 724 | while (cptr) 725 | { 726 | newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */ 727 | if (!newchild) {cJSON_Delete(newitem);return 0;} 728 | if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */ 729 | else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */ 730 | cptr=cptr->next; 731 | } 732 | return newitem; 733 | } 734 | 735 | void cJSON_Minify(char *json) 736 | { 737 | char *into=json; 738 | while (*json) 739 | { 740 | if (*json==' ') json++; 741 | else if (*json=='\t') json++; /* Whitespace characters. */ 742 | else if (*json=='\r') json++; 743 | else if (*json=='\n') json++; 744 | else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; /* double-slash comments, to end of line. */ 745 | else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} /* multiline comments. */ 746 | else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} /* string literals, which are \" sensitive. */ 747 | else *into++=*json++; /* All other characters. */ 748 | } 749 | *into=0; /* and null-terminate. */ 750 | } 751 | -------------------------------------------------------------------------------- /src/cJSON.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2009 Dave Gamble 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #ifndef cJSON__h 24 | #define cJSON__h 25 | 26 | #ifdef __cplusplus 27 | extern "C" 28 | { 29 | #endif 30 | 31 | /* cJSON Types: */ 32 | #define cJSON_False 0 33 | #define cJSON_True 1 34 | #define cJSON_NULL 2 35 | #define cJSON_Number 3 36 | #define cJSON_String 4 37 | #define cJSON_Array 5 38 | #define cJSON_Object 6 39 | 40 | #define cJSON_IsReference 256 41 | #define cJSON_StringIsConst 512 42 | 43 | /* The cJSON structure: */ 44 | typedef struct cJSON { 45 | struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ 46 | struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ 47 | 48 | int type; /* The type of the item, as above. */ 49 | 50 | char *valuestring; /* The item's string, if type==cJSON_String */ 51 | int valueint; /* The item's number, if type==cJSON_Number */ 52 | double valuedouble; /* The item's number, if type==cJSON_Number */ 53 | 54 | char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ 55 | } cJSON; 56 | 57 | typedef struct cJSON_Hooks { 58 | void *(*malloc_fn)(size_t sz); 59 | void (*free_fn)(void *ptr); 60 | } cJSON_Hooks; 61 | 62 | /* Supply malloc, realloc and free functions to cJSON */ 63 | extern void cJSON_InitHooks(cJSON_Hooks* hooks); 64 | 65 | 66 | /* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */ 67 | extern cJSON *cJSON_Parse(const char *value); 68 | /* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ 69 | extern char *cJSON_Print(cJSON *item); 70 | /* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ 71 | extern char *cJSON_PrintUnformatted(cJSON *item); 72 | /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ 73 | extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt); 74 | /* Delete a cJSON entity and all subentities. */ 75 | extern void cJSON_Delete(cJSON *c); 76 | 77 | /* Returns the number of items in an array (or object). */ 78 | extern int cJSON_GetArraySize(cJSON *array); 79 | /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ 80 | extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); 81 | /* Get item "string" from object. Case insensitive. */ 82 | extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); 83 | 84 | /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ 85 | extern const char *cJSON_GetErrorPtr(void); 86 | 87 | /* These calls create a cJSON item of the appropriate type. */ 88 | extern cJSON *cJSON_CreateNull(void); 89 | extern cJSON *cJSON_CreateTrue(void); 90 | extern cJSON *cJSON_CreateFalse(void); 91 | extern cJSON *cJSON_CreateBool(int b); 92 | extern cJSON *cJSON_CreateNumber(double num); 93 | extern cJSON *cJSON_CreateString(const char *string); 94 | extern cJSON *cJSON_CreateArray(void); 95 | extern cJSON *cJSON_CreateObject(void); 96 | 97 | /* These utilities create an Array of count items. */ 98 | extern cJSON *cJSON_CreateIntArray(const int *numbers,int count); 99 | extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count); 100 | extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count); 101 | extern cJSON *cJSON_CreateStringArray(const char **strings,int count); 102 | 103 | /* Append item to the specified array/object. */ 104 | extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); 105 | extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); 106 | extern void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item); /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */ 107 | /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ 108 | extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); 109 | extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); 110 | 111 | /* Remove/Detatch items from Arrays/Objects. */ 112 | extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which); 113 | extern void cJSON_DeleteItemFromArray(cJSON *array,int which); 114 | extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string); 115 | extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string); 116 | 117 | /* Update array items. */ 118 | extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem); /* Shifts pre-existing items to the right. */ 119 | extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); 120 | extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); 121 | 122 | /* Duplicate a cJSON item */ 123 | extern cJSON *cJSON_Duplicate(cJSON *item,int recurse); 124 | /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will 125 | need to be released. With recurse!=0, it will duplicate any children connected to the item. 126 | The item->next and ->prev pointers are always zero on return from Duplicate. */ 127 | 128 | /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ 129 | extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated); 130 | 131 | extern void cJSON_Minify(char *json); 132 | 133 | /* Macros for creating things quickly. */ 134 | #define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) 135 | #define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) 136 | #define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) 137 | #define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) 138 | #define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) 139 | #define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) 140 | 141 | /* When assigning an integer value, it needs to be propagated to valuedouble too. */ 142 | #define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val)) 143 | #define cJSON_SetNumberValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val)) 144 | 145 | #ifdef __cplusplus 146 | } 147 | #endif 148 | 149 | #endif 150 | -------------------------------------------------------------------------------- /src/cson.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cson.c 3 | * @author Letter (NevermindZZT@gmail.com) 4 | * @brief cson 5 | * @version 0.1 6 | * @date 2019-08-26 7 | * 8 | * @copyright (c) 2019 Letter 9 | * 10 | */ 11 | 12 | #include "cson.h" 13 | #include "cJSON.h" 14 | #include "stddef.h" 15 | #include "string.h" 16 | #include "stdio.h" 17 | 18 | 19 | /** 20 | * @brief 基本类型链表数据模型 21 | * 22 | */ 23 | CsonModel csonBasicListModel[] = 24 | { 25 | [0] = {CSON_TYPE_OBJ, NULL, 0, .param.objSize=sizeof(char)}, 26 | [1] = {CSON_TYPE_CHAR, NULL, 0}, 27 | [2] = {CSON_TYPE_OBJ, NULL, 0, .param.objSize=sizeof(short)}, 28 | [3] = {CSON_TYPE_SHORT, NULL, 0}, 29 | [4] = {CSON_TYPE_OBJ, NULL, 0, .param.objSize=sizeof(int)}, 30 | [5] = {CSON_TYPE_INT, NULL, 0}, 31 | [6] = {CSON_TYPE_OBJ, NULL, 0, .param.objSize=sizeof(long)}, 32 | [7] = {CSON_TYPE_LONG, NULL, 0}, 33 | [8] = {CSON_TYPE_OBJ, NULL, 0, .param.objSize=sizeof(float)}, 34 | [9] = {CSON_TYPE_FLOAT, NULL, 0}, 35 | [10] = {CSON_TYPE_OBJ, NULL, 0, .param.objSize=sizeof(double)}, 36 | [11] = {CSON_TYPE_DOUBLE, NULL, 0}, 37 | [12] = {CSON_TYPE_OBJ, NULL, 0, .param.objSize=sizeof(char *)}, 38 | [13] = {CSON_TYPE_STRING, NULL, 0}, 39 | }; 40 | 41 | 42 | /** 43 | * @brief cson 44 | * 45 | */ 46 | struct { 47 | void *(*malloc)(int); 48 | void (*free)(void *); 49 | } cson; 50 | 51 | 52 | /** 53 | * @brief CSON初始化 54 | * 55 | * @param malloc 内存分配函数 56 | * @param free 内存释放函数 57 | */ 58 | void csonInit(void *malloc, void *free) 59 | { 60 | cson.malloc = (void *(*)(int))malloc; 61 | cson.free = (void (*)(void *))free; 62 | cJSON_InitHooks(&(cJSON_Hooks){(void *(*)(size_t))cson.malloc, cson.free}); 63 | } 64 | 65 | 66 | signed char csonIsBasicListModel(CsonModel *model) 67 | { 68 | return (model >= &csonBasicListModel[0] && model <= &csonBasicListModel[13]) ? 1 : 0; 69 | } 70 | 71 | 72 | /** 73 | * @brief 解析JSON整型 74 | * 75 | * @param json JSON对象 76 | * @param key key 77 | * @return int 解析出的整型数 78 | */ 79 | int csonDecodeNumber(cJSON *json, char *key) 80 | { 81 | cJSON *item = key ? cJSON_GetObjectItem(json, key) : json; 82 | if (item && item->type == cJSON_Number) 83 | { 84 | return item->valueint; 85 | } 86 | return 0; 87 | } 88 | 89 | 90 | /** 91 | * @brief 解析JSON浮点型 92 | * 93 | * @param json JSON对象 94 | * @param key key 95 | * @return double 解析出的浮点型数 96 | */ 97 | double csonDecodeDouble(cJSON *json, char *key) 98 | { 99 | cJSON *item = key ? cJSON_GetObjectItem(json, key) : json; 100 | if (item && item->type == cJSON_Number) 101 | { 102 | return item->valuedouble; 103 | } 104 | return 0.0; 105 | } 106 | 107 | 108 | /** 109 | * @brief 解析JSON字符串数据 110 | * 111 | * @param json JSON对象 112 | * @param key key 113 | * @return char* 解析出的字符串 114 | */ 115 | char* csonDecodeString(cJSON *json, char *key) 116 | { 117 | char *p = NULL; 118 | char *str = NULL; 119 | short strLen = 0; 120 | cJSON *item = key ? cJSON_GetObjectItem(json, key) : json; 121 | if (item && item->type == cJSON_String) 122 | { 123 | str = item->valuestring; 124 | if (item->valuestring) 125 | { 126 | strLen = strlen(str); 127 | p = cson.malloc(strLen + 1); 128 | if (p) 129 | { 130 | memcpy((void *)p, (void *)str, strLen); 131 | *(p + strLen) = 0; 132 | return p; 133 | } 134 | } 135 | } 136 | return NULL; 137 | } 138 | 139 | 140 | /** 141 | * @brief 解析JOSN布尔型数据 142 | * 143 | * @param json JSON对象 144 | * @param key key 145 | * @return char 解析出的bool 146 | */ 147 | char csonDecodeBool(cJSON *json, char *key) 148 | { 149 | cJSON *item = cJSON_GetObjectItem(json, key); 150 | if (item && item->type == cJSON_True) 151 | { 152 | return 1; 153 | } 154 | return 0; 155 | } 156 | 157 | 158 | /** 159 | * @brief 解析CsonList数据 160 | * 161 | * @param json JSON对象 162 | * @param key key 163 | * @param model CsonList成员数据模型 164 | * @param modelSize SconList成员模型数量 165 | * @return void* CsonList对象 166 | */ 167 | void *csonDecodeList(cJSON *json, char *key, CsonModel *model, int modelSize) 168 | { 169 | CsonList *list = NULL; 170 | cJSON *array = cJSON_GetObjectItem(json, key); 171 | 172 | if (array && array->type == cJSON_Array) 173 | { 174 | for (short i = 0; i < cJSON_GetArraySize(array); i++) 175 | { 176 | void *obj = csonDecodeObject(cJSON_GetArrayItem(array, i), model, modelSize); 177 | if (csonIsBasicListModel(model)) 178 | { 179 | list = csonListAdd(list, (void *)(*((int *)obj))); 180 | cson.free(obj); 181 | } 182 | else 183 | { 184 | list = csonListAdd(list, obj); 185 | } 186 | } 187 | } 188 | return list; 189 | } 190 | 191 | 192 | /** 193 | * @brief 解析数组 194 | * 195 | * @param json json对象 196 | * @param key key 197 | * @param base 数组基址 198 | * @param elementType 数组元素类型 199 | * @param arraySize 数组大小 200 | */ 201 | void csonDecodeArray(cJSON *json, char *key, void * base, CsonType elementType, short arraySize) 202 | { 203 | cJSON *array = cJSON_GetObjectItem(json, key); 204 | cJSON *item; 205 | char *str; 206 | short strLen; 207 | 208 | if (array && array->type == cJSON_Array) 209 | { 210 | for (short i = 0; i < cJSON_GetArraySize(array); i++) 211 | { 212 | item = cJSON_GetArrayItem(array, i); 213 | switch (elementType) 214 | { 215 | case CSON_TYPE_CHAR: 216 | *(char *)((int)base + (i * sizeof(char))) = (char)item->valueint; 217 | break; 218 | case CSON_TYPE_SHORT: 219 | *(short *)((int)base + (i * sizeof(short))) = (short)item->valueint; 220 | break; 221 | case CSON_TYPE_INT: 222 | *(int *)((int)base + (i * sizeof(int))) = (int)item->valueint; 223 | break; 224 | case CSON_TYPE_LONG: 225 | *(long *)((int)base + (i * sizeof(long))) = (long)item->valueint; 226 | break; 227 | case CSON_TYPE_FLOAT: 228 | *(float *)((int)base + (i * sizeof(float))) = (float)item->valuedouble; 229 | break; 230 | case CSON_TYPE_DOUBLE: 231 | *(double *)((int)base + (i * sizeof(double))) = (double)item->valuedouble; 232 | break; 233 | case CSON_TYPE_STRING: 234 | strLen = strlen(item->valuestring); 235 | str = cson.malloc(strLen + 1); 236 | memcpy(str, item->valuestring, strLen); 237 | *(str + strLen) = 0; 238 | *(int *)((int)base + (i * sizeof(int))) = (int)str; 239 | break; 240 | default: 241 | break; 242 | } 243 | } 244 | } 245 | } 246 | 247 | 248 | /** 249 | * @brief 解析JSON对象 250 | * 251 | * @param json JSON对象 252 | * @param model 数据模型 253 | * @param modelSize 数据模型数量 254 | * @return void* 解析得到的对象 255 | */ 256 | void *csonDecodeObject(cJSON *json, CsonModel *model, int modelSize) 257 | { 258 | CSON_ASSERT(json, return NULL); 259 | 260 | if (json->type == cJSON_NULL) { 261 | return NULL; 262 | } 263 | 264 | short objSize = 0; 265 | for (short i = 0; i < modelSize; i++) 266 | { 267 | if (model[i].type == CSON_TYPE_OBJ) 268 | { 269 | objSize = model[i].param.objSize; 270 | } 271 | } 272 | void *obj = cson.malloc(objSize); 273 | CSON_ASSERT(obj, return NULL); 274 | 275 | for (short i = 0; i < modelSize; i++) 276 | { 277 | switch (model[i].type) 278 | { 279 | case CSON_TYPE_CHAR: 280 | *(char *)((int)obj + model[i].offset) = (char)csonDecodeNumber(json, model[i].key); 281 | break; 282 | case CSON_TYPE_SHORT: 283 | *(short *)((int)obj + model[i].offset) = (short)csonDecodeNumber(json, model[i].key); 284 | break; 285 | case CSON_TYPE_INT: 286 | *(int *)((int)obj + model[i].offset) = (int)csonDecodeNumber(json, model[i].key); 287 | break; 288 | case CSON_TYPE_LONG: 289 | *(long *)((int)obj + model[i].offset) = (long)csonDecodeNumber(json, model[i].key); 290 | break; 291 | case CSON_TYPE_FLOAT: 292 | *(float *)((int)obj + model[i].offset) = (float)csonDecodeDouble(json, model[i].key); 293 | break; 294 | case CSON_TYPE_DOUBLE: 295 | *(double *)((int)obj + model[i].offset) = csonDecodeDouble(json, model[i].key); 296 | break; 297 | case CSON_TYPE_BOOL: 298 | *(char *)((int)obj + model[i].offset) = (char)csonDecodeBool(json, model[i].key); 299 | break; 300 | case CSON_TYPE_STRING: 301 | *(int *)((int)obj + model[i].offset) = (int)csonDecodeString(json, model[i].key); 302 | break; 303 | case CSON_TYPE_LIST: 304 | *(int *)((int)obj + model[i].offset) = (int)csonDecodeList(json, 305 | model[i].key, model[i].param.sub.model, model[i].param.sub.size); 306 | break; 307 | case CSON_TYPE_STRUCT: 308 | *(int *)((int)obj + model[i].offset) = (int)csonDecodeObject( 309 | cJSON_GetObjectItem(json, model[i].key), 310 | model[i].param.sub.model, model[i].param.sub.size); 311 | break; 312 | case CSON_TYPE_ARRAY: 313 | csonDecodeArray(json, model[i].key, (void *)((int)obj + model[i].offset), 314 | model[i].param.array.eleType, model[i].param.array.size); 315 | break; 316 | case CSON_TYPE_JSON: 317 | *(int *)((int)obj + model[i].offset) = (int)cJSON_PrintUnformatted( 318 | cJSON_GetObjectItem(json, model[i].key)); 319 | break; 320 | default: 321 | break; 322 | } 323 | } 324 | return obj; 325 | } 326 | 327 | 328 | /** 329 | * @brief 解析JSON字符串 330 | * 331 | * @param jsonStr json字符串 332 | * @param model 数据模型 333 | * @param modelSize 数据模型数量 334 | * @return void* 解析得到的对象 335 | */ 336 | void *csonDecode(const char *jsonStr, CsonModel *model, int modelSize) 337 | { 338 | void *obj; 339 | cJSON *json = cJSON_Parse(jsonStr); 340 | CSON_ASSERT(json, return NULL); 341 | obj = csonDecodeObject(json, model, modelSize); 342 | cJSON_Delete(json); 343 | return obj; 344 | } 345 | 346 | 347 | 348 | /** 349 | * @brief 数字编码编码JSON 350 | * 351 | * @param json json对象 352 | * @param key key 353 | * @param num 数值 354 | */ 355 | void csonEncodeNumber(cJSON *json, char *key, double num) 356 | { 357 | if (key) 358 | { 359 | cJSON_AddNumberToObject(json, key, num); 360 | } 361 | else 362 | { 363 | json->type = cJSON_Number; 364 | json->valuedouble = num; 365 | json->valueint = (int)num; 366 | } 367 | } 368 | 369 | 370 | /** 371 | * @brief 字符串编码编码JSON 372 | * 373 | * @param json json对象 374 | * @param key key 375 | * @param str 字符串 376 | */ 377 | void csonEncodeString(cJSON *json, char *key, char *str) 378 | { 379 | if (key) 380 | { 381 | cJSON_AddStringToObject(json, key, str); 382 | } 383 | else 384 | { 385 | json->type = cJSON_String; 386 | json->valuestring = str; 387 | } 388 | } 389 | 390 | 391 | /** 392 | * @brief CsonList编码成JSON对象 393 | * 394 | * @param list CsonList对象 395 | * @param model 数据模型 396 | * @param modelSize 数据模型数量 397 | * @return cJSON* 编码得到的JOSN对象 398 | */ 399 | cJSON* csonEncodeList(CsonList *list, CsonModel *model, int modelSize) 400 | { 401 | cJSON *root = cJSON_CreateArray(); 402 | cJSON *item; 403 | CsonList *p = list; 404 | 405 | while (p) 406 | { 407 | if (p->obj) 408 | { 409 | if (csonIsBasicListModel(model)) 410 | { 411 | item = csonEncodeObject(&(p->obj), model, modelSize); 412 | } 413 | else 414 | { 415 | item = csonEncodeObject(p->obj, model, modelSize); 416 | } 417 | cJSON_AddItemToArray(root, item); 418 | } 419 | p = p->next; 420 | } 421 | return root; 422 | } 423 | 424 | 425 | /** 426 | * @brief 数组编码成JSON对象 427 | * 428 | * @param base 数组基址 429 | * @param elementType 数组元素类型 430 | * @param arraySize 数组大小 431 | * @return cJSON* 编码得到的JOSN对象 432 | */ 433 | cJSON* csonEncodeArray(void *base, CsonType elementType, short arraySize) 434 | { 435 | cJSON *root = cJSON_CreateArray(); 436 | cJSON *item; 437 | 438 | for (short i = 0; i < arraySize; i++) 439 | { 440 | switch (elementType) 441 | { 442 | case CSON_TYPE_CHAR: 443 | item = cJSON_CreateNumber(*(char *)((int)base + (i * sizeof(char)))); 444 | break; 445 | case CSON_TYPE_SHORT: 446 | item = cJSON_CreateNumber(*(short *)((int)base + (i * sizeof(short)))); 447 | break; 448 | case CSON_TYPE_INT: 449 | item = cJSON_CreateNumber(*(int *)((int)base + (i * sizeof(int)))); 450 | break; 451 | case CSON_TYPE_LONG: 452 | item = cJSON_CreateNumber(*(long *)((int)base + (i * sizeof(int)))); 453 | break; 454 | case CSON_TYPE_FLOAT: 455 | item = cJSON_CreateNumber(*(float *)((int)base + (i * sizeof(float)))); 456 | break; 457 | case CSON_TYPE_DOUBLE: 458 | item = cJSON_CreateNumber(*(double *)((int)base + (i * sizeof(double)))); 459 | break; 460 | case CSON_TYPE_STRING: 461 | item = cJSON_CreateString((char *)*(int *)((int)base + (i * sizeof(int)))); 462 | break; 463 | default: 464 | break; 465 | } 466 | cJSON_AddItemToArray(root, item); 467 | } 468 | return root; 469 | } 470 | 471 | 472 | /** 473 | * @brief 编码JSON对象 474 | * 475 | * @param obj 对象 476 | * @param model 数据模型 477 | * @param modelSize 数据模型数量 478 | * @return cJSON* 编码得到的json对象 479 | */ 480 | cJSON* csonEncodeObject(void *obj, CsonModel *model, int modelSize) 481 | { 482 | if (!obj) { 483 | return cJSON_CreateNull(); 484 | } 485 | cJSON *root = cJSON_CreateObject(); 486 | 487 | for (short i = 0; i < modelSize; i++) 488 | { 489 | switch (model[i].type) 490 | { 491 | case CSON_TYPE_CHAR: 492 | csonEncodeNumber(root, model[i].key, *(char *)((int)obj + model[i].offset)); 493 | break; 494 | case CSON_TYPE_SHORT: 495 | csonEncodeNumber(root, model[i].key, *(short *)((int)obj + model[i].offset)); 496 | break; 497 | case CSON_TYPE_INT: 498 | csonEncodeNumber(root, model[i].key, *(int *)((int)obj + model[i].offset)); 499 | break; 500 | case CSON_TYPE_LONG: 501 | csonEncodeNumber(root, model[i].key, *(long *)((int)obj + model[i].offset)); 502 | break; 503 | case CSON_TYPE_FLOAT: 504 | csonEncodeNumber(root, model[i].key, *(float *)((int)obj + model[i].offset)); 505 | break; 506 | case CSON_TYPE_DOUBLE: 507 | csonEncodeNumber(root, model[i].key, *(double *)((int)obj + model[i].offset)); 508 | break; 509 | case CSON_TYPE_BOOL: 510 | cJSON_AddBoolToObject(root, model[i].key, *(char *)((int)obj + model[i].offset)); 511 | break; 512 | case CSON_TYPE_STRING: 513 | if ((char *)(*(int *)((int)obj + model[i].offset))) 514 | { 515 | csonEncodeString(root, model[i].key, (char *)(*(int *)((int)obj + model[i].offset))); 516 | } 517 | break; 518 | case CSON_TYPE_LIST: 519 | if ((CsonList *)*(int *)((int)obj + model[i].offset)) 520 | { 521 | cJSON_AddItemToObject(root, model[i].key, 522 | csonEncodeList((CsonList *)*(int *)((int)obj + model[i].offset), 523 | model[i].param.sub.model, model[i].param.sub.size)); 524 | } 525 | break; 526 | case CSON_TYPE_STRUCT: 527 | if ((void *)(*(int *)((int)obj + model[i].offset))) 528 | { 529 | cJSON_AddItemToObject(root, model[i].key, csonEncodeObject( 530 | (void *)(*(int *)((int)obj + model[i].offset)), 531 | model[i].param.sub.model, model[i].param.sub.size)); 532 | } 533 | break; 534 | case CSON_TYPE_ARRAY: 535 | cJSON_AddItemToObject(root, model[i].key, csonEncodeArray( 536 | (void *)((int)obj + model[i].offset), 537 | model[i].param.array.eleType, model[i].param.array.size)); 538 | break; 539 | case CSON_TYPE_JSON: 540 | if ((char *)(*(int *)((int)obj + model[i].offset))) 541 | { 542 | cJSON_AddItemToObject(root, model[i].key, 543 | cJSON_Parse((char *)(*(int *)((int)obj + model[i].offset)))); 544 | } 545 | break; 546 | default: 547 | break; 548 | } 549 | } 550 | return root; 551 | } 552 | 553 | 554 | /** 555 | * @brief 编码成json字符串 556 | * 557 | * @param obj 对象 558 | * @param model 数据模型 559 | * @param modelSize 数据模型数量 560 | * @param bufferSize 分配给json字符串的空间大小 561 | * @param fmt 是否格式化json字符串 562 | * @return char* 编码得到的json字符串 563 | */ 564 | char* csonEncode(void *obj, CsonModel *model, int modelSize, int bufferSize, int fmt) 565 | { 566 | cJSON *json = csonEncodeObject(obj, model, modelSize); 567 | CSON_ASSERT(json, return NULL); 568 | char *jsonStr = cJSON_PrintBuffered(json, bufferSize, fmt); 569 | cJSON_Delete(json); 570 | return jsonStr; 571 | } 572 | 573 | 574 | /** 575 | * @brief 编码成json字符串 576 | * 577 | * @param obj 对象 578 | * @param model 数据模型 579 | * @param modelSize 数据模型数量 580 | * @return char* 编码得到的json字符串 581 | */ 582 | char* csonEncodeUnformatted(void *obj, CsonModel *model, int modelSize) 583 | { 584 | cJSON *json = csonEncodeObject(obj, model, modelSize); 585 | CSON_ASSERT(json, return NULL); 586 | char *jsonStr = cJSON_PrintUnformatted(json); 587 | cJSON_Delete(json); 588 | return jsonStr; 589 | } 590 | 591 | 592 | /** 593 | * @brief 释放CSON解析出的对象 594 | * 595 | * @param obj 对象 596 | * @param model 对象模型 597 | * @param modelSize 对象模型数量 598 | */ 599 | void csonFree(void *obj, CsonModel *model, int modelSize) 600 | { 601 | CsonList *list, *p; 602 | int *tmpNode; 603 | 604 | for (short i = 0; i < modelSize; i++) 605 | { 606 | switch ((int)model[i].type) 607 | { 608 | case CSON_TYPE_CHAR: 609 | case CSON_TYPE_SHORT: 610 | case CSON_TYPE_INT: 611 | case CSON_TYPE_LONG: 612 | case CSON_TYPE_FLOAT: 613 | case CSON_TYPE_DOUBLE: 614 | break; 615 | case CSON_TYPE_STRING: 616 | case CSON_TYPE_JSON: 617 | cson.free((char *)(*(int *)((int)obj + model[i].offset))); 618 | break; 619 | case CSON_TYPE_LIST: 620 | list = (CsonList *)*(int *)((int)obj + model[i].offset); 621 | while (list) 622 | { 623 | p = list; 624 | list = list->next; 625 | if (p->obj) 626 | { 627 | if (csonIsBasicListModel(model[i].param.sub.model)) 628 | { 629 | tmpNode = cson.malloc(sizeof(int)); 630 | *tmpNode = (int)(&(p->obj)); 631 | } 632 | else 633 | { 634 | tmpNode = p->obj; 635 | } 636 | csonFree(tmpNode, 637 | model[i].param.sub.model, model[i].param.sub.size); 638 | } 639 | cson.free(p); 640 | } 641 | break; 642 | case CSON_TYPE_STRUCT: 643 | csonFree((void *)(*(int *)((int)obj + model[i].offset)), 644 | model[i].param.sub.model, model[i].param.sub.size); 645 | break; 646 | case CSON_TYPE_ARRAY: 647 | if (model[i].param.array.eleType == CSON_TYPE_STRING) 648 | { 649 | for (short j = 0; j< model[i].param.array.size; j++) 650 | { 651 | if (*(int *)((int)obj + model[i].offset + (j << 2))) 652 | { 653 | cson.free((void *)*(int *)((int)obj + model[i].offset + (j << 2))); 654 | } 655 | } 656 | } 657 | break; 658 | default: 659 | break; 660 | } 661 | } 662 | cson.free(obj); 663 | } 664 | 665 | 666 | /** 667 | * @brief 释放cson编码生成的json字符串 668 | * 669 | * @param jsonStr json字符串 670 | */ 671 | void csonFreeJson(const char *jsonStr) 672 | { 673 | CSON_ASSERT(jsonStr, return); 674 | cson.free((void *)jsonStr); 675 | } 676 | 677 | 678 | /** 679 | * @brief CSON链表添加节点 680 | * 681 | * @param list 链表 682 | * @param obj 节点对象 683 | * @return CsonList 链表 684 | */ 685 | CsonList* csonListAdd(CsonList *list, void *obj) 686 | { 687 | if (!list) 688 | { 689 | list = cson.malloc(sizeof(CsonList)); 690 | if (!list) 691 | { 692 | return NULL; 693 | } 694 | list->next = NULL; 695 | list->obj = NULL; 696 | } 697 | CsonList *p = list; 698 | while (p->next) 699 | { 700 | p = p->next; 701 | } 702 | if (!p->obj) 703 | { 704 | p->obj = obj; 705 | p->next = NULL; 706 | } 707 | else 708 | { 709 | CsonList *node = cson.malloc(sizeof(CsonList)); 710 | if (node) 711 | { 712 | node->obj = obj; 713 | node->next = NULL; 714 | p->next = node; 715 | } 716 | } 717 | return list; 718 | } 719 | 720 | 721 | /** 722 | * @brief CSON链表删除节点 723 | * 724 | * @param list 链表 725 | * @param obj 节点对象 726 | * @param freeMem 释放内存 727 | * @return CsonList 链表 728 | */ 729 | CsonList *csonListDelete(CsonList *list, void *obj, char freeMem) 730 | { 731 | CSON_ASSERT(list, return NULL); 732 | 733 | CsonList head = {0}; 734 | head.next = list; 735 | CsonList *p = &head; 736 | CsonList *tmp; 737 | while (p->next) 738 | { 739 | if (p->next->obj && p->next->obj == obj) 740 | { 741 | tmp = p->next; 742 | p->next = p->next->next ? p->next->next : NULL; 743 | if (freeMem) 744 | { 745 | cson.free(tmp->obj); 746 | cson.free(tmp); 747 | } 748 | break; 749 | } 750 | p = p->next; 751 | } 752 | return head.next; 753 | } 754 | 755 | 756 | /** 757 | * @brief CSON新字符串 758 | * 759 | * @param src 源字符串 760 | * @return char* 新字符串 761 | * @note 此函数用于复制字符串,建议对结构体中字符串成员赋值时,使用此函数, 762 | * 方便使用`csonFree`进行内存释放 763 | */ 764 | char* csonNewString(const char *src) 765 | { 766 | int len = strlen(src); 767 | char *dest = cson.malloc(len + 1); 768 | strcpy(dest, src); 769 | return dest; 770 | } 771 | -------------------------------------------------------------------------------- /src/cson.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cson.h 3 | * @author Letter (NevermindZZT@gmail.com) 4 | * @brief cson 5 | * @version 0.1 6 | * @date 2019-08-26 7 | * 8 | * @copyright (c) 2019 Letter 9 | * 10 | */ 11 | 12 | #ifndef __CSON_H__ 13 | #define __CSON_H__ 14 | 15 | #include "stddef.h" 16 | #include "cJSON.h" 17 | 18 | 19 | #define CSON_VERSION "1.0.4" /**< CSON版本 */ 20 | 21 | /** 22 | * @defgroup CSON cson 23 | * @brief json tools for C 24 | * @addtogroup CSON 25 | * @{ 26 | */ 27 | 28 | 29 | /** 30 | * @brief CSON数据类型定义 31 | * 32 | */ 33 | typedef enum 34 | { 35 | CSON_TYPE_OBJ = 0, 36 | CSON_TYPE_CHAR, 37 | CSON_TYPE_SHORT, 38 | CSON_TYPE_INT, 39 | CSON_TYPE_LONG, 40 | CSON_TYPE_FLOAT, 41 | CSON_TYPE_DOUBLE, 42 | CSON_TYPE_BOOL, 43 | CSON_TYPE_STRING, 44 | CSON_TYPE_STRUCT, 45 | CSON_TYPE_LIST, 46 | CSON_TYPE_ARRAY, 47 | CSON_TYPE_JSON, 48 | } CsonType; 49 | 50 | 51 | /** 52 | * @brief CSON数据模型定义 53 | * 54 | */ 55 | typedef struct cson_model 56 | { 57 | CsonType type; /**< 数据类型 */ 58 | char *key; /**< 元素键值 */ 59 | short offset; /**< 元素偏移 */ 60 | union 61 | { 62 | struct 63 | { 64 | struct cson_model *model; /**< 子结构体模型 */ 65 | short size; /**< 子结构体模型大小 */ 66 | } sub; /**< 子结构体 */ 67 | struct 68 | { 69 | CsonType eleType; /**< 数组元素类型 */ 70 | short size; /**< 数组大小 */ 71 | } array; /**< 数组 */ 72 | int objSize; /**< 对象大小 */ 73 | CsonType basicListType; /**< 基础数据链表类型 */ 74 | } param; 75 | } CsonModel; 76 | 77 | 78 | /** 79 | * @brief Cson链表 80 | * 81 | */ 82 | typedef struct cson_list 83 | { 84 | struct cson_list *next; /**< 下一个元素 */ 85 | void *obj; /**< 对象 */ 86 | } CsonList; 87 | 88 | 89 | extern CsonModel csonBasicListModel[]; /**< 基础类型链表数据模型 */ 90 | 91 | #define CSON_MODEL_CHAR_LIST &csonBasicListModel[0] /**< char型链表数据模型 */ 92 | #define CSON_MODEL_SHORT_LIST &csonBasicListModel[2] /**< short型链表数据模型 */ 93 | #define CSON_MODEL_INT_LIST &csonBasicListModel[4] /**< int型链表数据模型 */ 94 | #define CSON_MODEL_LONG_LIST &csonBasicListModel[6] /**< long型链表数据模型 */ 95 | #define CSON_MODEL_FLOAT_LIST &csonBasicListModel[8] /**< float型链表数据模型 */ 96 | #define CSON_MODEL_DOUBLE_LIST &csonBasicListModel[10] /**< double型链表数据模型 */ 97 | #define CSON_MODEL_STRING_LIST &csonBasicListModel[12] /**< string型链表数据模型 */ 98 | 99 | #define CSON_BASIC_LIST_MODEL_SIZE 2 /**< 基础类型链表数据模型大小 */ 100 | 101 | /** 102 | * @brief 对象数据模型 103 | * 104 | * @param type 对象类型 105 | */ 106 | #define CSON_MODEL_OBJ(type) \ 107 | {CSON_TYPE_OBJ, NULL, 0, .param.objSize=sizeof(type)} 108 | 109 | /** 110 | * @brief char型数据模型 111 | * 112 | * @param type 对象模型 113 | * @param key 数据键值 114 | */ 115 | #define CSON_MODEL_CHAR(type, key) \ 116 | {CSON_TYPE_CHAR, #key, offsetof(type, key)} 117 | 118 | /** 119 | * @brief short型数据模型 120 | * 121 | * @param type 对象模型 122 | * @param key 数据键值 123 | */ 124 | #define CSON_MODEL_SHORT(type, key) \ 125 | {CSON_TYPE_SHORT, #key, offsetof(type, key)} 126 | 127 | /** 128 | * @brief int型数据模型 129 | * 130 | * @param type 对象模型 131 | * @param key 数据键值 132 | */ 133 | #define CSON_MODEL_INT(type, key) \ 134 | {CSON_TYPE_INT, #key, offsetof(type, key)} 135 | 136 | /** 137 | * @brief long型数据模型 138 | * 139 | * @param type 对象模型 140 | * @param key 数据键值 141 | */ 142 | #define CSON_MODEL_LONG(type, key) \ 143 | {CSON_TYPE_LONG, #key, offsetof(type, key)} 144 | 145 | /** 146 | * @brief float型数据模型 147 | * 148 | * @param type 对象模型 149 | * @param key 数据键值 150 | */ 151 | #define CSON_MODEL_FLOAT(type, key) \ 152 | {CSON_TYPE_FLOAT, #key, offsetof(type, key)} 153 | 154 | /** 155 | * @brief double型数据模型 156 | * 157 | * @param type 对象模型 158 | * @param key 数据键值 159 | */ 160 | #define CSON_MODEL_DOUBLE(type, key) \ 161 | {CSON_TYPE_DOUBLE, #key, offsetof(type, key)} 162 | 163 | /** 164 | * @brief bool型数据模型 165 | * 166 | * @param type 对象模型 167 | * @param key 数据键值 168 | */ 169 | #define CSON_MODEL_BOOL(type, key) \ 170 | {CSON_TYPE_CHAR, #key, offsetof(type, key)} 171 | 172 | /** 173 | * @brief 字符串型数据模型 174 | * 175 | * @param type 对象模型 176 | * @param key 数据键值 177 | */ 178 | #define CSON_MODEL_STRING(type, key) \ 179 | {CSON_TYPE_STRING, #key, offsetof(type, key)} 180 | 181 | /** 182 | * @brief 结构体型数据模型 183 | * 184 | * @param type 对象模型 185 | * @param key 数据键值 186 | * @param submodel 子结构体模型 187 | * @param subsize 子结构体模型大小 188 | */ 189 | #define CSON_MODEL_STRUCT(type, key, submodel, subsize) \ 190 | {CSON_TYPE_STRUCT, #key, offsetof(type, key), .param.sub.model=submodel, .param.sub.size=subsize} 191 | 192 | /** 193 | * @brief list型数据模型 194 | * 195 | * @param type 对象模型 196 | * @param key 数据键值 197 | * @param submodel 子结构体模型 198 | * @param subsize 子结构体模型大小 199 | */ 200 | #define CSON_MODEL_LIST(type, key, submodel, subsize) \ 201 | {CSON_TYPE_LIST, #key, offsetof(type, key), .param.sub.model=submodel, .param.sub.size=subsize} 202 | 203 | /** 204 | * @brief list型数据模型 205 | * 206 | * @param type 对象模型 207 | * @param key 数据键值 208 | * @param elementType 数组元素类型 209 | * @param arraySize 数组大小 210 | */ 211 | #define CSON_MODEL_ARRAY(type, key, elementType, arraySize) \ 212 | {CSON_TYPE_ARRAY, #key, offsetof(type, key), .param.array.eleType=elementType, .param.array.size=arraySize} 213 | 214 | /** 215 | * @brief 子json数据模型 216 | * 217 | * @param type 对象模型 218 | * @param key 数据键值 219 | */ 220 | #define CSON_MODEL_JSON(type, key) \ 221 | {CSON_TYPE_JSON, #key, offsetof(type, key)} 222 | 223 | /** 224 | * @brief CSON断言 225 | * 226 | * @param expr 表达式 227 | * @param action 断言失败执行动作 228 | */ 229 | #define CSON_ASSERT(expr, action) \ 230 | if (!(expr)) { \ 231 | printf(#expr " assert failed at file: %s, line: %d\r\n", __FILE__, __LINE__); \ 232 | action; \ 233 | } 234 | 235 | /** 236 | * @brief CSON初始化 237 | * 238 | * @param malloc 内存分配函数 239 | * @param free 内存释放函数 240 | */ 241 | void csonInit(void *malloc, void *free); 242 | 243 | /** 244 | * @brief 解析JSON对象 245 | * 246 | * @param json JSON对象 247 | * @param model 数据模型 248 | * @param modelSize 数据模型数量 249 | * @return void* 解析得到的对象 250 | */ 251 | void *csonDecodeObject(cJSON *json, CsonModel *model, int modelSize); 252 | 253 | /** 254 | * @brief 解析JSON对象 255 | * 256 | * @param json JSON对象 257 | * @param model 数据模型 258 | * @return void* 解析得到的对象 259 | */ 260 | #define csonDecodeObjectEx(json, model) \ 261 | csonDecodeObject(json, model, sizeof(model) / sizeof(CsonModel)) 262 | 263 | /** 264 | * @brief 解析JSON字符串 265 | * 266 | * @param jsonStr json字符串 267 | * @param model 数据模型 268 | * @param modelSize 数据模型数量 269 | * @return void* 解析得到的对象 270 | */ 271 | void *csonDecode(const char *jsonStr, CsonModel *model, int modelSize); 272 | 273 | /** 274 | * @brief 解析JSON字符串 275 | * 276 | * @param jsonStr json字符串 277 | * @param model 数据模型 278 | * @return void* 解析得到的对象 279 | */ 280 | #define csonDecodeEx(jsonStr, model) \ 281 | csonDecode(jsonStr, model, sizeof(model) / sizeof(CsonModel)); 282 | 283 | /** 284 | * @brief 编码成json字符串 285 | * 286 | * @param obj 对象 287 | * @param model 数据模型 288 | * @param modelSize 数据模型数量 289 | * @return char* 编码得到的json字符串 290 | */ 291 | cJSON* csonEncodeObject(void *obj, CsonModel *model, int modelSize); 292 | 293 | /** 294 | * @brief 编码成json字符串 295 | * 296 | * @param obj 对象 297 | * @param model 数据模型 298 | * @param modelSize 数据模型数量 299 | * @param bufferSize 分配给json字符串的空间大小 300 | * @param fmt 是否格式化json字符串 301 | * @return char* 编码得到的json字符串 302 | */ 303 | char* csonEncode(void *obj, CsonModel *model, int modelSize, int bufferSize, int fmt); 304 | 305 | /** 306 | * @brief 编码成json字符串 307 | * 308 | * @param obj 对象 309 | * @param model 数据模型 310 | * @param bufferSize 分配给json字符串的空间大小 311 | * @param fmt 是否格式化json字符串 312 | * @return char* 编码得到的json字符串 313 | */ 314 | #define csonEncodeEx(obj, model, bufferSize, fmt) \ 315 | csonEncode(obj, model, sizeof(model)/sizeof(CsonModel), bufferSize, fmt) 316 | 317 | /** 318 | * @brief 编码成json字符串 319 | * 320 | * @param obj 对象 321 | * @param model 数据模型 322 | * @param modelSize 数据模型数量 323 | * @return char* 编码得到的json字符串 324 | */ 325 | char* csonEncodeUnformatted(void *obj, CsonModel *model, int modelSize); 326 | 327 | /** 328 | * @brief 编码成json字符串 329 | * 330 | * @param obj 对象 331 | * @param model 数据模型 332 | * @return char* 编码得到的json字符串 333 | */ 334 | #define csonEncodeUnformattedEx(obj, model) \ 335 | csonEncodeUnformatted(obj, model, sizeof(model) / sizeof(CsonModel)) 336 | 337 | /** 338 | * @brief 释放CSON解析出的对象 339 | * 340 | * @param obj 对象 341 | * @param model 对象模型 342 | * @param modelSize 对象模型数量 343 | */ 344 | void csonFree(void *obj, CsonModel *model, int modelSize); 345 | 346 | /** 347 | * @brief 释放CSON解析出的对象 348 | * 349 | * @param obj 对象 350 | * @param model 对象模型 351 | */ 352 | #define csonFreeEx(obj, model) \ 353 | csonFree(obj, model, sizeof(model) / sizeof(CsonModel)) 354 | 355 | /** 356 | * @brief 释放cson编码生成的json字符串 357 | * 358 | * @param jsonStr json字符串 359 | */ 360 | void csonFreeJson(const char *jsonStr); 361 | 362 | /** 363 | * @brief CSON链表添加节点 364 | * 365 | * @param list 链表 366 | * @param obj 节点对象 367 | * @return CsonList 链表 368 | */ 369 | CsonList* csonListAdd(CsonList *list, void *obj); 370 | 371 | /** 372 | * @brief CSON链表删除节点 373 | * 374 | * @param list 链表 375 | * @param obj 节点对象 376 | * @param freeMem 释放内存 377 | * @return CsonList 链表 378 | */ 379 | CsonList *csonListDelete(CsonList *list, void *obj, char freeMem); 380 | 381 | /** 382 | * @brief CSON新字符串 383 | * 384 | * @param src 源字符串 385 | * @return char* 新字符串 386 | * @note 此函数用于复制字符串,建议对结构体中字符串成员赋值时,使用此函数, 387 | * 方便使用`csonFree`进行内存释放 388 | */ 389 | char* csonNewString(const char *src); 390 | 391 | /** 392 | * @} 393 | */ 394 | 395 | #endif 396 | --------------------------------------------------------------------------------