申请/释放空间
因为JSON对象与字符串需要在堆上申请/释放空间,故定义2个函数指针变量来存在函数地址。
static void* (*JSON_malloc)(size_t _Size);
static void (*JSON_free)(void* _Block);
通过调用JSONInit()函数来初始化这两个函数指针
void JSONInit(void* (*JSONmalloc)(size_t _Size), void (*JSONfree)(void* _Block))
{
JSON_malloc = JSONmalloc;
JSON_free = JSONfree;
}
解码
因为功能函数过多,这里仅介绍几个重要的函数。
解码JSON
传入需要解码的JSON字符串,与对应的数据模型,即可解码。
- 检查参数
- 检查申请/释放空间函数指针是否已经赋值
- 根对象是否为空
- 调用解析对象功能函数开始解析JSON字符串
void* DecodeJSON(char* jsonStr, PJSON_MODEL_t model, unsigned int modelCount, char removeInvalidChars)
{
void* root = NULL;
JSONErrorCode = JSON_SUCCESS;
if (jsonStr == NULL || model == NULL || modelCount == 0)
{
JSONErrorCode = PARAM_IS_EMPTY;
return NULL;
}
if (JSON_malloc == NULL || JSON_free == NULL)
{
JSONErrorCode = JSON_NOT_INIT;
return NULL;
}
if (removeInvalidChars)
{
strTrim(jsonStr);
}
#if (JSON_DEBUG == 1)
printf("解码的JSON字符串长度为:%zu\n", strlen(jsonStr));
printf("解码的JSON字符串为:%s\n", jsonStr);
#endif
if (*(jsonStr + 1) == '}')
{
JSONErrorCode = DECODE_ROOT_OBJECT_NULL;
return NULL;
}
root = DecodeObject(jsonStr, model, modelCount);
return root;
}
解析对象
- 检查函数参数
- 检查对象为空
- 获取根对象占用的字节大小
- 为对象申请空间
- 变量对象的数据模型,依次解析JSON字符串
- 检查错误代码,出错则释放对象,函数返回NULL
static void* DecodeObject(const char* jsonStr, PJSON_MODEL_t model, unsigned int modelCount)
{
void* obj = NULL;
unsigned short objectSize = 0;
const char* value = jsonStr;
const char* nextValue = NULL;
if (jsonStr == NULL || model == NULL || modelCount == 0)
{
JSONErrorCode = PARAM_IS_EMPTY;
return NULL;
}
if (*(value + 1) == '\0')
{
JSONErrorCode = DECODE_OBJECT_IS_EMPTY;
return NULL;
}
value++;
nextValue = value;
for (unsigned i = 0; i < modelCount; i++)
{
if (model[i].type == JSON_TYPE_OBJECT)
{
objectSize = model[i].value.objectSize;
break;
}
}
obj = JSON_malloc(objectSize);
if (obj == NULL)
{
JSONErrorCode = DECODE_OBJECT_FAIL_1;
return NULL;
}
memset(obj, 0, objectSize);
#if (JSON_DEBUG == 1)
printf("对象申请空间%p\n", obj);
#endif
for (unsigned int i = 1; i < modelCount; i++)
{
if ((model[i].type == JSON_TYPE_OBJECT || model[i].type == JSON_TYPE_ARRAY))
{
value = JSONSkipChildJsonStr((char**)&nextValue, model[i].type);
if (value == NULL)
{
JSONErrorCode = NOU_FIND_CHILD_ARRAY_OBJECT_END;
}
}
else
{
value = strtok_s(NULL, ",", (char**)&nextValue);
}
switch (model[i].type)
{
case JSON_TYPE_BOOL:
*(JSON_BOOL_t*)((char*)obj + model[i].offset) = DecodeBool(value, &model[i], 1);
break;
case JSON_TYPE_CHAR:
*(char*)((char*)obj + model[i].offset) = (char)DecodeNumberOrDouble(value, &model[i], 1);
break;
case JSON_TYPE_SHORT:
*(short*)((char*)obj + model[i].offset) = (short)DecodeNumberOrDouble(value, &model[i], 1);
break;
case JSON_TYPE_INT:
*(int*)((char*)obj + model[i].offset) = (int)DecodeNumberOrDouble(value, &model[i], 1);
break;
case JSON_TYPE_UCHAR:
*(unsigned char*)((char*)obj + model[i].offset) = (unsigned char)DecodeNumberOrDouble(value, &model[i], 1);
break;
case JSON_TYPE_USHORT:
*(unsigned short*)((char*)obj + model[i].offset) = (unsigned short)DecodeNumberOrDouble(value, &model[i], 1);
break;
case JSON_TYPE_UINT:
*(unsigned int*)((char*)obj + model[i].offset) = (unsigned int)DecodeNumberOrDouble(value, &model[i], 1);
break;
case JSON_TYPE_FLOAT:
*(float*)((char*)obj + model[i].offset) = (float)DecodeNumberOrDouble(value, &model[i], 1);
break;
case JSON_TYPE_DOUBLE:
*(double*)((char*)obj + model[i].offset) = (double)DecodeNumberOrDouble(value, &model[i], 1);
break;
case JSON_TYPE_STRING:
*(char**)((char*)obj + model[i].offset) = DecodeString(value, &model[i], 1);
break;
case JSON_TYPE_OBJECT:
value = CheckKeyName(value, &model[i]);
if (value == NULL)
{
JSONErrorCode = DECODE_OBJECT_FAIL;
FreeJSONObject(obj, model, modelCount);
return NULL;
}
void* childObj = NULL;
childObj = DecodeObject(value, model[i].value.child.model, model[i].value.child.count);
if (childObj == NULL)
{
if (JSONErrorCode == DECODE_OBJECT_IS_EMPTY)
{
JSONErrorCode = JSON_SUCCESS;
}
else
{
JSONErrorCode = DECODE_OBJECT_FAIL_2;
return NULL;
}
}
*(char**)((char*)obj + model[i].offset) = childObj;
break;
case JSON_TYPE_ARRAY:
DecodeArray(value, &model[i], (char*)obj + model[i].offset, 1);
if (JSONErrorCode == DECODE_ARRAY_IS_EMPTY)
{
JSONErrorCode = JSON_SUCCESS;
}
break;
default:
break;
}
if (JSONErrorCode != JSON_SUCCESS)
{
FreeJSONObject(obj, model, modelCount);
return NULL;
}
}
return obj;
}
解析实数
- 检查字符串是否可读
- 转换实数
static double DecodeNumberOrDouble(const char* jsonStr, PJSON_MODEL_t model, char decodeKeyName)
{
double d = 0.0;
const char* value = jsonStr;
const char* endStr = NULL;
if (value == NULL)
{
return 0.0;
}
if (decodeKeyName)
{
value = CheckKeyName(jsonStr, model);
if (value == NULL)
{
JSONErrorCode = DECODE_NUMBER_DOUBLE_FAIL;
return 0.0;
}
}
d = strtod(value, (char**)&endStr);
if (*endStr != 'n' && *endStr != '\0' && *endStr != '}')
{
JSONErrorCode = DECODE_NUMBER_DOUBLE_FAIL;
}
return d;
}
释放对象
- 遍历对象的数据模型
- 如果是实数类型,则继续
- 字符串类型则释放空间
- 对象类型则递归调用此函数
- 数组类型则根据数组元素类型来释放空间
void FreeJSONObject(void* obj, PJSON_MODEL_t model, unsigned int modelCount)
{
void* addr = NULL;
if (obj == NULL || model == NULL || modelCount == 0)
{
JSONErrorCode = PARAM_IS_EMPTY;
return;
}
if (JSON_malloc == NULL || JSON_free == NULL)
{
JSONErrorCode = JSON_NOT_INIT;
return;
}
for (unsigned int i = 0; i < modelCount; i++)
{
switch (model[i].type)
{
case JSON_TYPE_BOOL:
case JSON_TYPE_CHAR:
case JSON_TYPE_SHORT:
case JSON_TYPE_INT:
case JSON_TYPE_UCHAR:
case JSON_TYPE_USHORT:
case JSON_TYPE_UINT:
case JSON_TYPE_FLOAT:
case JSON_TYPE_DOUBLE:
break;
case JSON_TYPE_STRING:
addr = *(char**)((char*)obj + model[i].offset);
if (addr)
{
#if (JSON_DEBUG == 1)
printf("释放字符串%p %s\n", addr, addr);
#endif
JSON_free(addr);
}
break;
case JSON_TYPE_OBJECT:
if (model[i].keyName == NULL)
{
continue;
}
addr = *(char**)((char*)obj + model[i].offset);
if (addr)
{
FreeJSONObject(addr, model[i].value.child.model, model[i].value.child.count);
}
break;
case JSON_TYPE_ARRAY:
switch (model[i].value.array.type)
{
case JSON_TYPE_BOOL:
case JSON_TYPE_CHAR:
case JSON_TYPE_SHORT:
case JSON_TYPE_INT:
case JSON_TYPE_UCHAR:
case JSON_TYPE_USHORT:
case JSON_TYPE_UINT:
case JSON_TYPE_FLOAT:
case JSON_TYPE_DOUBLE:
break;
case JSON_TYPE_STRING:
for (unsigned int j = 0; j < model[i].value.array.count; j++)
{
addr = *(char**)((char*)obj + model[i].offset + j * model[i].value.array.size);
if (addr)
{
#if (JSON_DEBUG == 1)
printf("释放字符串%p %s\n", addr, addr);
#endif
JSON_free(addr);
}
}
break;
case JSON_TYPE_OBJECT:
for (unsigned int j = 0; j < model[i].value.array.count; j++)
{
addr = *(char**)((char*)obj + model[i].offset + j * model[i].value.array.size);
if (addr)
{
FreeJSONObject(addr, model[i].value.array.child.model, model[i].value.array.child.count);
}
}
break;
default:
break;
}
break;
default:
break;
}
}
#if (JSON_DEBUG == 1)
printf("释放对象%p\n", obj);
#endif
JSON_free(obj);
}
编码
JSON编码
- 先计算根对象需要的内存空间大小
- 调用编码对象功能函数编码JSON字符串
char* EncodeJSON(void* obj, PJSON_MODEL_t model, unsigned int modelCount)
{
char* encodeJSONStr = NULL;
char* str = NULL;
BYTES_t bytes = 0;
JSONErrorCode = JSON_SUCCESS;
if (obj == NULL || model == NULL || modelCount == 0)
{
JSONErrorCode = PARAM_IS_EMPTY;
return NULL;
}
if (JSON_malloc == NULL || JSON_free == NULL)
{
JSONErrorCode = JSON_NOT_INIT;
return;
}
bytes = GetObjectNeedBytes(obj, model, modelCount);
if (bytes == 0)
{
return NULL;
}
#if (JSON_DEBUG == 1)
printf("编码的JSON字符串长度为%u\n", bytes);
#endif
bytes++;
encodeJSONStr = JSON_malloc(bytes);
if (encodeJSONStr == NULL)
{
JSONErrorCode = ENCODE_FAIL;
return NULL;
}
memset(encodeJSONStr, 0, bytes);
#if (JSON_DEBUG == 1)
printf("编码的JSON字符串长度申请空间%p\n", encodeJSONStr);
#endif
str = encodeJSONStr;
str = EncodeObject(obj, model, modelCount, str);
*str = '\0';
#if (JSON_DEBUG == 1)
printf("编码的JSON字符串为%s\n", encodeJSONStr);
#endif
return encodeJSONStr;
}
demo
JSON字符串如下
{
"id": "0011223344",
"name": "张三",
"phone": "111-22223333",
"addr": "天安门广场",
"grade": "小学四年级",
"score": {
"math": 99.5,
"chinese": 85.5,
"english": 86,
"science": 86.5,
"history": 92
}
}
对应的结构体定义如下
typedef struct score
{
float math;
float chinese;
float english;
float science;
float history;
}score_t, * Pscore_t;
typedef struct stu
{
char* id;
char* name;
char* phone;
char* addr;
char* grade;
Pscore_t score;
}stu_t, * Pstu_t;
相应的数据模型
JSON_MODEL_t scoreModel[] =
{
JSON_ROOT_OBJECT(score_t),
JSON_FLOAT(score_t, math),
JSON_FLOAT(score_t, chinese),
JSON_FLOAT(score_t, english),
JSON_FLOAT(score_t, science),
JSON_FLOAT(score_t, history)
};
JSON_MODEL_t stuModel[] =
{
JSON_ROOT_OBJECT(stu_t),
JSON_STRING(stu_t, id),
JSON_STRING(stu_t, name),
JSON_STRING(stu_t, phone),
JSON_STRING(stu_t, addr),
JSON_STRING(stu_t, grade),
JSON_OBJECT(stu_t, score, scoreModel, sizeof(scoreModel) / sizeof(JSON_MODEL_t))
};
解码/编码
JSONInit(malloc, free);
char jsonStr[] = "\
{\
\"id\": \"0011223344\",\
\"name\" : \"张三\",\
\"phone\" : \"111-22223333\",\
\"addr\" : \"天安门广场\",\
\"grade\" : \"小学四年级\",\
\"score\" : {\
\"math\": 99.5,\
\"chinese\" : 85.5,\
\"english\" : 86,\
\"science\" : 86.5,\
\"history\" : 92\
}\
}\
";
Pstu_t stu = DecodeJSON(jsonStr, stuModel, sizeof(stuModel) / sizeof(JSON_MODEL_t), 1);
if (stu == NULL)
{
printf("stu解码失败 errorCode = %d\n", JSONErrorCode);
return;
}
if (stu->id == NULL)
{
printf("学号为空\n");
}
else
{
printf("学号为%s\n", stu->id);
}
if (stu->name == NULL)
{
printf("姓名为空\n");
}
else
{
printf("姓名为%s\n", stu->name);
}
if (stu->phone == NULL)
{
printf("手机号为空\n");
}
else
{
printf("手机号为%s\n", stu->phone);
}
if (stu->addr == NULL)
{
printf("住址为空\n");
}
else
{
printf("住址为%s\n", stu->addr);
}
if (stu->grade == NULL)
{
printf("年级为空\n");
}
else
{
printf("年级为%s\n", stu->grade);
}
if (stu->score == NULL)
{
printf("成绩为空\n");
}
else
{
printf("数学:%.2f 语文:%.2f 英语:%.2f 科学:%.2f 历史:%.2f\n",
stu->score->math, stu->score->chinese, stu->score->english, stu->score->science, stu->score->history);
}
printf("\n\n");
char* str = EncodeJSON(stu, stuModel, sizeof(stuModel) / sizeof(JSON_MODEL_t));
if (str == NULL)
{
printf("编码失败\n");
return;
}
printf("%s\n", str);
FreeJSONString(str);
FreeJSONObject(stu, stuModel, sizeof(stuModel) / sizeof(JSON_MODEL_t));
输出结果
C语言实现JSON字符串解码与编码(一)大致思路
C语言实现JSON字符串解码与编码(二)头文件介绍
C语言实现JSON字符串解码与编码(三)源代码
源代码下载链接
|