cJSON源碼閱讀(一)

源碼獲取

git clone https://github.com/DaveGamble/cJSON.git

cJSON數據結構

  1. 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;
  1. 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

  1. 向數組中添加元素
//發布給用戶的接口
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;
    }
}
  1. 獲取到指定位置元素
//將在數組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;
}
  1. 刪除數組中特定位置的元素項
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which)
{
    //調用了cJSON_DetachItemFromArray函數將要刪除的項從數組中分離出來
    cJSON_Delete(cJSON_DetachItemFromArray(array, which));
}
  1. 將數組中特定元素替換掉
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;
}
  1. 獲取數組的大小
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對象

  1. 向對象中添加一個元素項
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日

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。