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日

你可能感兴趣的:(cJSON源码阅读(一))