ASN.1 -- 使用asn1c完成ASN encode/decode

asn1c官网:http://lionet.info/asn1c/blog/
asn1c源代码:https://github.com/vlm/asn1c

一. 下载asn1c并编译生成可执行文件(关掉交叉编译)

  • 下载asn1c (此版本为主线版本asn1c-0.9.29,非release版本)
git clone https://github.com/vlm/asn1c.git

在这里插入图片描述

  • 进入下载好的代码asn1c下,执行以下命令编译源代码(可参考INSTALL.md)
test -f configure || autoreconf -iv
sudo ./configure
sudo make
make install
  • 执行完以上命令之后,可以使用man asn1c查看命令
    在这里插入图片描述

二. 使用asn1c命令将.asn文件生成.c和.h文件

  • 准备*.asn文件

  • 新建目录,将*.asn文件拷贝至./asn下
    在这里插入图片描述

  • 在./下创建out文件夹

v2x@ubuntu:~/ASN/parser$ tree
.
├── asn
│   ├── MsgFrame.asn
│   ├── ***.asn
└── out

MsgFrame.asn如下所示:

MessageFrame ::= CHOICE {
    
     
		bsmFrame BasicSafetyMessage,
		mapFrame MapData,
		rsmFrame RoadsideSafetyMessage,
		spatFrame SPAT,
		rsiFrame RoadSideInformation,
		...
	}
  • 在./执行以下命令,会在out中生成.c和.h文件
    默认生成带UPER编解码的版本
asn1c asn/*.asn -D out/ -gen-autotools -no-gen-example
  • 如果想要编译带例子的版本(正式代码中不需要,如果想自己测试可以使用)
asn1c asn/*.asn -D out/ -gen-autotools

之后会在./生成configure.ac Makefile.am
生成configuare文件

sudo autoreconf --force --install
sudo autoconf -i

编译例子

mkdir build
sudo ./configure --prefix=$(pwd)/build
sudo make install

会在./build下生成可执行文件和链接库

三.生成libasncodec.so(开启交叉编译)

  • 将out/下的*.c 和 *.h 分别拷贝到自己的代码中,编译成libasncodec.so
    在这里插入图片描述
    在这里插入图片描述

四.开启asn1c生成的代码中的debug log

  • 在编译libasncodec.so时,定义“-DEMIT_ASN_DEBUG=1”,CMakeLists.txt示例如下所示:
    在这里插入图片描述
    源代码中ASN_DEBUG的定义如下所示:
    在这里插入图片描述

五.encode示例

//asn1c通过MsgFrame.asn自动生成
/* MessageFrame */
typedef struct MessageFrame {
    
    
	MessageFrame_PR present;
	union MessageFrame_u {
    
    
		BasicSafetyMessage_t	 bsmFrame;
		MapData_t	 mapFrame;
		RoadsideSafetyMessage_t	 rsmFrame;
		SPAT_t	 spatFrame;
		RoadSideInformation_t	 rsiFrame;
		PrivateMsg_t	 pmFrame;
		RTCMcorrections_t	 rtcmFrame;
		/*
		 * This type is extensible,
		 * possible extensions are below.
		 */
	} choice;
	
	/* Context for parsing across buffer boundaries */
	asn_struct_ctx_t _asn_ctx;
} MessageFrame_t;
#define MAX_PAYLOAD_LEN 1300
asn_enc_rval_t er;
MessageFrame* msg_frame_;
msg_frame_ = (MessageFrame *)calloc(1, sizeof(MessageFrame));
tran_inner_msg_to_asn(msg, msg_frame_);
char buf_[MAX_PAYLOAD_LEN];
//ATS_UNALIGNED_BASIC_PER:使用UPER编码
//msg_frame_ :asn1c自动生成的根ASN格式
//buf_ :序列化之后的数据
er = asn_encode_to_buffer(0, ATS_UNALIGNED_BASIC_PER, &asn_DEF_MessageFrame, msg_frame_, buf_, MAX_PAYLOAD_LEN);
if (er.encoded > 0 && er.encoded <= MAX_PAYLOAD_LEN)
{
    
    
	//success
    len_ = er.encoded;
}
else
{
    
    
	//error
}
//使用内存拷贝的方式将val拷贝到str
int codec_asn_t::encode_string(const std::string val, OCTET_STRING_t &str)
{
    
    
    if (val.empty())
    {
    
    
        return E_INVAL;
    }

    str.size = val.size();
    str.buf = (uint8_t *)malloc(str.size);
    if (NULL == str.buf)
    {
    
    
        return E_NOMEM;
    }

    memset(str.buf, 0, str.size);
    memcpy(str.buf, val.data(), str.size);

    return E_OK;
}
//此例的缺点:此例中传入的变量val为int型,意味着在32位的机器中最大只能支持SIZE小于等于32个的bitstring
int codec_asn_t::encode_bitstring(int val, int bit_num, BIT_STRING_t &str)
{
    
    
    int len = (bit_num % 8 == 0) ? (bit_num / 8) : (bit_num / 8) + 1;
    int tmp_val = 0;
	//从源码中可以看出size为字节数
    str.size = bit_num;
    str.buf = (uint8_t *)malloc(len);
    if (NULL == str.buf)
    {
    
    
        return E_NOMEM;
    }
    //str.buf中应该传入的格式为:若asn中定义的bitstring的SIZE为16,
    //给asn中定义的(0)赋值为1,就将str.buf赋值为0x80(即10000000B);
    //给asn中定义的(1)也赋值为1,就将str.buf赋值为0xC0(即11000000B);
    //以此类推
    memset(str.buf, 0, len);
    tmp_val = 1;
    for (int i = 0; i < bit_num; i++)
    {
    
    
        if (val & tmp_val)
        {
    
    
            str.buf[i / 8] |= (0x80 >> (i % 8));
        }
        tmp_val *= 2;
    }

    return E_OK;
}

六.decode示例

asn_dec_rval_t rval;
//ATS_UNALIGNED_BASIC_PER:使用UPER编码
//msg_frame:接收decode之后的数据
//buf:接收到的decode之前的数据
rval = asn_decode(0, ATS_UNALIGNED_BASIC_PER, &asn_DEF_MessageFrame, (void **)(&msg_frame), (char *)buf, len);
if (rval.code == RC_OK)
{
    
    
	//success
    msg = tran_asn_to_inner_msg(msg_frame);
    ASN_STRUCT_FREE(asn_DEF_MessageFrame, msg_frame);
}
else
{
    
    
	//error
}
int codec_asn_t::decode_bitstring(const BIT_STRING_t &str, int &val)
{
    
    
    if ((str.size <= 0) ||
        (NULL == str.buf))
    {
    
    
        return E_INVAL;
    }

    int tmp_val = 1;

    val = 0;
    for (int i = 0; i < str.size; i++)
    {
    
    
        if (str.buf[i / 8] & (0x80 >> (i % 8)))
        {
    
    
            val |= tmp_val;
        }
        tmp_val *= 2;
    }
    return E_OK;
}

七.BIT_STRING.c源码分析

  • 由如下源代码可知,若使用PER、OER编解码格式,会使用单独的编解码函数;若使用其他编解码格式,编解码可复用OCTET_STRING
asn_TYPE_operation_t asn_OP_BIT_STRING = {
    
    
	OCTET_STRING_free,         /* Implemented in terms of OCTET STRING */
	BIT_STRING_print,
	BIT_STRING_compare,
	OCTET_STRING_decode_ber,   /* Implemented in terms of OCTET STRING */
	OCTET_STRING_encode_der,   /* Implemented in terms of OCTET STRING */
	OCTET_STRING_decode_xer_binary,
	BIT_STRING_encode_xer,
#ifdef	ASN_DISABLE_OER_SUPPORT
	0,
	0,
#else
	BIT_STRING_decode_oer,
	BIT_STRING_encode_oer,
#endif  /* ASN_DISABLE_OER_SUPPORT */
#ifdef	ASN_DISABLE_PER_SUPPORT
	0,
	0,
#else
	BIT_STRING_decode_uper,	/* Unaligned PER decoder */
	BIT_STRING_encode_uper,	/* Unaligned PER encoder */
#endif  /* ASN_DISABLE_PER_SUPPORT */
	BIT_STRING_random_fill,
	0	/* Use generic outmost tag fetcher */
};
  • BIT_STRING_encode_uper函数下调用的BIT_STRING__compactify会将bitstring进一步优化,将尽可能压缩发送的byte,以及进一步填充bits_unused
/* Figure out the size without the trailing bits */
    st = BIT_STRING__compactify(st, &compact_bstr);

猜你喜欢

转载自blog.csdn.net/mao834099514/article/details/109102770