源碼獲取
git clone https://github.com/DaveGamble/cJSON.git
cJSON數據結構
- cJSON結構體
typedef struct cJSON
{
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
//next和prev兩個指針提供了一個cJSON節點指向雙向鏈表的前一個節點或者后一個節點
struct cJSON *next;
struct cJSON *prev;
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
//child指針指向當前cJSON節點的子節點
struct cJSON *child;
/* The type of the item, as above. */
//cJSON節點的類型
int type;
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
char *valuestring;
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
int valueint;
/* The item's number, if type==cJSON_Number */
double valuedouble;
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
//cJSON節點的key值
char *string;
} cJSON;
- cJSON類型
#define cJSON_Invalid (0)
#define cJSON_False (1 << 0)
#define cJSON_True (1 << 1)
#define cJSON_NULL (1 << 2)
#define cJSON_Number (1 << 3)
#define cJSON_String (1 << 4)
#define cJSON_Array (1 << 5)
#define cJSON_Object (1 << 6)
//raw類型 {"message":"\{\"name\":\"Tom\"\}"}
#define cJSON_Raw (1 << 7) /* raw json */
#define cJSON_IsReference 256
#define cJSON_StringIsConst 512
對于各個類型的判斷有專門的函數類似:cJSON_Is...,例如:
cJSON_bool cJSON_IsString(const cJSON * const item)
{
if (item == NULL)
{
return false;
}
return (item->type & 0xFF) == cJSON_String;
}
創建cJSON節點,使用類似cJSON_Create...的函數分配內存,例如:
//定義的宏
#define internal_malloc malloc
#define internal_free free
#define internal_realloc realloc
//cJSON中封裝了一層分配和釋放內存時使用的函數
typedef struct internal_hooks
{
void *(CJSON_CDECL *allocate)(size_t size);
void (CJSON_CDECL *deallocate)(void *pointer);
void *(CJSON_CDECL *reallocate)(void *pointer, size_t size);
} internal_hooks;
//初始化global_hooks變量,實際上就是調用了c語言的malloc,free,realloc三個函數
static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc };
//分配一個cJSON結構體大小的內存空間
static cJSON *cJSON_New_Item(const internal_hooks * const hooks)
{
cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON));
if (node)
{
memset(node, '\0', sizeof(cJSON));
}
return node;
}
//以創建True類型的子節點為例,其他類型的cJSON節點創建非常的類似
cJSON * cJSON_CreateTrue(void)
{
//獲取到分配的內存地址
cJSON *item = cJSON_New_Item(&global_hooks);
if(item)
{
//將type賦予對應的類型
item->type = cJSON_True;
}
return item;
}
cJSON結構體內存釋放
void cJSON_Delete(cJSON *item)
{
cJSON *next = NULL;
//如果不是NULL指針
while (item != NULL)
{
//保存下一個節點
next = item->next;
//如果不是Reference類型,子節點不為空
if (!(item->type & cJSON_IsReference) && (item->child != NULL))
{
//遞歸釋放子節點
cJSON_Delete(item->child);
}
//如果不是Reference類型,有分配valuestring指針的空間
if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
{
//釋放valuestring的內存
global_hooks.deallocate(item->valuestring);
}
//如果不是cJSON_StringIsConst,則將cJSON結構體中的string釋放
if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
{
global_hooks.deallocate(item->string);
}
global_hooks.deallocate(item);
//釋放下一個兄弟節點
item = next;
}
}
數組 Arrays
- 向數組中添加元素
//發布給用戶的接口
CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item)
{
//調用靜態函數來實現,array:數組,item:要插入的元素
add_item_to_array(array, item);
}
//內部靜態函數,用戶無法調用
static cJSON_bool add_item_to_array(cJSON *array, cJSON *item)
{
cJSON *child = NULL;
//對于指針的合法性校驗
if ((item == NULL) || (array == NULL))
{
return false;
}
//獲取到數組的子節點值
child = array->child;
//如果沒有子節點,則新加入的元素是子節點的第一項
if (child == NULL)
{
/* list is empty, start new one */
array->child = item;
}
//如果存在子節點,則將新插入的節點放到子節點的最后面。
else
{
/* append to the end */
while (child->next)
{
child = child->next;
}
//suffix_object函數實現的功能:
//child->next=item;
//item->prev=child;
suffix_object(child, item);
}
return true;
}
向數組中的特定位置插入元素
void cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
{
cJSON *after_inserted = NULL;
//判斷which是否合法
if (which < 0)
{
return;
}
//get_array_item函數用來獲取到第which個元素的指針(從0開始),實現起來很簡單,這里略過
after_inserted = get_array_item(array, (size_t)which);
//如果是數組中沒有元素
if (after_inserted == NULL)
{
add_item_to_array(array, newitem);
return;
}
//雙向鏈表的插入元素過程
newitem->next = after_inserted;
newitem->prev = after_inserted->prev;
after_inserted->prev = newitem;
//如果是插入到最開始地方,將數組的child指針指向新加入的元素
if (after_inserted == array->child)
{
array->child = newitem;
}
//如果不是在數組最開始的地方
else
{
newitem->prev->next = newitem;
}
}
- 獲取到指定位置元素
//將在數組which位置的元素從數組中分離出來
cJSON * cJSON_DetachItemFromArray(cJSON *array, int which)
{
if (which < 0)
{
return NULL;
}
return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which));
}
//實際上就是從雙向鏈表中將元素分離出來
cJSON * cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item)
{
if ((parent == NULL) || (item == NULL))
{
return NULL;
}
if (item->prev != NULL)
{
/* not the first element */
item->prev->next = item->next;
}
if (item->next != NULL)
{
/* not the last element */
item->next->prev = item->prev;
}
if (item == parent->child)
{
/* first element */
parent->child = item->next;
}
/* make sure the detached item doesn't point anywhere anymore */
item->prev = NULL;
item->next = NULL;
return item;
}
- 刪除數組中特定位置的元素項
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which)
{
//調用了cJSON_DetachItemFromArray函數將要刪除的項從數組中分離出來
cJSON_Delete(cJSON_DetachItemFromArray(array, which));
}
- 將數組中特定元素替換掉
void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
{
if (which < 0)
{
return;
}
cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem);
}
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement)
{
if ((parent == NULL) || (replacement == NULL) || (item == NULL))
{
return false;
}
//如果要替換的節點和新節點是同一個
if (replacement == item)
{
return true;
}
replacement->next = item->next;
replacement->prev = item->prev;
if (replacement->next != NULL)
{
replacement->next->prev = replacement;
}
if (replacement->prev != NULL)
{
replacement->prev->next = replacement;
}
if (parent->child == item)
{
parent->child = replacement;
}
item->next = NULL;
item->prev = NULL;
//將舊的節點刪除
cJSON_Delete(item);
return true;
}
- 獲取數組的大小
int cJSON_GetArraySize(const cJSON *array)
{
cJSON *child = NULL;
size_t size = 0;
if (array == NULL)
{
return 0;
}
//獲取到child子節點
child = array->child;
while(child != NULL)
{
size++;
child = child->next;
}
/* FIXME: Can overflow here. Cannot be fixed without breaking the API */
return (int)size;
}
Object對象
- 向對象中添加一個元素項
void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
{
add_item_to_object(object, string, item, &global_hooks, false);
}
static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key)
{
char *new_key = NULL;
int new_type = cJSON_Invalid;
if ((object == NULL) || (string == NULL) || (item == NULL))
{
return false;
}
if (constant_key)
{
//將string的const指針去掉
new_key = (char*)cast_away_const(string);
new_type = item->type | cJSON_StringIsConst;
}
else
{
//cJSON_strdup創建一個string字符串的副本,并返回新分配內存的地址
new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks);
if (new_key == NULL)
{
return false;
}
new_type = item->type & ~cJSON_StringIsConst;
}
if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
{
hooks->deallocate(item->string);
}
item->string = new_key;
item->type = new_type;
return add_item_to_array(object, item);
}
未完
關于json的解析和序列化放到后面的文章中
2019年6月23日