Initial commit

This commit is contained in:
Letter 2019-08-28 18:49:55 +08:00
commit e9a1505a97
8 changed files with 2272 additions and 0 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Letter
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

169
demo/cson_test.c Normal file
View File

@ -0,0 +1,169 @@
/**
* @file cson_test.c
* @author Letter (NevermindZZT@gmail.cn)
* @brief
* @version 0.1
* @date 2019-08-27
*
* @copyright (c) 2019 Letter
*
*/
#include "shell.h"
#include "ulog.h"
#include "cson.h"
struct subtest
{
int id;
char *test;
};
struct test
{
char id;
short num;
int max;
double value;
char *name;
struct subtest *sub;
CsonList *list;
char *str[2];
CsonList *charList;
CsonList *strList;
};
CsonModel subModel[] =
{
CSON_MODEL_OBJ(struct subtest),
CSON_MODEL_INT(struct subtest, id),
CSON_MODEL_STRING(struct subtest, test)
};
CsonModel model[] =
{
CSON_MODEL_OBJ(struct test),
CSON_MODEL_CHAR(struct test, id),
CSON_MODEL_SHORT(struct test, num),
CSON_MODEL_INT(struct test, max),
CSON_MODEL_DOUBLE(struct test, value),
CSON_MODEL_STRING(struct test, name),
CSON_MODEL_STRUCT(struct test, sub, subModel, sizeof(subModel)/sizeof(CsonModel)),
CSON_MODEL_LIST(struct test, list, subModel, sizeof(subModel)/sizeof(CsonModel)),
CSON_MODEL_ARRAY(struct test, str, CSON_TYPE_STRING, 2),
CSON_MODEL_LIST(struct test, charList, CSON_MODEL_INT_LIST, CSON_BASIC_LIST_MODEL_SIZE),
CSON_MODEL_LIST(struct test, strList, CSON_MODEL_STRING_LIST, CSON_BASIC_LIST_MODEL_SIZE)
};
void csonTest(void)
{
char *jsonStr = "{\"id\": 1, \"num\": 300, \"max\": 1000, \"value\": 10.3, \"name\": \"letter\", "
"\"sub\": {\"id\": 20, \"test\": \"hello world\"},"
" \"list\": [{\"id\": 21, \"test\": \"hello cson\"}, {\"id\": 22, \"test\": \"hello letter\"}],"
"\"str\": [\"array1\", \"array2\"],"
"\"charList\": [1, 12, 52], "
"\"strList\": [\"str1\", \"str2\"]}";
struct test *st = csonDecode(jsonStr, model, sizeof(model)/sizeof(CsonModel));
ulogDebug("josn 0x%08x, id: %d, num: %d, max: %d, value: %lf, name: %s\r\nsub: id: %d, test: %s",
st, st->id, st->num, st->max, st->value, st->name, st->sub->id, st->sub->test);
ulogDebug("str: %s %s", st->str[0], st->str[1]);
CsonList *p = st->list;
while (p)
{
struct subtest *sst = p->obj;
if (p->obj)
{
ulogDebug("list: id: %d, test: %s", sst->id, sst->test);
}
p = p->next;
}
p = st->charList;
while (p)
{
int *sst = p->obj;
if (p->obj)
{
ulogDebug("list: id: %d", *sst);
}
p = p->next;
}
p = st->strList;
while (p)
{
char **sst = p->obj;
if (p->obj)
{
ulogDebug("list: id: %s", *sst);
}
p = p->next;
}
char *root = csonEncode(st, model, sizeof(model)/sizeof(CsonModel), 512, 0);
printf("encode: %s", root);
csonFreeJson(root);
csonFree(st, model, sizeof(model)/sizeof(CsonModel));
}
SHELL_EXPORT_CMD(csonTest, csonTest, test);
/** 项目结构体 */
struct project
{
int id;
char *name;
};
/** 仓库结构体 */
struct hub
{
int id;
char *user;
struct project *cson;
};
/** 项目结构体数据模型 */
CsonModel projectModel[] =
{
CSON_MODEL_OBJ(struct project),
CSON_MODEL_INT(struct project, id),
CSON_MODEL_STRING(struct project, name),
};
/** 仓库结构体数据模型 */
CsonModel hubModel[] =
{
CSON_MODEL_OBJ(struct hub),
CSON_MODEL_INT(struct hub, id),
CSON_MODEL_STRING(struct hub, user),
CSON_MODEL_STRUCT(struct hub, cson, projectModel, sizeof(projectModel)/sizeof(CsonModel))
};
void csonDemo(void)
{
char *jsonDemo = "{\"id\": 1, \"user\": \"Letter\", \"cson\": {\"id\": 2, \"name\": \"cson\"}}";
/** 解析json */
struct hub *pHub = csonDecode(jsonDemo, hubModel, sizeof(hubModel)/sizeof(CsonModel));
printf("hub: id: %d, user: %s, project id: %d, project name: %s\r\n",
pHub->id, pHub->user, pHub->cson->id, pHub->cson->name);
/** 序列化对象 */
char *formatJson = csonEncodeFormatted(pHub, hubModel, sizeof(hubModel)/sizeof(CsonModel));
printf("format json: %s\r\n", formatJson);
/** 释放结构体对象 */
csonFree(pHub, hubModel, sizeof(hubModel)/sizeof(CsonModel));
/** 释放序列化生成的json字符串 */
csonFreeJson(formatJson);
}
SHELL_EXPORT_CMD(csonDemo, csonDemo, test);

261
redeme.md Normal file
View File

@ -0,0 +1,261 @@
# CSON
![version](https://img.shields.io/badge/version-1.0.0-brightgreen.svg)
![build](https://img.shields.io/badge/build-2019.8.27-brightgreen.svg)
基于[cJSON](https://github.com/kbranigan/cJSON),运行于C语言平台的json-struct模型解析工具
- [CSON](#cson)
- [简介](#简介)
- [使用](#使用)
- [声明结构体](#声明结构体)
- [定义数据模型](#定义数据模型)
- [使用CSON解析](#使用cson解析)
- [结构体数据类型](#结构体数据类型)
- [数据模型映射](#数据模型映射)
- [API](#api)
- [初始化](#初始化)
- [反序列化](#反序列化)
- [序列化](#序列化)
- [空间释放](#空间释放)
- [释放结构体对象](#释放结构体对象)
- [释放json字符串](#释放json字符串)
- [注意](#注意)
## 简介
[CSON](https://github.com/NevermindZZT/cson)是一个简单的cJSON的二次封装相比于使用原生cJSON一层一层解析的方式CSON采用模型映射的方式使用模型将结构体的特征进行描述然后根据模型将json数据直接解析成结构体免去使用原生cJSON需要多次调用API的复杂性可以很大程度减少代码冗余增加代码逻辑性。
CSON的模型映射借鉴了高级语言(比如说Java)的反射机制通过建立数据模型记录结构体的元素类型偏移然后直接在内存层面进行操作对C语言提供类似于[gson](https://github.com/google/gson)这样的高效json解析工具
## 使用
CSON通过数据模型将结构体和json建立映射关系因此你需要做的就是在声明结构体的时候同时使用数据模型对结构体进行描述之后只需要直接调用CSON的api即可
### 声明结构体
```C
/** 项目结构体 */
struct project
{
int id;
char *name;
};
/** 仓库结构体 */
struct hub
{
int id;
char *user;
struct project *cson;
};
```
### 定义数据模型
对每一个需要使用cson的结构体都需要定义相对应的数据模型
```C
/** 项目结构体数据模型 */
CsonModel projectModel[] =
{
CSON_MODEL_OBJ(struct project),
CSON_MODEL_INT(struct project, id),
CSON_MODEL_STRING(struct project, name),
};
/** 仓库结构体数据模型 */
CsonModel hubModel[] =
{
CSON_MODEL_OBJ(struct hub),
CSON_MODEL_INT(struct hub, id),
CSON_MODEL_STRING(struct hub, user),
CSON_MODEL_STRUCT(struct hub, cson, projectModel, sizeof(projectModel)/sizeof(CsonModel))
};
```
### 使用CSON解析
只需要定义好数据模型就可以使用CSON读json进行序列化和反序列化
```C
void csonDemo(void)
{
char *jsonDemo = "{\"id\": 1, \"user\": \"Letter\", \"cson\": {\"id\": 2, \"name\": \"cson\"}}";
/** 解析json */
struct hub *pHub = csonDecode(jsonDemo, hubModel, sizeof(hubModel)/sizeof(CsonModel));
printf("hub: id: %d, user: %s, project id: %d, project name: %s\r\n",
pHub->id, pHub->user, pHub->cson->id, pHub->cson->name);
/** 序列化对象 */
char *formatJson = csonEncodeFormatted(pHub, hubModel, sizeof(hubModel)/sizeof(CsonModel));
printf("format json: %s\r\n", formatJson);
/** 释放结构体对象 */
csonFree(pHub, hubModel, sizeof(hubModel)/sizeof(CsonModel));
/** 释放序列化生成的json字符串 */
csonFreeJson(formatJson);
}
```
运行结果:
```plain
hub: id: 1, user: Letter, project id: 2, project name: cson
format json: {
"id": 1,
"user": "Letter",
"cson": {
"id": 2,
"name": "cson"
}
}
```
可以看到无论是解析json还是序列化结构体到json在使用CSON的情况下都只需要一行代码就可以解决同样的操作在使用原生cJSON的情况下你可能需要多次判断解析元素
## 结构体数据类型
CSON采用数据模型对结构体进行解析在方便josn操作的同时也给结构体的定义带来了一些限制目前CSON所支持在结构体中定义的数据类型包括
1. 整数(char, short, int, long)
2. 浮点数(float, double)
3. 字符串(char *)
4. 基本类型数组(char[], short[], int[], long[], float[], double[], *char[])
5. 子结构体(指针形式)
6. 链表(CsonList)
其中为了方便解析CSON定义了一个专用的链表(CsonList)用于对json中复杂结构的数组映射
CSON支持的数据类型基本包括绝大多数使用场景对于一些之前就定义好的结构体可能需要稍微做一点修改
## 数据模型映射
CSON采用数据模型建立结构体同json之间的映射数据模型通过结构体数组进行定义数据模型定义如下
```C
/**
* @brief CSON数据模型定义
*
*/
typedef struct cson_model
{
CsonType type; /**< 数据类型 */
char *key; /**< 元素键值 */
short offset; /**< 元素偏移 */
union
{
struct
{
struct cson_model *model; /**< 子结构体模型 */
short size; /**< 子结构体模型大小 */
} sub; /**< 子结构体 */
struct
{
CsonType eleType; /**< 数组元素类型 */
short size; /**< 数组大小 */
} array; /**< 数组 */
int objSize; /**< 对象大小 */
CsonType basicListType; /**< 基础数据链表类型 */
} param;
} CsonModel;
```
对于每一个需要使用CSON的结构体都需要定义一个数据模型每一个数据模型都需要包含一条结构体描述`CSON_MODEL_OBJ(type)`以及若干个数据描述,取决于结构体的成员数量
一般情况下你只需要使用CSON提供的宏进行数据模型条目的定义数据模型宏与对应的数据类型对应如下
| 数据模型宏 | 数据类型 | 备注 |
| -------------------------------------------------- | -------- | -------------------------------------------------- |
| CSON_MODEL_OBJ(type) | 结构体 | 用于描述整个结构体,每一个数据模型都需要包含此条目 |
| CSON_MODEL_CHAR(type, key) | char | |
| CSON_MODEL_SHORT(type, key) | short | |
| CSON_MODEL_INT(type, key) | int | |
| CSON_MODEL_LONG(type, key) | long | |
| CSON_MODEL_FLOAT(type, key) | float | |
| CSON_MODEL_DOUBLE(type, key) | double | |
| CSON_MODEL_BOOL(type, key) | bool | C没有bool,对应为char |
| CSON_MODEL_STRING(type, key) | char * | |
| CSON_MODEL_STRUCT(type, key, submodel, subsize) | 子结构体 | 子结构体必须是结构体指针的形式 |
| CSON_MODEL_LIST(type, key, submodel, subsize) | CsonList | CSON定义的链表 |
| CSON_MODEL_ARRAY(type, key, elementType, arraySize | 数组 | 支持基本数据类型, 数组的每一个元素必须合法 |
## API
CSON源文件有完整的注释可以通过Doxygen等工具导出完整的API文档以下是几个关键API的说明
### 初始化
初始化CSON提供内存分配和内存释放函数对于标准C库可以使用`malloc`和`free`
```C
void csonInit(void *malloc, void *free)
```
- 参数
- `malloc` 内存分配函数
- `free` 内存释放函数
### 反序列化
解析json将json字符串反序列化成结构体对象
```C
void *csonDecodeObject(cJSON *json, CsonModel *model, int modelSize)
```
- 参数
- `json` json字符串
- `model` 描述目标结构体的数据模型
- `modelSize` 数据模型大小
- 返回
- `void *` 反序列化得到的结构体对象
### 序列化
编码结构体将结构体对象序列化成json字符串
```C
char* csonEncode(void *obj, CsonModel *model, int modelSize, int bufferSize, int fmt)
```
- 参数
- `obj` 源结构体对象
- `model` 描述源结构体的数据模型
- `modelSize` 数据模型大小
- `bufferSize` 可分配给json字符串的空间大小需要根据内容估计大小
- `fmt` 是否格式化json字符串
- 返回
- `char *` 序列化得到的json字符串
### 空间释放
CSON提供了两个释放内存的函数用于释放CSON生成的结构体对象和json字符串
#### 释放结构体对象
```C
void csonFree(void *obj, CsonModel *model, int modelSize)
```
- 参数
- `obj` 待释放的结构体对象
- `model` 待释放的结构体数据模型
- `modelSize` 待释放的结构体数据模型大小
#### 释放json字符串
```C
void csonFreeJson(const char *jsonStr)
```
- 参数
- `jsonStr` 待释放的json字符串
## 注意
- 数据模型根据结构体不同而不同,数据模型的数量=结构体成员数量+1多出来的一条是定义结构体`CSON_MODEL_OBJ(type)`
- 数组类型映射时会处理给进去的数组大小,所以请确保每一个数组元素都是合法的
- 基本数据类型链表采用类似子结构体的方式CSON默认定义了基本数据类型链表元素的数据模型通过类似`CSON_MODEL_LIST(struct test, strList, CSON_MODEL_STRING_LIST, CSON_BASIC_LIST_MODEL_SIZE)`进行定义即可

750
src/cJSON.c Normal file
View File

@ -0,0 +1,750 @@
/*
Copyright (c) 2009 Dave Gamble
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/* cJSON */
/* JSON parser in C. */
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <float.h>
#include <limits.h>
#include <ctype.h>
#include "cJSON.h"
static const char *ep;
const char *cJSON_GetErrorPtr(void) {return ep;}
static int cJSON_strcasecmp(const char *s1,const char *s2)
{
if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0;
return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
}
static void *(*cJSON_malloc)(size_t sz) = malloc;
static void (*cJSON_free)(void *ptr) = free;
static char* cJSON_strdup(const char* str)
{
size_t len;
char* copy;
len = strlen(str) + 1;
if (!(copy = (char*)cJSON_malloc(len))) return 0;
memcpy(copy,str,len);
return copy;
}
void cJSON_InitHooks(cJSON_Hooks* hooks)
{
if (!hooks) { /* Reset hooks */
cJSON_malloc = malloc;
cJSON_free = free;
return;
}
cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
cJSON_free = (hooks->free_fn)?hooks->free_fn:free;
}
/* Internal constructor. */
static cJSON *cJSON_New_Item(void)
{
cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
if (node) memset(node,0,sizeof(cJSON));
return node;
}
/* Delete a cJSON structure. */
void cJSON_Delete(cJSON *c)
{
cJSON *next;
while (c)
{
next=c->next;
if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string);
cJSON_free(c);
c=next;
}
}
/* Parse the input text to generate a number, and populate the result into item. */
static const char *parse_number(cJSON *item,const char *num)
{
double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;
if (*num=='-') sign=-1,num++; /* Has sign? */
if (*num=='0') num++; /* is zero */
if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */
if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */
if (*num=='e' || *num=='E') /* Exponent? */
{ num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */
while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */
}
n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */
item->valuedouble=n;
item->valueint=(int)n;
item->type=cJSON_Number;
return num;
}
static int pow2gt (int x) { --x; x|=x>>1; x|=x>>2; x|=x>>4; x|=x>>8; x|=x>>16; return x+1; }
typedef struct {char *buffer; int length; int offset; } printbuffer;
static char* ensure(printbuffer *p,int needed)
{
char *newbuffer;int newsize;
if (!p || !p->buffer) return 0;
needed+=p->offset;
if (needed<=p->length) return p->buffer+p->offset;
newsize=pow2gt(needed);
newbuffer=(char*)cJSON_malloc(newsize);
if (!newbuffer) {cJSON_free(p->buffer);p->length=0,p->buffer=0;return 0;}
if (newbuffer) memcpy(newbuffer,p->buffer,p->length);
cJSON_free(p->buffer);
p->length=newsize;
p->buffer=newbuffer;
return newbuffer+p->offset;
}
static int update(printbuffer *p)
{
char *str;
if (!p || !p->buffer) return 0;
str=p->buffer+p->offset;
return p->offset+strlen(str);
}
/* Render the number nicely from the given item into a string. */
static char *print_number(cJSON *item,printbuffer *p)
{
char *str=0;
double d=item->valuedouble;
if (d==0)
{
if (p) str=ensure(p,2);
else str=(char*)cJSON_malloc(2); /* special case for 0. */
if (str) strcpy(str,"0");
}
else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
{
if (p) str=ensure(p,21);
else str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */
if (str) sprintf(str,"%d",item->valueint);
}
else
{
if (p) str=ensure(p,64);
else str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */
if (str)
{
if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d);
else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d);
else sprintf(str,"%f",d);
}
}
return str;
}
static unsigned parse_hex4(const char *str)
{
unsigned h=0;
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;
h=h<<4;str++;
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;
h=h<<4;str++;
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;
h=h<<4;str++;
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;
return h;
}
/* Parse the input text into an unescaped cstring, and populate item. */
static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
static const char *parse_string(cJSON *item,const char *str)
{
const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;
if (*str!='\"') {ep=str;return 0;} /* not a string! */
while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */
out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */
if (!out) return 0;
ptr=str+1;ptr2=out;
while (*ptr!='\"' && *ptr)
{
if (*ptr!='\\') *ptr2++=*ptr++;
else
{
ptr++;
switch (*ptr)
{
case 'b': *ptr2++='\b'; break;
case 'f': *ptr2++='\f'; break;
case 'n': *ptr2++='\n'; break;
case 'r': *ptr2++='\r'; break;
case 't': *ptr2++='\t'; break;
case 'u': /* transcode utf16 to utf8. */
uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */
if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */
if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */
{
if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */
uc2=parse_hex4(ptr+3);ptr+=6;
if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */
uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
}
len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
switch (len) {
case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
case 1: *--ptr2 =(uc | firstByteMark[len]);
}
ptr2+=len;
break;
default: *ptr2++=*ptr; break;
}
ptr++;
}
}
*ptr2=0;
if (*ptr=='\"') ptr++;
item->valuestring=out;
item->type=cJSON_String;
return ptr;
}
/* Render the cstring provided to an escaped version that can be printed. */
static char *print_string_ptr(const char *str,printbuffer *p)
{
const char *ptr;char *ptr2,*out;int len=0,flag=0;unsigned char token;
for (ptr=str;*ptr;ptr++) flag|=((*ptr>0 && *ptr<32)||(*ptr=='\"')||(*ptr=='\\'))?1:0;
if (!flag)
{
len=ptr-str;
if (p) out=ensure(p,len+3);
else out=(char*)cJSON_malloc(len+3);
if (!out) return 0;
ptr2=out;*ptr2++='\"';
strcpy(ptr2,str);
ptr2[len]='\"';
ptr2[len+1]=0;
return out;
}
if (!str)
{
if (p) out=ensure(p,3);
else out=(char*)cJSON_malloc(3);
if (!out) return 0;
strcpy(out,"\"\"");
return out;
}
ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;}
if (p) out=ensure(p,len+3);
else out=(char*)cJSON_malloc(len+3);
if (!out) return 0;
ptr2=out;ptr=str;
*ptr2++='\"';
while (*ptr)
{
if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
else
{
*ptr2++='\\';
switch (token=*ptr++)
{
case '\\': *ptr2++='\\'; break;
case '\"': *ptr2++='\"'; break;
case '\b': *ptr2++='b'; break;
case '\f': *ptr2++='f'; break;
case '\n': *ptr2++='n'; break;
case '\r': *ptr2++='r'; break;
case '\t': *ptr2++='t'; break;
default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */
}
}
}
*ptr2++='\"';*ptr2++=0;
return out;
}
/* Invote print_string_ptr (which is useful) on an item. */
static char *print_string(cJSON *item,printbuffer *p) {return print_string_ptr(item->valuestring,p);}
/* Predeclare these prototypes. */
static const char *parse_value(cJSON *item,const char *value);
static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p);
static const char *parse_array(cJSON *item,const char *value);
static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p);
static const char *parse_object(cJSON *item,const char *value);
static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p);
/* Utility to jump whitespace and cr/lf */
static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}
/* Parse an object - create a new root, and populate. */
cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
{
const char *end=0;
cJSON *c=cJSON_New_Item();
ep=0;
if (!c) return 0; /* memory fail */
end=parse_value(c,skip(value));
if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */
/* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}}
if (return_parse_end) *return_parse_end=end;
return c;
}
/* Default options for cJSON_Parse */
cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);}
/* Render a cJSON item/entity/structure to text. */
char *cJSON_Print(cJSON *item) {return print_value(item,0,1,0);}
char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0,0);}
char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt)
{
printbuffer p;
p.buffer=(char*)cJSON_malloc(prebuffer);
p.length=prebuffer;
p.offset=0;
return print_value(item,0,fmt,&p);
return p.buffer;
}
/* Parser core - when encountering text, process appropriately. */
static const char *parse_value(cJSON *item,const char *value)
{
if (!value) return 0; /* Fail on null. */
if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; }
if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; }
if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; }
if (*value=='\"') { return parse_string(item,value); }
if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); }
if (*value=='[') { return parse_array(item,value); }
if (*value=='{') { return parse_object(item,value); }
ep=value;return 0; /* failure. */
}
/* Render a value to text. */
static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p)
{
char *out=0;
if (!item) return 0;
if (p)
{
switch ((item->type)&255)
{
case cJSON_NULL: {out=ensure(p,5); if (out) strcpy(out,"null"); break;}
case cJSON_False: {out=ensure(p,6); if (out) strcpy(out,"false"); break;}
case cJSON_True: {out=ensure(p,5); if (out) strcpy(out,"true"); break;}
case cJSON_Number: out=print_number(item,p);break;
case cJSON_String: out=print_string(item,p);break;
case cJSON_Array: out=print_array(item,depth,fmt,p);break;
case cJSON_Object: out=print_object(item,depth,fmt,p);break;
}
}
else
{
switch ((item->type)&255)
{
case cJSON_NULL: out=cJSON_strdup("null"); break;
case cJSON_False: out=cJSON_strdup("false");break;
case cJSON_True: out=cJSON_strdup("true"); break;
case cJSON_Number: out=print_number(item,0);break;
case cJSON_String: out=print_string(item,0);break;
case cJSON_Array: out=print_array(item,depth,fmt,0);break;
case cJSON_Object: out=print_object(item,depth,fmt,0);break;
}
}
return out;
}
/* Build an array from input text. */
static const char *parse_array(cJSON *item,const char *value)
{
cJSON *child;
if (*value!='[') {ep=value;return 0;} /* not an array! */
item->type=cJSON_Array;
value=skip(value+1);
if (*value==']') return value+1; /* empty array. */
item->child=child=cJSON_New_Item();
if (!item->child) return 0; /* memory fail */
value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */
if (!value) return 0;
while (*value==',')
{
cJSON *new_item;
if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
child->next=new_item;new_item->prev=child;child=new_item;
value=skip(parse_value(child,skip(value+1)));
if (!value) return 0; /* memory fail */
}
if (*value==']') return value+1; /* end of array */
ep=value;return 0; /* malformed. */
}
/* Render an array to text */
static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p)
{
char **entries;
char *out=0,*ptr,*ret;int len=5;
cJSON *child=item->child;
int numentries=0,i=0,fail=0;
size_t tmplen=0;
/* How many entries in the array? */
while (child) numentries++,child=child->next;
/* Explicitly handle numentries==0 */
if (!numentries)
{
if (p) out=ensure(p,3);
else out=(char*)cJSON_malloc(3);
if (out) strcpy(out,"[]");
return out;
}
if (p)
{
/* Compose the output array. */
i=p->offset;
ptr=ensure(p,1);if (!ptr) return 0; *ptr='['; p->offset++;
child=item->child;
while (child && !fail)
{
print_value(child,depth+1,fmt,p);
p->offset=update(p);
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;}
child=child->next;
}
ptr=ensure(p,2);if (!ptr) return 0; *ptr++=']';*ptr=0;
out=(p->buffer)+i;
}
else
{
/* Allocate an array to hold the values for each */
entries=(char**)cJSON_malloc(numentries*sizeof(char*));
if (!entries) return 0;
memset(entries,0,numentries*sizeof(char*));
/* Retrieve all the results: */
child=item->child;
while (child && !fail)
{
ret=print_value(child,depth+1,fmt,0);
entries[i++]=ret;
if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
child=child->next;
}
/* If we didn't fail, try to malloc the output string */
if (!fail) out=(char*)cJSON_malloc(len);
/* If that fails, we fail. */
if (!out) fail=1;
/* Handle failure. */
if (fail)
{
for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
cJSON_free(entries);
return 0;
}
/* Compose the output array. */
*out='[';
ptr=out+1;*ptr=0;
for (i=0;i<numentries;i++)
{
tmplen=strlen(entries[i]);memcpy(ptr,entries[i],tmplen);ptr+=tmplen;
if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}
cJSON_free(entries[i]);
}
cJSON_free(entries);
*ptr++=']';*ptr++=0;
}
return out;
}
/* Build an object from the text. */
static const char *parse_object(cJSON *item,const char *value)
{
cJSON *child;
if (*value!='{') {ep=value;return 0;} /* not an object! */
item->type=cJSON_Object;
value=skip(value+1);
if (*value=='}') return value+1; /* empty array. */
item->child=child=cJSON_New_Item();
if (!item->child) return 0;
value=skip(parse_string(child,skip(value)));
if (!value) return 0;
child->string=child->valuestring;child->valuestring=0;
if (*value!=':') {ep=value;return 0;} /* fail! */
value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
if (!value) return 0;
while (*value==',')
{
cJSON *new_item;
if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
child->next=new_item;new_item->prev=child;child=new_item;
value=skip(parse_string(child,skip(value+1)));
if (!value) return 0;
child->string=child->valuestring;child->valuestring=0;
if (*value!=':') {ep=value;return 0;} /* fail! */
value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
if (!value) return 0;
}
if (*value=='}') return value+1; /* end of array */
ep=value;return 0; /* malformed. */
}
/* Render an object to text. */
static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p)
{
char **entries=0,**names=0;
char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
cJSON *child=item->child;
int numentries=0,fail=0;
size_t tmplen=0;
/* Count the number of entries. */
while (child) numentries++,child=child->next;
/* Explicitly handle empty object case */
if (!numentries)
{
if (p) out=ensure(p,fmt?depth+4:3);
else out=(char*)cJSON_malloc(fmt?depth+4:3);
if (!out) return 0;
ptr=out;*ptr++='{';
if (fmt) {*ptr++='\n';for (i=0;i<depth-1;i++) *ptr++='\t';}
*ptr++='}';*ptr++=0;
return out;
}
if (p)
{
/* Compose the output: */
i=p->offset;
len=fmt?2:1; ptr=ensure(p,len+1); if (!ptr) return 0;
*ptr++='{'; if (fmt) *ptr++='\n'; *ptr=0; p->offset+=len;
child=item->child;depth++;
while (child)
{
if (fmt)
{
ptr=ensure(p,depth); if (!ptr) return 0;
for (j=0;j<depth;j++) *ptr++='\t';
p->offset+=depth;
}
print_string_ptr(child->string,p);
p->offset=update(p);
len=fmt?2:1;
ptr=ensure(p,len); if (!ptr) return 0;
*ptr++=':';if (fmt) *ptr++='\t';
p->offset+=len;
print_value(child,depth,fmt,p);
p->offset=update(p);
len=(fmt?1:0)+(child->next?1:0);
ptr=ensure(p,len+1); if (!ptr) return 0;
if (child->next) *ptr++=',';
if (fmt) *ptr++='\n';*ptr=0;
p->offset+=len;
child=child->next;
}
ptr=ensure(p,fmt?(depth+1):2); if (!ptr) return 0;
if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
*ptr++='}';*ptr=0;
out=(p->buffer)+i;
}
else
{
/* Allocate space for the names and the objects */
entries=(char**)cJSON_malloc(numentries*sizeof(char*));
if (!entries) return 0;
names=(char**)cJSON_malloc(numentries*sizeof(char*));
if (!names) {cJSON_free(entries);return 0;}
memset(entries,0,sizeof(char*)*numentries);
memset(names,0,sizeof(char*)*numentries);
/* Collect all the results into our arrays: */
child=item->child;depth++;if (fmt) len+=depth;
while (child)
{
names[i]=str=print_string_ptr(child->string,0);
entries[i++]=ret=print_value(child,depth,fmt,0);
if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
child=child->next;
}
/* Try to allocate the output string */
if (!fail) out=(char*)cJSON_malloc(len);
if (!out) fail=1;
/* Handle failure */
if (fail)
{
for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}
cJSON_free(names);cJSON_free(entries);
return 0;
}
/* Compose the output: */
*out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
for (i=0;i<numentries;i++)
{
if (fmt) for (j=0;j<depth;j++) *ptr++='\t';
tmplen=strlen(names[i]);memcpy(ptr,names[i],tmplen);ptr+=tmplen;
*ptr++=':';if (fmt) *ptr++='\t';
strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
if (i!=numentries-1) *ptr++=',';
if (fmt) *ptr++='\n';*ptr=0;
cJSON_free(names[i]);cJSON_free(entries[i]);
}
cJSON_free(names);cJSON_free(entries);
if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
*ptr++='}';*ptr++=0;
}
return out;
}
/* Get Array size/item / object item. */
int cJSON_GetArraySize(cJSON *array) {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;}
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
/* Utility for array list handling. */
static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
/* Utility for handling references. */
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;}
/* Add item to array/object. */
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);}}
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);}
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);}
void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));}
void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));}
cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0;
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;}
void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
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;}
void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
/* Replace array/object items with new ones. */
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;}
newitem->next=c;newitem->prev=c->prev;c->prev=newitem;if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;}
void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return;
newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem;
if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);}
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);}}
/* Create basic types: */
cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;}
cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;}
cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}
/* Create Arrays: */
cJSON *cJSON_CreateIntArray(const int *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;}
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;}
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;}
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;}
/* Duplication */
cJSON *cJSON_Duplicate(cJSON *item,int recurse)
{
cJSON *newitem,*cptr,*nptr=0,*newchild;
/* Bail on bad ptr */
if (!item) return 0;
/* Create new item */
newitem=cJSON_New_Item();
if (!newitem) return 0;
/* Copy over all vars */
newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble;
if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}}
if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}}
/* If non-recursive, then we're done! */
if (!recurse) return newitem;
/* Walk the ->next chain for the child. */
cptr=item->child;
while (cptr)
{
newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */
if (!newchild) {cJSON_Delete(newitem);return 0;}
if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */
else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */
cptr=cptr->next;
}
return newitem;
}
void cJSON_Minify(char *json)
{
char *into=json;
while (*json)
{
if (*json==' ') json++;
else if (*json=='\t') json++; /* Whitespace characters. */
else if (*json=='\r') json++;
else if (*json=='\n') json++;
else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; /* double-slash comments, to end of line. */
else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} /* multiline comments. */
else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} /* string literals, which are \" sensitive. */
else *into++=*json++; /* All other characters. */
}
*into=0; /* and null-terminate. */
}

149
src/cJSON.h Normal file
View File

@ -0,0 +1,149 @@
/*
Copyright (c) 2009 Dave Gamble
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef cJSON__h
#define cJSON__h
#ifdef __cplusplus
extern "C"
{
#endif
/* cJSON Types: */
#define cJSON_False 0
#define cJSON_True 1
#define cJSON_NULL 2
#define cJSON_Number 3
#define cJSON_String 4
#define cJSON_Array 5
#define cJSON_Object 6
#define cJSON_IsReference 256
#define cJSON_StringIsConst 512
/* The cJSON structure: */
typedef struct cJSON {
struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
int type; /* The type of the item, as above. */
char *valuestring; /* The item's string, if type==cJSON_String */
int valueint; /* The item's number, if type==cJSON_Number */
double valuedouble; /* The item's number, if type==cJSON_Number */
char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
} cJSON;
typedef struct cJSON_Hooks {
void *(*malloc_fn)(size_t sz);
void (*free_fn)(void *ptr);
} cJSON_Hooks;
/* Supply malloc, realloc and free functions to cJSON */
extern void cJSON_InitHooks(cJSON_Hooks* hooks);
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
extern cJSON *cJSON_Parse(const char *value);
/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
extern char *cJSON_Print(cJSON *item);
/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
extern char *cJSON_PrintUnformatted(cJSON *item);
/* 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 */
extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt);
/* Delete a cJSON entity and all subentities. */
extern void cJSON_Delete(cJSON *c);
/* Returns the number of items in an array (or object). */
extern int cJSON_GetArraySize(cJSON *array);
/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
/* Get item "string" from object. Case insensitive. */
extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
/* 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. */
extern const char *cJSON_GetErrorPtr(void);
/* These calls create a cJSON item of the appropriate type. */
extern cJSON *cJSON_CreateNull(void);
extern cJSON *cJSON_CreateTrue(void);
extern cJSON *cJSON_CreateFalse(void);
extern cJSON *cJSON_CreateBool(int b);
extern cJSON *cJSON_CreateNumber(double num);
extern cJSON *cJSON_CreateString(const char *string);
extern cJSON *cJSON_CreateArray(void);
extern cJSON *cJSON_CreateObject(void);
/* These utilities create an Array of count items. */
extern cJSON *cJSON_CreateIntArray(const int *numbers,int count);
extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count);
extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count);
extern cJSON *cJSON_CreateStringArray(const char **strings,int count);
/* Append item to the specified array/object. */
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
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 */
/* 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. */
extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
/* Remove/Detatch items from Arrays/Objects. */
extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
extern void cJSON_DeleteItemFromArray(cJSON *array,int which);
extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string);
/* Update array items. */
extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem); /* Shifts pre-existing items to the right. */
extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
/* Duplicate a cJSON item */
extern cJSON *cJSON_Duplicate(cJSON *item,int recurse);
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
need to be released. With recurse!=0, it will duplicate any children connected to the item.
The item->next and ->prev pointers are always zero on return from Duplicate. */
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);
extern void cJSON_Minify(char *json);
/* Macros for creating things quickly. */
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
#define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
#define cJSON_SetNumberValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
#ifdef __cplusplus
}
#endif
#endif

602
src/cson.c Normal file
View File

@ -0,0 +1,602 @@
/**
* @file cson.c
* @author Letter (NevermindZZT@gmail.cn)
* @brief cson
* @version 0.1
* @date 2019-08-26
*
* @copyright (c) 2019 Letter
*
*/
#include "cson.h"
#include "cJSON.h"
#include "stddef.h"
#include "string.h"
#include "stdio.h"
/**
* @brief
*
*/
CsonModel csonBasicListModel[] =
{
[0] = {CSON_TYPE_OBJ, NULL, 0, .param.objSize=sizeof(char)},
[1] = {CSON_TYPE_CHAR, NULL, 0},
[2] = {CSON_TYPE_OBJ, NULL, 0, .param.objSize=sizeof(short)},
[3] = {CSON_TYPE_SHORT, NULL, 0},
[4] = {CSON_TYPE_OBJ, NULL, 0, .param.objSize=sizeof(int)},
[5] = {CSON_TYPE_INT, NULL, 0},
[6] = {CSON_TYPE_OBJ, NULL, 0, .param.objSize=sizeof(long)},
[7] = {CSON_TYPE_LONG, NULL, 0},
[8] = {CSON_TYPE_OBJ, NULL, 0, .param.objSize=sizeof(float)},
[9] = {CSON_TYPE_FLOAT, NULL, 0},
[10] = {CSON_TYPE_OBJ, NULL, 0, .param.objSize=sizeof(double)},
[11] = {CSON_TYPE_DOUBLE, NULL, 0},
[12] = {CSON_TYPE_OBJ, NULL, 0, .param.objSize=sizeof(char *)},
[13] = {CSON_TYPE_STRING, NULL, 0},
};
/**
* @brief cson
*
*/
struct {
void *(*malloc)(int);
void (*free)(void *);
} cson;
/**
* @brief CSON初始化
*
* @param malloc
* @param free
*/
void csonInit(void *malloc, void *free)
{
cson.malloc = (void *(*)(int))malloc;
cson.free = (void (*)(void *))free;
cJSON_InitHooks(&(cJSON_Hooks){(void *(*)(size_t))cson.malloc, cson.free});
}
/**
* @brief JSON整型
*
* @param json JSON对象
* @param key key
* @return int
*/
int csonDecodeNumber(cJSON *json, char *key)
{
cJSON *item = key ? cJSON_GetObjectItem(json, key) : json;
if (item && item->type == cJSON_Number)
{
return item->valueint;
}
return 0;
}
/**
* @brief JSON浮点型
*
* @param json JSON对象
* @param key key
* @return double
*/
double csonDecodeDouble(cJSON *json, char *key)
{
cJSON *item = key ? cJSON_GetObjectItem(json, key) : json;
if (item && item->type == cJSON_Number)
{
return item->valuedouble;
}
return 0.0;
}
/**
* @brief JSON字符串数据
*
* @param json JSON对象
* @param key key
* @return char*
*/
char* csonDecodeString(cJSON *json, char *key)
{
char *p = NULL;
char *str = NULL;
short strLen = 0;
cJSON *item = key ? cJSON_GetObjectItem(json, key) : json;
if (item && item->type == cJSON_String)
{
str = item->valuestring;
if (item->valuestring)
{
strLen = strlen(str);
p = cson.malloc(strLen + 1);
if (p)
{
memcpy((void *)p, (void *)str, strLen);
*(p + strLen) = 0;
return p;
}
}
}
return NULL;
}
/**
* @brief JOSN布尔型数据
*
* @param json JSON对象
* @param key key
* @return char bool
*/
char csonDecodeBool(cJSON *json, char *key)
{
cJSON *item = cJSON_GetObjectItem(json, key);
if (item && item->type == cJSON_True)
{
return 1;
}
return 0;
}
/**
* @brief CsonList数据
*
* @param json JSON对象
* @param key key
* @param model CsonList成员数据模型
* @param modelSize SconList成员模型数量
* @return void* CsonList对象
*/
void *csonDecodeList(cJSON *json, char *key, CsonModel *model, int modelSize)
{
CsonList *list = NULL;
CsonList *node;
cJSON *array = cJSON_GetObjectItem(json, key);
if (array && array->type == cJSON_Array)
{
for (short i = 0; i < cJSON_GetArraySize(array); i++)
{
if (!list)
{
list = cson.malloc(sizeof(CsonList));
node = list;
}
else
{
node->next = cson.malloc(sizeof(CsonList));
node = node->next;
}
node->obj = csonDecodeObject(cJSON_GetArrayItem(array, i), model, modelSize);
node->next = NULL;
}
}
return list;
}
void csonDecodeArray(cJSON *json, char *key, void * base, CsonType elementType, short arraySize)
{
cJSON *array = cJSON_GetObjectItem(json, key);
cJSON *item;
char *str;
short strLen;
if (array && array->type == cJSON_Array)
{
for (short i = 0; i < cJSON_GetArraySize(array); i++)
{
item = cJSON_GetArrayItem(array, i);
switch (elementType)
{
case CSON_TYPE_CHAR:
*(char *)((int)base + (i * sizeof(char))) = (char)item->valueint;
break;
case CSON_TYPE_SHORT:
*(short *)((int)base + (i * sizeof(short))) = (short)item->valueint;
break;
case CSON_TYPE_INT:
*(int *)((int)base + (i * sizeof(int))) = (int)item->valueint;
break;
case CSON_TYPE_LONG:
*(long *)((int)base + (i * sizeof(long))) = (long)item->valueint;
break;
case CSON_TYPE_FLOAT:
*(float *)((int)base + (i * sizeof(float))) = (float)item->valuedouble;
break;
case CSON_TYPE_DOUBLE:
*(double *)((int)base + (i * sizeof(double))) = (double)item->valuedouble;
break;
case CSON_TYPE_STRING:
strLen = strlen(item->valuestring);
str = cson.malloc(strLen + 1);
memcpy(str, item->valuestring, strLen);
*(str + strLen) = 0;
*(int *)((int)base + (i * sizeof(int))) = (int)str;
break;
default:
break;
}
}
}
}
/**
* @brief JSON对象
*
* @param json JSON对象
* @param model
* @param modelSize
* @return void*
*/
void *csonDecodeObject(cJSON *json, CsonModel *model, int modelSize)
{
CSON_ASSERT(json, return NULL);
short objSize = 0;
for (short i = 0; i < modelSize; i++)
{
if (model[i].type == CSON_TYPE_OBJ)
{
objSize = model[i].param.objSize;
}
}
void *obj = cson.malloc(objSize);
CSON_ASSERT(obj, return NULL);
for (short i = 0; i < modelSize; i++)
{
switch (model[i].type)
{
case CSON_TYPE_CHAR:
*(char *)((int)obj + model[i].offset) = (char)csonDecodeNumber(json, model[i].key);
break;
case CSON_TYPE_SHORT:
*(short *)((int)obj + model[i].offset) = (short)csonDecodeNumber(json, model[i].key);
break;
case CSON_TYPE_INT:
*(int *)((int)obj + model[i].offset) = (int)csonDecodeNumber(json, model[i].key);
break;
case CSON_TYPE_LONG:
*(long *)((int)obj + model[i].offset) = (long)csonDecodeNumber(json, model[i].key);
break;
case CSON_TYPE_FLOAT:
*(float *)((int)obj + model[i].offset) = (float)csonDecodeDouble(json, model[i].key);
break;
case CSON_TYPE_DOUBLE:
*(double *)((int)obj + model[i].offset) = csonDecodeDouble(json, model[i].key);
break;
case CSON_TYPE_BOOL:
*(char *)((int)obj + model[i].offset) = (char)csonDecodeNumber(json, model[i].key);
break;
case CSON_TYPE_STRING:
*(int *)((int)obj + model[i].offset) = (int)csonDecodeString(json, model[i].key);
break;
case CSON_TYPE_LIST:
*(int *)((int)obj + model[i].offset) = (int)csonDecodeList(json,
model[i].key, model[i].param.sub.model, model[i].param.sub.size);
break;
case CSON_TYPE_STRUCT:
*(int *)((int)obj + model[i].offset) = (int)csonDecodeObject(
cJSON_GetObjectItem(json, model[i].key),
model[i].param.sub.model, model[i].param.sub.size);
break;
case CSON_TYPE_ARRAY:
csonDecodeArray(json, model[i].key, (void *)((int)obj + model[i].offset),
model[i].param.array.eleType, model[i].param.array.size);
break;
default:
break;
}
}
return obj;
}
/**
* @brief JSON字符串
*
* @param jsonStr json字符串
* @param model
* @param modelSize
* @return void*
*/
void *csonDecode(const char *jsonStr, CsonModel *model, int modelSize)
{
void *obj;
cJSON *json = cJSON_Parse(jsonStr);
CSON_ASSERT(json, return NULL);
obj = csonDecodeObject(json, model, modelSize);
cJSON_Delete(json);
return obj;
}
/**
* @brief JSON
*
* @param json json对象
* @param key key
* @param num
*/
void csonEncodeNumber(cJSON *json, char *key, double num)
{
if (key)
{
cJSON_AddNumberToObject(json, key, num);
}
else
{
json->type = cJSON_Number;
json->valuedouble = num;
json->valueint = (int)num;
}
}
/**
* @brief JSON
*
* @param json json对象
* @param key key
* @param str
*/
void csonEncodeString(cJSON *json, char *key, char *str)
{
if (key)
{
cJSON_AddStringToObject(json, key, str);
}
else
{
json->type = cJSON_String;
json->valuestring = str;
}
}
/**
* @brief CsonList编码成JSON对象
*
* @param list CsonList对象
* @param model
* @param modelSize
* @return cJSON* JOSN对象
*/
cJSON* csonEncodeList(CsonList *list, CsonModel *model, int modelSize)
{
cJSON *root = cJSON_CreateArray();
cJSON *item;
CsonList *p = list;
while (p)
{
if (p->obj)
{
item = csonEncodeObject(p->obj, model, modelSize);
cJSON_AddItemToArray(root, item);
}
p = p->next;
}
return root;
}
/**
* @brief JSON对象
*
* @param base
* @param elementType
* @param arraySize
* @return cJSON* JOSN对象
*/
cJSON* csonEncodeArray(void *base, CsonType elementType, short arraySize)
{
cJSON *root = cJSON_CreateArray();
cJSON *item;
for (short i = 0; i < arraySize; i++)
{
switch (elementType)
{
case CSON_TYPE_CHAR:
item = cJSON_CreateNumber(*(char *)((int)base + (i * sizeof(char))));
break;
case CSON_TYPE_SHORT:
item = cJSON_CreateNumber(*(short *)((int)base + (i * sizeof(short))));
break;
case CSON_TYPE_INT:
item = cJSON_CreateNumber(*(int *)((int)base + (i * sizeof(int))));
break;
case CSON_TYPE_LONG:
item = cJSON_CreateNumber(*(long *)((int)base + (i * sizeof(int))));
break;
case CSON_TYPE_FLOAT:
item = cJSON_CreateNumber(*(float *)((int)base + (i * sizeof(float))));
break;
case CSON_TYPE_DOUBLE:
item = cJSON_CreateNumber(*(double *)((int)base + (i * sizeof(double))));
break;
case CSON_TYPE_STRING:
item = cJSON_CreateString((char *)*(int *)((int)base + (i * sizeof(int))));
break;
default:
break;
}
cJSON_AddItemToArray(root, item);
}
return root;
}
/**
* @brief JSON对象
*
* @param obj
* @param model
* @param modelSize
* @return cJSON* JOSN对象
*/
cJSON* csonEncodeObject(void *obj, CsonModel *model, int modelSize)
{
CSON_ASSERT(obj, return NULL);
cJSON *root = cJSON_CreateObject();
for (short i = 0; i < modelSize; i++)
{
switch (model[i].type)
{
case CSON_TYPE_CHAR:
csonEncodeNumber(root, model[i].key, *(char *)((int)obj + model[i].offset));
// cJSON_AddNumberToObject(root, model[i].key, *(char *)((int)obj + model[i].offset));
break;
case CSON_TYPE_SHORT:
csonEncodeNumber(root, model[i].key, *(short *)((int)obj + model[i].offset));
break;
case CSON_TYPE_INT:
csonEncodeNumber(root, model[i].key, *(int *)((int)obj + model[i].offset));
break;
case CSON_TYPE_LONG:
csonEncodeNumber(root, model[i].key, *(long *)((int)obj + model[i].offset));
break;
case CSON_TYPE_FLOAT:
csonEncodeNumber(root, model[i].key, *(float *)((int)obj + model[i].offset));
break;
case CSON_TYPE_DOUBLE:
csonEncodeNumber(root, model[i].key, *(double *)((int)obj + model[i].offset));
break;
case CSON_TYPE_BOOL:
cJSON_AddBoolToObject(root, model[i].key, *(char *)((int)obj + model[i].offset));
break;
case CSON_TYPE_STRING:
csonEncodeString(root, model[i].key, (char *)(*(int *)((int)obj + model[i].offset)));
// cJSON_AddStringToObject(root, model[i].key, (char *)(*(int *)((int)obj + model[i].offset)));
break;
case CSON_TYPE_LIST:
cJSON_AddItemToObject(root, model[i].key,
csonEncodeList((CsonList *)*(int *)((int)obj + model[i].offset),
model[i].param.sub.model, model[i].param.sub.size));
break;
case CSON_TYPE_STRUCT:
cJSON_AddItemToObject(root, model[i].key, csonEncodeObject(
(void *)(*(int *)((int)obj + model[i].offset)),
model[i].param.sub.model, model[i].param.sub.size));
break;
case CSON_TYPE_ARRAY:
cJSON_AddItemToObject(root, model[i].key, csonEncodeArray(
(void *)((int)obj + model[i].offset),
model[i].param.array.eleType, model[i].param.array.size));
break;
default:
break;
}
}
return root;
}
/**
* @brief json字符串
*
* @param obj
* @param model
* @param modelSize
* @return char* josn字符串
*/
char* csonEncode(void *obj, CsonModel *model, int modelSize, int bufferSize, int fmt)
{
cJSON *json = csonEncodeObject(obj, model, modelSize);
CSON_ASSERT(json, return NULL);
char *jsonStr = cJSON_PrintBuffered(json, bufferSize, fmt);
cJSON_Delete(json);
return jsonStr;
}
/**
* @brief CSON解析出的对象
*
* @param obj
* @param model
* @param modelSize
*/
void csonFree(void *obj, CsonModel *model, int modelSize)
{
CsonList *list, *p;
for (short i = 0; i < modelSize; i++)
{
switch ((int)model[i].type)
{
case CSON_TYPE_CHAR:
case CSON_TYPE_SHORT:
case CSON_TYPE_INT:
case CSON_TYPE_LONG:
case CSON_TYPE_FLOAT:
case CSON_TYPE_DOUBLE:
break;
case CSON_TYPE_STRING:
cson.free((char *)(*(int *)((int)obj + model[i].offset)));
break;
case CSON_TYPE_LIST:
list = (CsonList *)*(int *)((int)obj + model[i].offset);
while (list)
{
p = list;
list = list->next;
if (p->obj)
{
csonFree(p->obj,
model[i].param.sub.model, model[i].param.sub.size);
}
cson.free(p);
}
break;
case CSON_TYPE_STRUCT:
csonFree((void *)(*(int *)((int)obj + model[i].offset)),
model[i].param.sub.model, model[i].param.sub.size);
break;
case CSON_TYPE_ARRAY:
if (model[i].param.array.eleType == CSON_TYPE_STRING)
{
for (short j = 0; j< model[i].param.array.size; j++)
{
if (*(int *)((int)obj + model[i].offset + (j << 2)))
{
cson.free((void *)*(int *)((int)obj + model[i].offset + (j << 2)));
}
}
}
break;
default:
break;
}
}
cson.free(obj);
}
/**
* @brief cson编码生成的json字符串
*
* @param jsonStr json字符串
*/
void csonFreeJson(const char *jsonStr)
{
CSON_ASSERT(jsonStr, return);
cson.free((void *)jsonStr);
}

318
src/cson.h Normal file
View File

@ -0,0 +1,318 @@
/**
* @file cson.h
* @author Letter (NevermindZZT@gmail.cn)
* @brief cson
* @version 0.1
* @date 2019-08-26
*
* @copyright (c) 2019 Letter
*
*/
#ifndef __CSON_H__
#define __CSON_H__
#include "stddef.h"
#include "cJSON.h"
#define CSON_VERSION "1.0.0" /**< CSON版本 */
/**
* @defgroup CSON cson
* @brief json tools for C
* @addtogroup CSON
* @{
*/
/**
* @brief CSON数据类型定义
*
*/
typedef enum
{
CSON_TYPE_OBJ = 0,
CSON_TYPE_CHAR,
CSON_TYPE_SHORT,
CSON_TYPE_INT,
CSON_TYPE_LONG,
CSON_TYPE_FLOAT,
CSON_TYPE_DOUBLE,
CSON_TYPE_BOOL,
CSON_TYPE_STRING,
CSON_TYPE_STRUCT,
CSON_TYPE_LIST,
CSON_TYPE_ARRAY,
} CsonType;
/**
* @brief CSON数据模型定义
*
*/
typedef struct cson_model
{
CsonType type; /**< 数据类型 */
char *key; /**< 元素键值 */
short offset; /**< 元素偏移 */
union
{
struct
{
struct cson_model *model; /**< 子结构体模型 */
short size; /**< 子结构体模型大小 */
} sub; /**< 子结构体 */
struct
{
CsonType eleType; /**< 数组元素类型 */
short size; /**< 数组大小 */
} array; /**< 数组 */
int objSize; /**< 对象大小 */
CsonType basicListType; /**< 基础数据链表类型 */
} param;
} CsonModel;
/**
* @brief Cson链表
*
*/
typedef struct cson_list
{
struct cson_list *next; /**< 下一个元素 */
void *obj; /**< 对象 */
} CsonList;
extern CsonModel csonBasicListModel[]; /**< 基础类型链表数据模型 */
#define CSON_MODEL_CHAR_LIST &csonBasicListModel[0] /**< char型链表数据模型 */
#define CSON_MODEL_SHORT_LIST &csonBasicListModel[2] /**< short型链表数据模型 */
#define CSON_MODEL_INT_LIST &csonBasicListModel[4] /**< int型链表数据模型 */
#define CSON_MODEL_LONG_LIST &csonBasicListModel[6] /**< long型链表数据模型 */
#define CSON_MODEL_FLOAT_LIST &csonBasicListModel[8] /**< float型链表数据模型 */
#define CSON_MODEL_DOUBLE_LIST &csonBasicListModel[10] /**< double型链表数据模型 */
#define CSON_MODEL_STRING_LIST &csonBasicListModel[12] /**< string型链表数据模型 */
#define CSON_BASIC_LIST_MODEL_SIZE 2 /**< 基础类型链表数据模型大小 */
/**
* @brief
*
* @param type
*/
#define CSON_MODEL_OBJ(type) \
{CSON_TYPE_OBJ, NULL, 0, .param.objSize=sizeof(type)}
/**
* @brief char型数据模型
*
* @param type
* @param key
*/
#define CSON_MODEL_CHAR(type, key) \
{CSON_TYPE_CHAR, #key, offsetof(type, key)}
/**
* @brief short型数据模型
*
* @param type
* @param key
*/
#define CSON_MODEL_SHORT(type, key) \
{CSON_TYPE_SHORT, #key, offsetof(type, key)}
/**
* @brief int型数据模型
*
* @param type
* @param key
*/
#define CSON_MODEL_INT(type, key) \
{CSON_TYPE_INT, #key, offsetof(type, key)}
/**
* @brief long型数据模型
*
* @param type
* @param key
*/
#define CSON_MODEL_LONG(type, key) \
{CSON_TYPE_LONG, #key, offsetof(type, key)}
/**
* @brief float型数据模型
*
* @param type
* @param key
*/
#define CSON_MODEL_FLOAT(type, key) \
{CSON_TYPE_FLOAT, #key, offsetof(type, key)}
/**
* @brief double型数据模型
*
* @param type
* @param key
*/
#define CSON_MODEL_DOUBLE(type, key) \
{CSON_TYPE_DOUBLE, #key, offsetof(type, key)}
/**
* @brief bool型数据模型
*
* @param type
* @param key
*/
#define CSON_MODEL_BOOL(type, key) \
{CSON_TYPE_CHAR, #key, offsetof(type, key)}
/**
* @brief
*
* @param type
* @param key
*/
#define CSON_MODEL_STRING(type, key) \
{CSON_TYPE_STRING, #key, offsetof(type, key)}
/**
* @brief
*
* @param type
* @param key
* @param submodel
* @param subsize
*/
#define CSON_MODEL_STRUCT(type, key, submodel, subsize) \
{CSON_TYPE_STRUCT, #key, offsetof(type, key), .param.sub.model=submodel, .param.sub.size=subsize}
/**
* @brief list型数据模型
*
* @param type
* @param key
* @param submodel
* @param subsize
*/
#define CSON_MODEL_LIST(type, key, submodel, subsize) \
{CSON_TYPE_LIST, #key, offsetof(type, key), .param.sub.model=submodel, .param.sub.size=subsize}
/**
* @brief list型数据模型
*
* @param type
* @param key
* @param elementType
* @param arraySize
*/
#define CSON_MODEL_ARRAY(type, key, elementType, arraySize) \
{CSON_TYPE_ARRAY, #key, offsetof(type, key), .param.array.eleType=elementType, .param.array.size=arraySize}
/**
* @brief CSON断言
*
* @param expr
* @param action
*/
#define CSON_ASSERT(expr, action) \
if (!(expr)) { \
printf(#expr " assert failed at file: %s, line: %d", __FILE__, __LINE__); \
action; \
}
/**
* @brief json字符串
*
* @param obj
* @param model
* @param modelSize
*
* @return char * josn字符串
*/
#define csonEncodeUnformatted(obj, model, modelSize) \
csonEncode(obj, model, modelSize, 256, 0)
/**
* @brief json字符串
*
* @param obj
* @param model
* @param modelSize
*
* @return char * josn字符串
*/
#define csonEncodeFormatted(obj, model, modelSize) \
csonEncode(obj, model, modelSize, 256, 1)
/**
* @brief CSON初始化
*
* @param malloc
* @param free
*/
void csonInit(void *malloc, void *free);
/**
* @brief JSON对象
*
* @param json JSON对象
* @param model
* @param modelSize
* @return void*
*/
void *csonDecodeObject(cJSON *json, CsonModel *model, int modelSize);
/**
* @brief JSON字符串
*
* @param jsonStr json字符串
* @param model
* @param modelSize
* @return void*
*/
void *csonDecode(const char *jsonStr, CsonModel *model, int modelSize);
/**
* @brief json字符串
*
* @param obj
* @param model
* @param modelSize
* @return char* josn字符串
*/
cJSON* csonEncodeObject(void *obj, CsonModel *model, int modelSize);
/**
* @brief json字符串
*
* @param obj
* @param model
* @param modelSize
* @return char* josn字符串
*/
char* csonEncode(void *obj, CsonModel *model, int modelSize, int bufferSize, int fmt);
/**
* @brief CSON解析出的对象
*
* @param obj
* @param model
* @param modelSize
*/
void csonFree(void *obj, CsonModel *model, int modelSize);
/**
* @brief cson编码生成的json字符串
*
* @param jsonStr json字符串
*/
void csonFreeJson(const char *jsonStr);
/**
* @}
*/
#endif