编程语言
首页 > 编程语言> > cJSON源码分析(三)

cJSON源码分析(三)

作者:互联网

在构建好一个JSON对象之后,如何访问呢?

首先试着将json字符串序列化,并全部打印出来看下结构再说:

char * string = "{\"name\":\"xxx\", \"name2\":\"xxx2\"}";cJSON * root = cJSON_Parse(string);//json字符串序列化printf("%s\n", cJSON_Print(root));//json格式化输出

在这里插入图片描述
看源码了解一下cJSON_Print函数大致实现过程吧(cJSON_Parse函数实现的源码可翻阅前面文章)

/*
    printbuffer结构体主要用作格式化或非格式化打印json数据结构的缓冲区
*/typedef struct{
    unsigned char *buffer; //内容
    size_t length; //长度
    size_t offset; //偏移量
    size_t depth; /* current nesting depth (for formatted printing) 当前嵌套深度(用于格式化打印)*/
    cJSON_bool noalloc; //bool类型
    cJSON_bool format; /*bool类型, is this print a formatted print 这是是否格式化输出,用true,false控制*/
    internal_hooks hooks; //通过hook对内存进行操作} printbuffer;#define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) //判断大小,全部用括号括起来,否则如果a,b是表达式且含有比<符号级别更低的运算符就会出现不可预料的错误/* Render a cJSON item/entity/structure to text. 
将项目/实体/结构呈现为文本*/CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item){
    return (char*)print(item, true, &global_hooks);//global_hooks作为全局变量负责分配内存缓冲区}static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks){
    static const size_t default_buffer_size = 256;
    printbuffer buffer[1];
    unsigned char *printed = NULL;

    memset(buffer, 0, sizeof(buffer));

    /* create buffer 创建缓冲区读取字符*/
    buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size);
    buffer->length = default_buffer_size;
    buffer->format = format;
    buffer->hooks = *hooks;
    if (buffer->buffer == NULL)
    {
        goto fail;
    }

    /* print the value */
    if (!print_value(item, buffer))
    {
        goto fail;
    }
    update_offset(buffer);//更新偏移量

    /* check if reallocate is available */
    if (hooks->reallocate != NULL)//检查开辟的空间是否满足
    {
        printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1);//动态增加或减少空间
        if (printed == NULL) {
            goto fail;
        }
        buffer->buffer = NULL;
    }
    else /* otherwise copy the JSON over to a new buffer 
    否则,将JSON复制到新的缓冲区*/
    {
        printed = (unsigned char*) hooks->allocate(buffer->offset + 1);
        if (printed == NULL)
        {
            goto fail;
        }
        memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1));
        printed[buffer->offset] = '\0'; /* just to be sure 只是想确定一下,应该是保证字符串有正确的结束符号*/

        /* free the buffer */
        hooks->deallocate(buffer->buffer);//释放缓冲区内存
    }

    return printed;fail:
    if (buffer->buffer != NULL)
    {
        hooks->deallocate(buffer->buffer);
    }

    if (printed != NULL)
    {
        hooks->deallocate(printed);
    }

    return NULL;}/* Render a value to text. 
将值呈现为文本。*/static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer){
    unsigned char *output = NULL;

    if ((item == NULL) || (output_buffer == NULL))
    {
        return false;
    }

    switch ((item->type) & 0xFF)//0xFF, 表示item->type取低8位的值作为参数,更高位的数据不参考
    {
        case cJSON_NULL:
            output = ensure(output_buffer, 5);//确保偏移量足够容纳内容
            if (output == NULL)
            {
                return false;
            }
            strcpy((char*)output, "null");
            return true;

        case cJSON_False:
            output = ensure(output_buffer, 6);
            if (output == NULL)
            {
                return false;
            }
            strcpy((char*)output, "false");
            return true;

        case cJSON_True:
            output = ensure(output_buffer, 5);
            if (output == NULL)
            {
                return false;
            }
            strcpy((char*)output, "true");
            return true;

        case cJSON_Number:
            return print_number(item, output_buffer);

        case cJSON_Raw:
        {
            size_t raw_length = 0;
            if (item->valuestring == NULL)
            {
                return false;
            }

            raw_length = strlen(item->valuestring) + sizeof("");
            output = ensure(output_buffer, raw_length);
            if (output == NULL)
            {
                return false;
            }
            memcpy(output, item->valuestring, raw_length);
            return true;
        }

        case cJSON_String:
            return print_string(item, output_buffer);

        case cJSON_Array:
            return print_array(item, output_buffer);

        case cJSON_Object:
            return print_object(item, output_buffer);

        default:
            return false;
    }}/* calculate the new length of the string in a printbuffer and update the offset 
计算打印缓冲区中字符串的新长度并更新偏移量*/static void update_offset(printbuffer * const buffer){
    const unsigned char *buffer_pointer = NULL;
    if ((buffer == NULL) || (buffer->buffer == NULL))
    {
        return;
    }
    buffer_pointer = buffer->buffer + buffer->offset;

    buffer->offset += strlen((const char*)buffer_pointer);}/* realloc printbuffer if necessary to have at least "needed" bytes more 
重新分配printbuffer(如果需要的话)至少“需要”更多的字节*/static unsigned char* ensure(printbuffer * const p, size_t needed){
    unsigned char *newbuffer = NULL;
    size_t newsize = 0;

    if ((p == NULL) || (p->buffer == NULL))
    {
        return NULL;
    }

    if ((p->length > 0) && (p->offset >= p->length))
    {
        /* make sure that offset is valid 
        确保偏移量有效*/
        return NULL;
    }

    if (needed > INT_MAX)
    {
        /* sizes bigger than INT_MAX are currently not supported 
        当前不支持大于INT_MAX的大小*/
        return NULL;
    }

    needed += p->offset + 1;
    if (needed <= p->length)
    {
        return p->buffer + p->offset;
    }

    if (p->noalloc) {
        return NULL;
    }

    /* calculate new buffer size 
    计算新缓冲区大小*/
    if (needed > (INT_MAX / 2))
    {
        /* overflow of int, use INT_MAX if possible 
        int会溢出,溢出原因我认为是当int数是负数的时候,符号位为1,运算之后可能会超出size_t的大小
        如果可能,请使用 INT_MAX*/
        if (needed <= INT_MAX)
        {
            newsize = INT_MAX;
        }
        else
        {
            return NULL;
        }
    }
    else
    {
        newsize = needed * 2;
    }

    if (p->hooks.reallocate != NULL)
    {
        /* reallocate with realloc if available 
        重新分配与重新分配(如果可用)*/
        newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize);
        if (newbuffer == NULL)
        {
            p->hooks.deallocate(p->buffer);
            p->length = 0;
            p->buffer = NULL;

            return NULL;
        }
    }
    else
    {
        /* otherwise reallocate manually 
        否则手动重新分配*/
        newbuffer = (unsigned char*)p->hooks.allocate(newsize);
        if (!newbuffer)
        {
            p->hooks.deallocate(p->buffer);
            p->length = 0;
            p->buffer = NULL;

            return NULL;
        }
        
        memcpy(newbuffer, p->buffer, p->offset + 1);
        p->hooks.deallocate(p->buffer);
    }
    p->length = newsize;
    p->buffer = newbuffer;

    return newbuffer + p->offset;}

序列化json字符串确实繁琐,其主要花费时间在缓冲区边界界定,内容复制,内存分配处理上。
大致了解一下工作流程,函数调用顺序大致如下(主要功能):

cJSON_Print  ==>    print  ==>   print_value ==>ensure和print_string和print_array等

               

标签:分析,return,cJSON,hooks,buffer,源码,output,NULL
来源: https://blog.51cto.com/u_14175378/2759886