print_array
/* 功 能:将cjson数组结构体转换为字符串格式 参 数:item数组结构体指针 depth-深度 fmt-调整格式 p-输出缓冲结构体指针 返回值: */ static char* print_array(cJSON* item, int depth, int fmt, printbuffer* p) { char** entries;// 保存一个数组的地址。该数组是指针数组。 char* out = NULL; char* ptr = NULL; char* ret = NULL; int len = 5; cJSON* child = item->child; int numentries = 0;// 数组元素个数 int i = 0; // 循环计数器 int fail = 0; // 处理出错标志 size_t tmplen = 0; /* 计算数组元素个数 */ while (NULL != child) { numentries++; child = child->next; } /* 显现的处理元素个数为0时 */ if (0 == numentries) { if (NULL != p) out = ensure(p, 3); else out = (char*)cJSON_malloc(3); if (NULL != out) strcpy(out, "[]"); return out; } if (NULL != p) { /* 组成输出数组 */ i = p->offset; ptr = ensure(p, 1); if (NULL == ptr) return NULL; *ptr = '['; p->offset++; child = item->child; while (NULL != child && 0 == fail) { print_value(child, depth + 1, fmt, p); p->offset = update(p); if (NULL != child->next) { len = fmt ? 2 : 1; ptr = ensure(p, len + 1); if (NULL == ptr) return NULL; *ptr++ = ','; if (0 != 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 { /* 分配一个指针数组来保存每个元素的指针*/ entries = (char**)cJSON_malloc(numentries * sizeof(char*)); if (NULL == entries)// 内存申请失败 return 0; memset(entries, 0, numentries * sizeof(char*));// 初始化内存 /* 检索所有结果: */ child = item->child; while (NULL != child && 0 == fail) { ret = print_value(child, depth + 1, fmt, 0); entries[i++] = ret; if (NULL != ret) len += strlen(ret) + 2 + (fmt ? 1 : 0); else fail = 1;// 结束标记 child = child->next;// 指向它的兄弟节点 } /* 如果没有失败,尝试malloc输出字符串 */ if (0 == fail) out = (char*)cJSON_malloc(len); if (NULL == out) fail = 1; if (0 != fail) { for (i = 0; i < numentries; i++) { if (entries[i]) cJSON_free(entries[i]); } cJSON_free(entries); return NULL; } *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 (0 != fmt) *ptr++ = ' '; *ptr = '\0'; } cJSON_free(entries[i]); } cJSON_free(entries); *ptr++ = ']'; *ptr++ = '\0'; } return out; }
parse_object
/* 功 能:从文本构建一个对象(就是{....}包含的) 参 数:item-结构体 value-字符串指针 返回值:字符串新的指针 */ static const char* parse_object(cJSON* item, const char* value) { cJSON* child = NULL; if ('{' != *value) // 不是对象 { ep = value; // 将后面不能解析的字符串给到ep return NULL; } item->type = cJSON_Object; // 设置类型 value = skip(value + 1); // 从{后面开始跳过控制字符和空格 if ('}' == *value) // 空对象 { return value + 1; } child = cJSON_New_Item(); // 确定{}中间有数据,就申请空间 if (NULL == child) // 申请空间失败 { return NULL; } item->child = child; // 连接当前节点 // 先将指针跳过控制字符和空格,然后将字符串放入堆区, // 最后再将指针跳过控制字符和空格 value = skip(parse_string(child, skip(value))); if ('\0' == value) // 指针走到头了 { return NULL; } child->string = child->valuestring; // 将key存入string中, child->valuestring = '\0'; if (':' != *value) // 没找到":" { ep = value; return NULL; } // 先将指针跳过控制字符和空格,然后将接下来字符串指针找匹配的函数, // 然后将其放入孩纸结构体中,最后再将指针跳过控制字符和空格 value = skip(parse_value(child, skip(value + 1))); if ('\0' == value) // 指针走到头了 { return NULL; } while (',' == *value) // 还有,表示还有数据 { cJSON* new_item; new_item = cJSON_New_Item(); if (NULL == new_item) // 申请空间失败 { return NULL; } // 将兄弟节点连接起来 child->next = new_item; new_item->prev = child; child = new_item; // 更新节点指针 // 先将指针跳过控制字符和空格,然后将接下来字符串拷贝到堆区 // 最后再将指针跳过控制字符和空格 value = skip(parse_string(child, skip(value + 1))); if ('\0' == value) // 字符串指针遇到'\0' { return NULL; } child->string = child->valuestring;// 将key放入string中 child->valuestring = '\0'; if (':' != *value) // 未找到":" { ep = value; return NULL; } // 先将指针跳过控制字符和空格,然后将接下来对字符串做相应处理 // 最后再将指针跳过控制字符和空格 value = skip(parse_value(child, skip(value + 1))); if (value == NULL) return NULL; } if ('}' == *value) // {}结束标记 { return value + 1; } ep = value; // 匹配到'}' 发生错误 return NULL; }
print_object
/* 功 能:将对象结构体转换为字符串存储在输出缓冲区中 参 数:item-对象 depth-深度 fmt-输出格式(1-有换行符 0-无) p-输出缓冲结构体指针 返回值:返回字符串在堆区起始地址 */ static char* print_object(cJSON* item, int depth, int fmt, printbuffer* p) { char** entries = NULL; // 保存item中元素的value在输出缓冲区的地址 char** names = NULL; // 保存item中元素的key在输出缓冲区的地址 char* out = NULL; // 保存item转换为文本在堆区的位置 char* ptr = NULL; char* ret = NULL; char* str = NULL; int len = 7; // 字符串的长度 最少 "","" 7个字节 int i = 0, j = 0; // 循环计数器 cJSON* child = item->child; // 指向item的第一个儿子 int numentries = 0; // 保存对象中对的个数 int fail = 0; // 保存到输出缓冲区的出错标志 size_t tmplen = 0; while (NULL != child) // 计算有多少对元素 { numentries++; child = child->next; } if (0 == numentries) // 键值对的个数为0 { if (NULL != p) // 输出缓冲结构体指针不为NULL { // 判断当前偏移量下比较len+3(因为需要放俩个""和一个\0)长度的字符是否越界并作出保护措施 out = ensure(p, fmt ? depth + 4 : 3); } else { out = (char*)cJSON_malloc(fmt ? depth + 4 : 3); } if (NULL == out) // 申请空间失败 { return 0; } ptr = out; *ptr++ = '{'; // 大括号开 if (0 != fmt) { *ptr++ = '\n'; for (i = 0; i < depth - 1; i++) *ptr++ = '\t'; } *ptr++ = '}'; // 大括号闭 *ptr++ = '\0'; return out; } if (NULL != p) // 输出缓冲结构体指针不为NULL { /* 组成的输出: */ i = p->offset; len = fmt ? 2 : 1; // 有换行符多一个字符"\n\0" // 判断当前偏移量下比较len+1(有换行符三个字节,无换行符俩个字节)长度的字符是否越界并作出保护措施 ptr = ensure(p, len + 1); if (NULL == ptr) // 地址无效 return NULL; *ptr++ = '{'; // 大括号开 if (1 == fmt) // 判断有无换行符 *ptr++ = '\n'; *ptr = '\0'; p->offset += len; // 输出缓冲结构体的偏移量更新 child = item->child; // 指向下一个儿子 depth++; // 深度+1 while (NULL != child) { if (1 == fmt) // 有换行符 { ptr = ensure(p, depth); // 安全检查 if (NULL == ptr) // 指针无效 return NULL; 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 (NULL == ptr) // 指针无效 return NULL; *ptr++ = ':'; if (1 == fmt) *ptr++ = '\t'; p->offset += len; // 更新输出缓冲结构体指针偏移量 print_value(child, depth, fmt, p);// 将json结构体转换为字符串。 p->offset = update(p); // 获取缓冲区的字符串长度 len = (fmt ? 1 : 0) + (child->next ? 1 : 0); ptr = ensure(p, len + 1); // 安全检查 if (NULL == ptr) // 指针无效 return NULL; if (NULL != child->next) // 判断还有无元素(节点) *ptr++ = ','; if (1 == fmt) *ptr++ = '\n'; *ptr = '\0'; p->offset += len; // 更新输出缓冲结构体指针偏移量 child = child->next; // 继续下一个节点 } ptr = ensure(p, fmt ? (depth + 1) : 2); // 安全检查 考虑了换行符和tab if (NULL == ptr) // 指针无效 return 0; if (1 == fmt) { for (i = 0; i < depth - 1; i++) // 深度 *ptr++ = '\t'; } *ptr++ = '}'; *ptr = '\0'; out = (p->buffer) + i; } else // 输出缓冲结构体指针不为NULL { entries = (char**)cJSON_malloc(numentries * sizeof(char*)); // 给value申请空间 if (NULL == entries) // 申请空间失败 { return NULL; } names = (char**)cJSON_malloc(numentries * sizeof(char*)); // 给key申请空间 if (NULL == names) // 申请空间失败 { cJSON_free(entries); // 释放前面申请成功的空间 return NULL; } memset(entries, 0, sizeof(char*) * numentries); // 给value空间初始化 memset(names, 0, sizeof(char*) * numentries); // 给key空间初始化 /* 将所有结果收集到我们的数组中: */ child = item->child; // 指向数组第一个元素 depth++; // 深度增加 \t if (0 != fmt) len += depth; while (NULL != child) { names[i] = str = print_string_ptr(child->string, 0); // 返回该元素key字符串在输出缓冲区的起始位置 entries[i++] = ret = print_value(child, depth, fmt, 0); // 返回该元素value字符串在输出缓冲区的起始位置 if (NULL != str && NULL != ret) { // fmt为换行符 depth为深度\t 深度可叠加 但是换行符最多有一个 // key为一个字符串 value为一个字符串 所以会多出来俩个\0 因为strlen不算\0 len += strlen(ret) + strlen(str) + 2 + (fmt ? 2 + depth : 0); } else // 出错了 { fail = 1; } child = child->next; // 处理下一个元素(下一个节点) } /* 尝试分配输出字符串 */ if (0 == fail) out = (char*)cJSON_malloc(len); if (NULL == out) // 申请失败 fail = 1; /* 处理失败 */ if (1 == fail) { for (i = 0; i < numentries; i++) // 将俩个数组中保存堆区开辟的空间依次释放掉 { if (NULL != names[i]) cJSON_free(names[i]); if (NULL != entries[i]) cJSON_free(entries[i]); } cJSON_free(names); cJSON_free(entries); return NULL; } /* 组成的输出: */ *out = '{'; // 存入大括开 ptr = out + 1; // 指向未填充的地址 if (1 == fmt) // 有换行符 *ptr++ = '\n'; *ptr = '\0'; for (i = 0; i < numentries; i++) { if (1 == fmt) { for (j = 0; j < depth; j++) // 深度 *ptr++ = '\t'; } tmplen = strlen(names[i]); // 计算当前key字符串的长度 memcpy(ptr, names[i], tmplen); // 拷贝 ptr += tmplen; // 指针更新 *ptr++ = ':'; if (1 == fmt) *ptr++ = '\t'; strcpy(ptr, entries[i]); // 拷贝当前value字符串 ptr += strlen(entries[i]); // 指针更新 if (i != numentries - 1) *ptr++ = ','; if (1 == fmt) *ptr++ = '\n'; *ptr = '\0'; cJSON_free(names[i]); // 释放掉当前键值对所占的内存 cJSON_free(entries[i]); } cJSON_free(names); cJSON_free(entries); if (1 == fmt) // 格式操作 { for (i = 0; i < depth - 1; i++) *ptr++ = '\t'; } *ptr++ = '}'; // 大括号闭 *ptr++ = '\0'; } return out; // 返回字符串在堆区起始地址 }
cJSON_GetArraySize
/* 获取数组大小/对象个数 */ int cJSON_GetArraySize(cJSON* array) { cJSON* c = array->child; // 指向第一个儿子 int i = 0; while (NULL != c) { i++; c = c->next; } return i; }
cJSON_GetArrayItem
/* 查找数组结构体第item(从0开始)个子结构体的地址并返回 */ cJSON* cJSON_GetArrayItem(cJSON* array, int item) { cJSON* c = array->child; while (NULL != c && item > 0) { item--; c = c->next; } return c; }
cJSON_GetObjectItem
/* 查找对象结构体中key为string的子结构体的地址并返回 */ cJSON* cJSON_GetObjectItem(cJSON* object, const char* string) { cJSON* c = object->child; while (NULL != c && 0 != cJSON_strcasecmp(c->string, string)) { c = c->next; } return c; }
suffix_object
/* 将兄弟节点连接起来 类似与链表结构 */ static void suffix_object(cJSON* prev, cJSON* item) { prev->next = item; item->prev = prev; }
create_reference
/* 用于处理引用的实用程序(拷贝一份item结构体) */ static cJSON* create_reference(cJSON* item) { cJSON* ref = cJSON_New_Item(); if (NULL == ref)// 申请失败 { return NULL; } memcpy(ref, item, sizeof(cJSON));// 内存初始化 ref->string = '\0'; ref->type |= cJSON_IsReference; ref->next = NULL; ref->prev = NULL; return ref; }
cJSON_AddItemToArray
/* 功 能:添加元素(子结构体)到数组(父结构体)最后 参 数:array-数组结构体 item-元素子结构体 返回值:无 */ void cJSON_AddItemToArray(cJSON* array, cJSON* item) { cJSON* c = array->child; // 指向父结构体的第一个儿子 if (NULL == item) // 若发现子结构体指针为空就直接结束 { return; } if (NULL == c) // 若发现父结构的儿子为空时,直接添加 { array->child = item; } else // 若发现父结构的儿子不为空时,就开始找最后那个儿子节点 { while (NULL != c && NULL != c->next) { c = c->next; } suffix_object(c, item); // 连接新节点函数 } }
cJSON_AddItemToObject
/* 功 能:添加子结构到对象中 参 数:object-对象 string-新子结构的key item-新结构体的value 返回值:无 */ void cJSON_AddItemToObject(cJSON* object, const char* string, cJSON* item) { if (NULL == item) // 子结构体指针为NULL { return; } if ('\0' != item->string) // 子结构体中的key(string)不为空.就释放掉 { cJSON_free(item->string); } // 先在堆区开辟空间将key(string)放入然后再将堆区地址给到key(string)保管 item->string = cJSON_strdup(string); cJSON_AddItemToArray(object, item); // 将子结构体放入对象(jbject)中 }
cJSON_AddItemToObjectCS
/* 功 能:添加元素结构体到对象结构体中 参 数:object-对象 string-新添加元素的key item-新添加元素的value 返回值:无 */ void cJSON_AddItemToObjectCS(cJSON* object, const char* string, cJSON* item) { if (NULL == item) { return; } if (0 == (item->type & cJSON_StringIsConst) && '\0' != item->string) // 若item的key存在就先释放 { cJSON_free(item->string); } item->string = (char*)string; // 将key放入item item->type |= cJSON_StringIsConst; // 将type放入item cJSON_AddItemToArray(object, item); // 再将item放入对象(数组)中 }
cJSON_AddItemReferenceToArray
/* 添加元素引用到数组中 */ void cJSON_AddItemReferenceToArray(cJSON* array, cJSON* item) { cJSON_AddItemToArray(array, create_reference(item)); }
cJSON_AddItemReferenceToObject
/* 添加元素引用到对象中 */ void cJSON_AddItemReferenceToObject(cJSON* object, const char* string, cJSON* item) { cJSON_AddItemToObject(object, string, create_reference(item)); }