ASN.1 -- 使用asn1c完成ASN encode/decode
asn1c官網(wǎng):http://lionet.info/asn1c/blog/
asn1c源代碼:https://github.com/vlm/asn1c
一. 下載asn1c并編譯生成可執(zhí)行文件(關掉交叉編譯)
下載asn1c (此版本為主線版本asn1c-0.9.29,非release版本)
git clone https://github.com/vlm/asn1c.git
1
進入下載好的代碼asn1c下,執(zhí)行以下命令編譯源代碼(可參考INSTALL.md)
test -f configure || autoreconf -iv
sudo ./configure
sudo make
make install
1
2
3
4
執(zhí)行完以上命令之后,可以使用man asn1c查看命令
二. 使用asn1c命令將.asn文件生成.c和.h文件
準備*.asn文件
新建目錄,將*.asn文件拷貝至./asn下
在./下創(chuàng)建out文件夾
v2x@ubuntu:~/ASN/parser$ tree
.
├── asn
│ ├── MsgFrame.asn
│ ├── ***.asn
└── out
1
2
3
4
5
6
MsgFrame.asn如下所示:
MessageFrame ::= CHOICE {
bsmFrame BasicSafetyMessage,
mapFrame MapData,
rsmFrame RoadsideSafetyMessage,
spatFrame SPAT,
rsiFrame RoadSideInformation,
...
}
1
2
3
4
5
6
7
8
在./執(zhí)行以下命令,會在out中生成.c和.h文件
默認生成帶UPER編解碼的版本
asn1c asn/*.asn -D out/ -gen-autotools -no-gen-example
1
如果想要編譯帶例子的版本(正式代碼中不需要,如果想自己測試可以使用)
asn1c asn/*.asn -D out/ -gen-autotools
1
之后會在./生成configure.ac Makefile.am
生成configuare文件
sudo autoreconf --force --install
sudo autoconf -i
1
2
編譯例子
mkdir build
sudo ./configure --prefix=$(pwd)/build
sudo make install
1
2
3
會在./build下生成可執(zhí)行文件和鏈接庫
三.生成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;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#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_ :序列化之后的數(shù)據(jù)
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
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//使用內(nèi)存拷貝的方式將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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//此例的缺點:此例中傳入的變量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為字節(jié)數(shù)
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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
六.decode示例
asn_dec_rval_t rval;
//ATS_UNALIGNED_BASIC_PER:使用UPER編碼
//msg_frame:接收decode之后的數(shù)據(jù)
//buf:接收到的decode之前的數(shù)據(jù)
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
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
七.BIT_STRING.c源碼分析
由如下源代碼可知,若使用PER、OER編解碼格式,會使用單獨的編解碼函數(shù);若使用其他編解碼格式,編解碼可復用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 */
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
BIT_STRING_encode_uper函數(shù)下調(diào)用的BIT_STRING__compactify會將bitstring進一步優(yōu)化,將盡可能壓縮發(fā)送的byte,以及進一步填充bits_unused
/* Figure out the size without the trailing bits */
st = BIT_STRING__compactify(st, &compact_bstr);
————————————————
原文鏈接:https://blog.csdn.net/mao834099514/article/details/109102770
*博客內(nèi)容為網(wǎng)友個人發(fā)布,僅代表博主個人觀點,如有侵權(quán)請聯(lián)系工作人員刪除。