c印记(十): parcel(数据集,数据容器)实现

一、写在前面的话

parcel是Android中的Framework层的一个数据结构,以c++实现,可以理解为数据集或者数据容器,在android将其作为函数的参数以及binder通信等,这里是仿照Android的parcel写的一个c语言版本的parcel,当然并不是完全将Android的parcel翻译成c语言,还会对其进行精简,将一些复杂的东西统统丢掉,只留下,数据容器操作相关的部分。以便以后在各种通信(网络,线程间,硬件接口如SPI之间),数据封装等等情况下,可以快速使用。

二、接口定义

也就是一个header file。

#ifndef __TINY_PARCEL_H__
#define __TINY_PARCEL_H__

#include "general_type.h"
#include "general_error.h"

/***************************************************************************
 *
 * macro declaration
 *
 ***************************************************************************/

/***************************************************************************
 *
 * data structure declaration
 *
 ***************************************************************************/

/** @brief parcel data and interface */
typedef struct tiny_parcel_s
{
    GU08* data; /**< pointer to data buffer */
    GU32 pos;   /**< offset position of parcel operation */
    GU32 size;  /**< the size of data buffer */

    /**
    *@brief  write data to parcel
    *
    *@param  parcel [in] pointer to parcel data structure.
    *@param  data   [in] pointer to data buffer.
    *@param  len    [in] the length of data
    *
    *@retuen success: G_OK, fail: error code.
    *@see
    */
    GS32(*write)(struct tiny_parcel_s* parcel, const void* data, GU32 len);

    /**
    *@brief  write a 32 bits integer value to parcel
    *
    *@param  parcel [in] pointer to parcel data structure.
    *@param  value  [in] the value of integer
    *
    *@retuen success: G_OK, fail: error code.
    *@see
    */
    GS32 (*writeInt32)(struct tiny_parcel_s* parcel, GS32 value);


    /**
    *@brief  write a 64 bits integer value to parcel
    *
    *@param  parcel [in] pointer to parcel data structure.
    *@param  value  [in] the value of integer
    *
    *@retuen success: G_OK, fail: error code.
    *@see
    */
    GS32(*writeInt64)(struct tiny_parcel_s* parcel, GS64 value);

    /**
    *@brief  write a float value to parcel
    *
    *@param  parcel [in] pointer to parcel data structure.
    *@param  value  [in] the value of float
    *
    *@retuen success: G_OK, fail: error code.
    *@see
    */
    GS32(*writeFloat)(struct tiny_parcel_s* parcel, GFLT value);

    /**
    *@brief  write a string to parcel
    *
    *@param  parcel [in] pointer to parcel data structure.
    *@param  value  [in] pointer to string
    *
    *@retuen success: G_OK, fail: error code.
    *@see
    *
    *@note the string must end with '\0'.
    *
    */
    GS32(*writeString)(struct tiny_parcel_s* parcel, const char* value);

    /**
    *@brief  read data from parcel
    *
    *@param  parcel    [in]  pointer to parcel data structure.
    *@param  out_data  [out] pointer to out data buffer.
    *@param  len       [in]  the length of out data(request read)
    *
    *@retuen success: G_OK, fail: error code.
    *@see
    */
    GS32(*read)(struct tiny_parcel_s* parcel, void* out_data, GU32 len);

    /**
    *@brief  read a 32 bits integer from parcel
    *
    *@param  parcel [in]  pointer to parcel data structure.
    *
    *@retuen the value of integer
    *@see
    */
    GS32(*readInt32)(struct tiny_parcel_s* parcel);

    /**
    *@brief  read a 64 bits integer from parcel
    *
    *@param  parcel [in]  pointer to parcel data structure.
    *
    *@retuen the value of integer
    *@see
    */
    GS64(*readInt64)(struct tiny_parcel_s* parcel);

    /**
    *@brief  read a float from parcel
    *
    *@param  parcel [in]  pointer to parcel data structure.
    *
    *@retuen the value of float
    *@see
    */
    GFLT(*readFloat)(struct tiny_parcel_s* parcel);

    /**
    *@brief  read a string from parcel
    *
    *@param  parcel [in]  pointer to parcel data structure.
    *
    *@retuen success: the pointer to string, fail: NULL
    *@see
    */
    GSTR(*readString)(struct tiny_parcel_s* parcel);

}tiny_parcel_t;
/***************************************************************************
 *
 * API declaration
 *
 ***************************************************************************/

 /**
 *@brief  initialize parcel data structure
 *
 *@param  parcel [io] pointer to parcel data structure.
 *@param  data   [in] pointer to data buffer.
 *@param  len    [in] the length of out data()
 *
 *@retuen success: G_OK, fail: error code.
 *@see
 *
 *@note this interface set does not thread safe
 *
 */
 GS32 TinyParcelInitialize(tiny_parcel_t* parcel, void* data, GU32 len);

#endif //end of __TINY_PARCEL_H__

其中general_xxx.h 就是前一章说的一些通用的头文件,其中定义基本数据类型,以及 功能 宏,通用错误号等等。 当然,这里也可以自己在这个parcel的header file中定义,但是因为c印记 这一系列的文章,绝大多数都会使用到这些基本数据类型以及通用错误号等东西,所以就特意将这些聚拢成几个公用的header file。

三、pracel功能的具体实现

#include <stdio.h>
#include <string.h> /** 标准c相关头文件 */

#include "tiny_parcel.h" /** parcel 接口声明头文件 */


/***************************************************************************
*
* macro define
*
***************************************************************************/

/** 宏定义一些log输出接口, 移植的时候只需要修改这个宏就可以改变log的输出方式 */
#define LOGE printf
#define LOGD printf
/***************************************************************************
*
* data structure define
*
***************************************************************************/


/***************************************************************************
*
* inner API define
*
***************************************************************************/
static inline GS32 TinyPracelWriteCommon(char* dst, GU32 dst_size, GU32* pos,  const void* data, GU32 len)
{
    GS32 ret = G_ErrorBadParameter;

    if (data && (len > 0))
    {
        if ((*pos + len) <= dst_size)
        {
            memcpy(dst + *pos, data, len);
            *pos += len;
            ret = G_OK;
        }
        else
        {
            LOGE("doesn't enough data or space(pos+len(%d) < size(%d)) \n", (*pos + len), dst_size);
            ret = G_ErrorOverflow;
        }
    }

    return ret;
}

static inline GS32 TinyPracelWrite(tiny_parcel_t* parcel, const void* data, GU32 len)
{
    return TinyPracelWriteCommon(parcel->data, parcel->size, &(parcel->pos), data, len);
}

static GS32 TinyPracelWriteInt32(tiny_parcel_t* parcel, GS32 value)
{
    return TinyPracelWrite(parcel, (const void*)&value, sizeof(value));
}

static GS32 TinyPracelWriteInt64(tiny_parcel_t* parcel, GS64 value)
{
    return TinyPracelWrite(parcel, (const void*)&value, sizeof(value));
}

static GS32 TinyPracelWriteFloat(tiny_parcel_t* parcel, GFLT value)
{
    return TinyPracelWrite(parcel, (const void*)&value, sizeof(value));
}

static GS32 TinyPracelWriteString(tiny_parcel_t* parcel, const char* value)
{
    return TinyPracelWrite(parcel, (const void*)value, value ? (strlen(value) + 1) : 0);
}

static inline GS32 TinyPracelRead(tiny_parcel_t* parcel, void* out_data, GU32 len)
{
    return TinyPracelWriteCommon(out_data, parcel->size, &(parcel->pos), parcel->data, len);
}

static GS32 TinyPracelReadInt32(tiny_parcel_t* parcel)
{
    GS32 value = 0;
    TinyPracelRead(parcel, (void*)&value, sizeof(value));

    return value;
}

static GS64 TinyPracelReadInt64(tiny_parcel_t* parcel)
{
    GS64 value = 0;
    TinyPracelRead(parcel, (void*)&value, sizeof(value));

    return value;
}

static GFLT TinyPracelReadFloat(tiny_parcel_t* parcel)
{
    GFLT value = 0;
    TinyPracelRead(parcel, (void*)&value, sizeof(value));

    return value;
}

static GSTR TinyPracelReadString(tiny_parcel_t* parcel)
{
    GSTR value = NULL;
    GU32 avail = parcel->size - parcel->pos;

    if (avail > 0)
    {
        GSTR str = (GSTR)(parcel->data + parcel->pos);
        // is the string's trailing NUL within the parcel's valid bounds?
        GSTR eos = memchr(str, '\0', avail);

        if (eos)
        {
            GU32 len = eos - str;
            value = str;
            parcel->pos += (len + 1); /** + 1, indicate skip '\0' */
        }
    }

    return value;
}
/***************************************************************************
*
* API define
*
***************************************************************************/

GS32 TinyPracelInitialize(tiny_parcel_t* parcel, void* data, GU32 len)
{
    GS32 ret = G_ErrorBadParameter;

    if (parcel && data && (len > 0))
    {
        parcel->data = data;
        parcel->size = len;
        parcel->pos = 0;

        /** register inteface */
        parcel->read = TinyPracelRead;
        parcel->readFloat = TinyPracelReadFloat;
        parcel->readInt32 = TinyPracelReadInt32;
        parcel->readInt64 = TinyPracelReadInt64;
        parcel->readString = TinyPracelReadString;

        parcel->write = TinyPracelWrite;
        parcel->writeFloat = TinyPracelWriteFloat;
        parcel->writeInt32 = TinyPracelWriteInt32;
        parcel->writeInt64 = TinyPracelWriteInt64;
        parcel->writeString = TinyPracelWriteString;

        ret = G_OK;
    }

    return ret;
}

四、使用例子

1、 用途

  • parcel可以用作函数的参数,以支持各种参数组合以及后续扩展,就比如Android中AwesomePlayer中的invoke接口(其原型为:status_t invoke(const Parcel &request, Parcel *reply);)

  • parcel可以用来实现协议通信,比如模组与模组之间,线程与线程之间,进程与进程之间,甚至是系统与系统之间也可以使用parcel将需要传输的数据或信息按照自定义的格式(就相当于约定好的协议)组合写到一个buffer之中,然后通过网络,SPI,uart,I2C等方式传输到目标系统,再使用parcel的read接口,按照自定义的格式一一读取出来

2、例子

#include <stdio.h>
#include <string.h>

#include "tiny_parcel.h"
/***************************************************************************
*
* macro define
*
***************************************************************************/
#define LOGE printf
#define LOGD printf

/***************************************************************************
*
* API define
*
***************************************************************************/
int main(int argc, char* argv[])
{
#define PARCEL_BUF_SIZE 1024

    char temp_buf[PARCEL_BUF_SIZE];

    char* pbuf1 = temp_buf;

    char* pbuf2 = NULL; 
    tiny_parcel_t write_parcel;
    GS32 dataInt32 = 123;
    GS64 dataInt64 = 456;
    GFLT dataFloat = 789.123;
    GSTR dataString = "this is string";
    GSTR dataData = "this is data"; /** fake pure data */
    GU32 dataLen = strlen(dataData);


    GS32 ret = TinyParcelInitialize(&write_parcel, pbuf1, PARCEL_BUF_SIZE);

    if (ret == G_OK)
    {
        LOGD("write data:\n");
        LOGD("int32: %d\n", dataInt32);
        LOGD("int64: %lld\n", dataInt64);
        LOGD("float: %f\n", dataFloat);
        LOGD("string: %s\n", dataString);
        LOGD("pure data: %s\n", dataData);

        /** write data to parcel */
        write_parcel.writeInt32(&write_parcel, dataInt32);
        write_parcel.writeInt64(&write_parcel, dataInt64);
        write_parcel.writeFloat(&write_parcel, dataFloat);
        write_parcel.writeString(&write_parcel, dataString);
        ret = write_parcel.write(&write_parcel,dataData, dataLen);

        if (ret == G_OK)
        {       
            /** fake data transform */
            pbuf2 = pbuf1;
            LOGD("\n=======================================\n");
            /** read data from parcel */
            {/** fake other thread/porcessor/system */
                GS32 readInt32 = 0;
                GS64 readInt64 = 0;
                GFLT readFloat = 0.0;
                GSTR readString = NULL;         
                GU32 readDataLen = dataLen;
                char readPureData[PARCEL_BUF_SIZE] = {0};
                tiny_parcel_t read_parcel;

                ret = TinyParcelInitialize(&read_parcel, pbuf2, PARCEL_BUF_SIZE);

                if (ret == G_OK)
                {
                    readInt32 = read_parcel.readInt32(&read_parcel);
                    readInt64 = read_parcel.readInt64(&read_parcel);
                    readFloat = read_parcel.readFloat(&read_parcel);
                    readString = read_parcel.readString(&read_parcel);

                    ret = read_parcel.read(&read_parcel, readPureData, readDataLen);

                    if (ret == G_OK)
                    {
                        LOGD("read data:\n");
                        LOGD("int32: %d\n", readInt32);
                        LOGD("int64: %lld\n", readInt64);
                        LOGD("float: %f\n", readFloat);
                        LOGD("string: %s\n", readString);
                        LOGD("pure data: %s\n", readPureData);

                        LOGD("\n=========================================\n");
                        if ((dataInt32 == readInt32) &&
                            (dataInt64 == readInt64) &&
                            (dataFloat == readFloat) &&
                            (!strcmp(dataString, readString)) &&
                            (!memcmp(dataData, readPureData, dataLen)))
                        {
                            LOGD("data check OK ...\n");
                        }
                        else
                        {
                            LOGD("data check failed ...\n");
                        }
                    }
                    else
                    {
                        LOGE("read pure data from parcel failed(0x%08x)\n", ret);
                    }
                }
                else
                {
                    LOGE("initialize read parcel failed(0x%08x)\n", ret);
                }

            }       
        }
        else
        {
            LOGE("read pure data to parcel failed(0x%08x)\n", ret);
        }

    }
    else
    {
        LOGE("initialize write parcel failed(0x%08x)\n", ret);
    }



    return 0;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值