ASN.1简介
ASN.1抽象语法标记(Abstract Syntax Notation One) ASN.1是一种 ISO/ITU-T 标准,描述了一种对数据进行表示、编码、传输和解码的数据格式。它提供了一整套正规的格式用于描述对象的结构,而不管语言上如何执行及这些数据的具体指代,也不用去管到底是什么样的应用程序。
对于ASN.1中的数据,包含整形,字符型,时间,字符串等我们需要不同的函数或者方案来进行编码和解码。因此本文设计一种自动化编码和解码的计算机程序,根据设计好的结构体,自动编码成ASN.1格式的报文,自动解码ASN.1格式的报文到相应的数据结构。
在任何需要以数字方式发送信息的地方,ASN.1 都可以发送各种形式的信息(声频、视频、数据等等)。ASN.1 和特定的 ASN.1 编码规则推进了结构化数据的传输,尤其是网络中应用程序之间的结构化数据传输,它以一种独立于计算机架构和语言的方式来描述数据结构。
现有的方案一般是在自己的业务流程中按照模块接口手动创建ASN.1报文和手动解码ASN.1报文,最多对整形,字符型,时间,字符串等数据结构进行一次封装,然后再给业务流程做调用。
本文描述的方法是设计一种自动化编码和解码的计算机程序,根据设计好的结构体,自动编码成ASN.1格式的报文,自动解码ASN.1格式的报文到相应的数据结构。
系统设计
编码通过函数make,原型为int make(void *data, DWORD wDataLen, BYTE *pbMsg, DWORD wMsgLen),data是需要转换的自定义结构体,wDataLen是需要转换结构体的长度,pbMsg是转换后的报文,wMsgLen是转换后的报文长度,返回值也为转换后的报文长度。注意这里的报文内存不在make函数中分配,需要自己确保长度足够。
解码通过函数devide,原型为int devide(void *data, DWORD wDataLen, BYTE *pbMsg, DWORD wMsgLen),data是需要存储数据的自定义结构体,wDataLen是需要存储结构体的长度,pbMsg是需要解码的报文,wMsgLen是需要解码的报文长度,返回值为已解码的报文长度。
基础数据类型设计
基础的数据结构有yl_NULL,yl_bool,yl_BYTE,yl_WORD,yl_DWORD,yl_float,yl_double,共7种,分别为null,bool,unsigned char,unsigned short,unsigned long,float,double。基础数据结构包含结构标志和数据2个成员,其中yl_NULL4个字节,yl_double16个字节,其余都是8个字节。
复合的数据结构有yl_BYTE_SURE_array,yl_BYTE_UNSURE_array,yl_choice,yl_struct,yl_struct_of,共5种,分别为定长BYTE数组,不定长BYTE数组,choice选择,结构体,结构体数组。复合数据结构包含标志、长度、成员数量、选项和数据等成员。
数据结构的具体定义如下:
编码解码class设计
对外只呈现make和devide两个函数接口。
内部组帧为make*系列的函数,解帧为devide*系列的函数。
源码
#include "yl_func.h"
#include "yl_type.h"
#include <stdio.h>
#define Byte4ToInt(pb) ((int)(pb[3]<<24) + (int)(pb[2]<<16) + (int)(pb[1]<<8) + pb[0])
CYl::CYl()
{
}
CYl::~CYl()
{
}
int CYl::make(void *data, DWORD wDataLen, BYTE *pbMsg, DWORD wMsgLen)
{
m_pb = (BYTE *)data;//数据指针
m_dwStructLen = (int)wDataLen;//数据结构体占用字节数
m_pbMsg = (BYTE *)pbMsg;//生成报文指针
int iTag = Byte4ToInt(m_pb);
printf("encode process: Tag= %d, m_wLen= %d\n", iTag, m_dwStructLen);
if (iTag != YL_STRUCT){//一定是一个结构体开头
printf("encode fail: Tag= %d, m_wLen= %d\n", iTag, m_dwStructLen);
return -1;
}
pbMove(4, 4);
int iRet = makeStruct();
if (iRet){
printf("encode fail: Tag= %d, m_wLen= %d\n", iRet, m_dwStructLen);
return -1;
}
return m_pbMsg - pbMsg;
}
int CYl::makeOneStruct()
{
int iTag = Byte4ToInt(m_pb);
printf("encode process: Tag= %d, m_wLen= %d\n", iTag, m_dwStructLen);
pbMove(4, 4);
switch (iTag){
case YL_NULL: break;
case YL_BOOL: makeBool(); break;
case YL_BYTE: makeBYTE(); break;
case YL_WORD: makeWORD(); break;
case YL_DWORD: makeDWORD(); break;
case YL_FLOAT: makeFloat(); break;
case YL_DOUBLE: makeDouble(); break;
case YL_ARR_SURE: makeSureArr(); break;
case YL_ARR_UNSURE: makeUnSureArr(); break;
case YL_CHOICE: if (makeChoice()) return iTag; break;
case YL_STRUCT: if (int iRet = makeStruct()) return iRet; break;
case YL_STRUCT_OF: if (int iRet = makeStructOf()) return iRet; break;
default: return iTag;
}
if (m_dwStructLen < 0)
return -1;
return 0;
}
int CYl::makeStruct()
{
int iMember = *m_pb;
pbMove(4, 4);
for (int i=0; i<iMember; i++){
if (int iRet = makeOneStruct())
return iRet;
}
return 0;
}
void CYl::makeBool(){ *m_pbMsg++ = *m_pb; pbMove(4, 4);}
void CYl::makeBYTE(){*m_pbMsg++ = *m_pb; pbMove(4, 4);}
void CYl::makeWORD(){for(int i=0; i<2; i++) *m_pbMsg++ = *m_pb++; pbMove(2, 4);}
void CYl::makeDWORD(){for(int i=0; i<4; i++) *m_pbMsg++ = *m_pb++; pbMove(0, 4);}
void CYl::makeFloat(){for(int i=0; i<4; i++) *m_pbMsg++ = *m_pb++; pbMove(0, 4);}
void CYl::makeDouble(){for(int i=0; i<8; i++) *m_pbMsg++ = *m_pb++; pbMove(0, 8);}
void CYl::makeSureArr()
{
int iLen = Byte4ToInt(m_pb); pbMove(4, 4);
for (int i=0; i<iLen; i++) *m_pbMsg++ = *m_pb++;
pbMove(((iLen-1)/4+1) * 4 - iLen, ((iLen-1)/4+1) * 4);
}
void CYl::makeUnSureArr()
{
int iTotalLen = Byte4ToInt(m_pb); pbMove(4, 4);
int iLen = Byte4ToInt(m_pb); pbMove(4, 4);
EncodeAxdrLength(iLen);
for (int i=0; i<iLen; i++) *m_pbMsg++ = *m_pb++;
pbMove(((iTotalLen-1)/4+1) * 4 - iLen, ((iTotalLen-1)/4+1) * 4);
}
int CYl::makeStructOf()
{
int iTotalLen = Byte4ToInt(m_pb); pbMove(4, 4);
int iLen = Byte4ToInt(m_pb); pbMove(4, 4);
EncodeAxdrLength(iLen);
for (int i=0; i<iLen; i++){
if (int iRet = makeOneStruct())
return iRet;
}
for (int i=iLen; i<iTotalLen; i++){
if (int iRet = jumpOneStruct())
return iRet;
}
return 0;
}
int CYl::makeChoice()
{
int iRet;
int iMember = *m_pb++;
int iChoice = *m_pb++;
if (iChoice >= iMember) return -1;
pbMove(2, 4);
for (int i=0; i<iChoice; i++){
if (iRet = jumpOneStruct())
return iRet;
}
*m_pbMsg++ = (BYTE)iChoice;
if (iRet = makeOneStruct()) return iRet;
for (int i=iChoice+1; i<iMember; i++){
if (iRet = jumpOneStruct())
return iRet;
}
return 0;
}
int CYl::devide(void *data, DWORD wDataLen, BYTE *pbMsg, DWORD wMsgLen)
{
m_pb = (BYTE *)data;//数据指针
m_dwStructLen = wDataLen;//数据结构体占用字节数
m_pbMsg = (BYTE *)pbMsg;//待解析报文指针
m_dwMsgLen = (int)wMsgLen;//待解析报文长度
int iTag = Byte4ToInt(m_pb);
printf("decode process: Tag= %d, m_wLen= %d\n", iTag, m_dwStructLen);
if (iTag != YL_STRUCT){//一定是一个结构体开头
printf("decode fail: Tag= %d, m_wLen= %d\n", iTag, m_dwStructLen);
return -1;
}
pbMove(4, 4);
int iRet = devideStruct();
if (iRet){
printf("decode fail: Tag= %d, m_dwStructLen = %d, m_dwMsgLen = %d\n", iRet, m_dwStructLen, m_dwMsgLen);
return -1;
}
return m_pbMsg - pbMsg;
}
int CYl::devideOneStruct()
{
int iTag = Byte4ToInt(m_pb);
printf("decode process: Tag= %d, m_dwStructLen = %d, before m_dwMsgLen = %d, ", iTag, m_dwStructLen, m_dwMsgLen);
pbMove(4, 4);
switch (iTag){
case YL_NULL: break;
case YL_BOOL: if (devideBool() < 0) return iTag; break;
case YL_BYTE: if (devideBYTE() < 0) return iTag; break;
case YL_WORD: if (devideWORD() < 0) return iTag; break;
case YL_DWORD: if (devideDWORD() < 0) return iTag; break;
case YL_FLOAT: if (devideFloat() < 0) return iTag; break;
case YL_DOUBLE: if (devideDouble() < 0) return iTag; break;
case YL_ARR_SURE: if (devideSureArr() < 0) return iTag; break;
case YL_ARR_UNSURE: if (devideUnSureArr() < 0) return iTag; break;
case YL_CHOICE: if (devideChoice()) return iTag; break;
case YL_STRUCT: if (int iRet = devideStruct()) return iRet; break;//注意这里多层struct嵌套的情况,里层返回非0时,外层立刻返回
case YL_STRUCT_OF: if (int iRet = devideStructOf()) return iRet; break;
default: return iTag;
}
printf("after m_dwMsgLen= %d\n", m_dwMsgLen);
if (m_dwStructLen < 0)
return -1;
return 0;
}
int CYl::devideStruct()
{
int iMember = *m_pb;
pbMove(4, 4);
for (int i=0; i<iMember; i++){
if (int iRet = devideOneStruct())
return iRet;
}
return 0;
}
int CYl::devideBool()
{
m_dwMsgLen -= 1; if (m_dwMsgLen < 0) return -1;
*m_pb = *m_pbMsg++; pbMove(4, 4); return 0;
}
int CYl::devideBYTE()
{
m_dwMsgLen -= 1; if (m_dwMsgLen < 0) return -1;
*m_pb = *m_pbMsg++; pbMove(4, 4); return 0;
}
int CYl::devideWORD()
{
m_dwMsgLen -= 2; if (m_dwMsgLen < 0) return -1;
for(int i=0; i<2; i++) *m_pb++ = *m_pbMsg++; pbMove(2, 4); return 0;
}
int CYl::devideDWORD()
{
m_dwMsgLen -= 4; if (m_dwMsgLen < 0) return -1;
for(int i=0; i<4; i++) *m_pb++ = *m_pbMsg++; pbMove(0, 4); return 0;
}
int CYl::devideFloat()
{
m_dwMsgLen -= 4; if (m_dwMsgLen < 0) return -1;
for(int i=0; i<4; i++) *m_pb++ = *m_pbMsg++; pbMove(0, 4); return 0;
}
int CYl::devideDouble()
{
m_dwMsgLen -= 8;if (m_dwMsgLen < 0) return -1;
for(int i=0; i<8; i++) *m_pb++ = *m_pbMsg++; pbMove(0, 8); return 0;
}
int CYl::devideSureArr()
{
int iLen = Byte4ToInt(m_pb); pbMove(4, 4);
m_dwMsgLen -= iLen; if (m_dwMsgLen < 0) return -1;
for (int i=0; i<iLen; i++) *m_pb++ = *m_pbMsg++;
pbMove(((iLen-1)/4+1) * 4 - iLen, ((iLen-1)/4+1) * 4);
return 0;
}
int CYl::devideUnSureArr()
{
DWORD iLen, iTmp;
int iByte, i;
int iTotalLen = Byte4ToInt(m_pb); pbMove(4, 4);
if ((iByte = DecodeAxdrLength(iLen)) < 0) return -1;
if (iLen > iTotalLen) return -2;
for (i=0,iTmp=iLen; i<4; i++) { *m_pb++ = iTmp & 0xff; iTmp >>= 8;} pbMove(0, 4);
m_dwMsgLen -= iLen; if (m_dwMsgLen < 0) return -3;
for (int i=0; i<iLen; i++) *m_pb++ = *m_pbMsg++;
pbMove(((iTotalLen-1)/4+1) * 4 - iLen, ((iTotalLen-1)/4+1) * 4);
return 0;
}
int CYl::devideStructOf()
{
DWORD iLen, iTmp;
int iByte, i;
int iTotalLen = Byte4ToInt(m_pb); pbMove(4, 4);
if ((iByte = DecodeAxdrLength(iLen)) < 0) return -1;
if (iLen > iTotalLen) return -2;
for (i=0,iTmp=iLen; i<4; i++) { *m_pb++ = iTmp & 0xff; iTmp >>= 8;} pbMove(0, 4);
m_dwMsgLen -= iLen; if (m_dwMsgLen < 0) return -3;
for (int i=0; i<iLen; i++){
if (int iRet = devideOneStruct())
return iRet;
}
for (int i=iLen; i<iTotalLen; i++){
if (int iRet = jumpOneStruct())
return iRet;
}
return 0;
}
int CYl::devideChoice()
{
m_dwMsgLen -= 1;
if (m_dwMsgLen < 0) return -1;
int iMember = *m_pb++;//总的选项,结构体自带
int iChoice = (int)*m_pbMsg; //选项,报文带来
*m_pb++ = *m_pbMsg++;
if (iChoice >= iMember) return -1;
pbMove(2, 4);
int iRet;
for (int i=0; i<iChoice; i++){
if (iRet = jumpOneStruct())
return iRet;
}
if (iRet = devideOneStruct()) return iRet;
for (int i=iChoice+1; i<iMember; i++){
if (iRet = jumpOneStruct())
return iRet;
}
return 0;
}
int CYl::jumpOneStruct()
{
if (m_dwStructLen < 0) return -1;
int iTag = Byte4ToInt(m_pb);
pbMove(4, 4);
switch (iTag){
case YL_NULL: break;
case YL_BOOL: pbMove(4, 4); break;
case YL_BYTE: pbMove(4, 4); break;
case YL_WORD: pbMove(4, 4); break;
case YL_DWORD: pbMove(4, 4); break;
case YL_FLOAT: pbMove(4, 4); break;
case YL_DOUBLE: pbMove(8, 8); break;
case YL_ARR_SURE: {
int iLen = Byte4ToInt(m_pb); pbMove(4, 4);
pbMove(((iLen-1)/4+1) * 4, ((iLen-1)/4+1) * 4);
break;
}
case YL_ARR_UNSURE: {
int iTotalLen = Byte4ToInt(m_pb); pbMove(4, 4); pbMove(4, 4);
pbMove(((iTotalLen-1)/4+1) * 4, ((iTotalLen-1)/4+1) * 4);
break;
}
case YL_CHOICE: if (int iRet = jumpStruct()) return iRet; break;//这时候当做一个完全的结构体来跳过
case YL_STRUCT: if (int iRet = jumpStruct()) return iRet; break;
case YL_STRUCT_OF: {
int iTotalLen = Byte4ToInt(m_pb); pbMove(4, 4); pbMove(4, 4);
for (int i=0; i<iTotalLen; i++){
if (int iRet = jumpOneStruct())
return iRet;
}
break;
}
default: return iTag;
}
return 0;
}
int CYl::jumpStruct()
{
int iMember = *m_pb;
pbMove(4, 4);
for (int i=0; i<iMember; i++){
if (int iRet = jumpOneStruct())
return iRet;
}
return 0;
}
void CYl::pbMove(int iPb, int iLen){m_pb += iPb; m_dwStructLen -= iLen;}
/**
* @brief 编码 axdr 可变长数据
*
* @param [in]len 待转长度
* @param [in]fSigned 有无符号,默认 false
* @return BYTE 返回编码后的字节长度
*/
int CYl::EncodeAxdrLength(int len, bool fSigned)
{
if(len < 128){
*m_pbMsg++ = len;
return 1;
}else{
BYTE k = 4, ch[4] = {0};
ch[0] = (BYTE)(len >> 24);
ch[1] = (BYTE)(len >> 16);
ch[2] = (BYTE)(len >> 8);
ch[3] = (BYTE)len;
for (int i = 0; i < 4; i++){
if(ch[i] == 0) k--;
else break;
}
for (int i = 0; i < k; i++){
if(fSigned){
if(ch[4 - k] < 0x80) *m_pbMsg++ = 0x80 | k;
else{*m_pbMsg++ = 0x80 | (k+1); *m_pbMsg++ = 0;}
}else if(i == 0) *m_pbMsg++ = 0x80 | k;
*m_pbMsg++ = ch[4 - k + i];
}
if(fSigned) return k + 1 + 1;
else return k + 1;
}
}
/**
* @brief 解码 axdr 可变长数据
*
* @param [out]pwNum 解码后的长度信息
* @return int 返回可变长数据占用的字节数,失败返回 -1
*/
int CYl::DecodeAxdrLength(DWORD &pwNum)
{
m_dwMsgLen -= 1;
if (m_dwMsgLen < 0) return -1;
if (*m_pbMsg < 128){
pwNum = *m_pbMsg++;
return 1;
}
else{
BYTE k = *m_pbMsg++ - 0x80;
if(k > 3) return -2;
m_dwMsgLen -= k;
if (m_dwMsgLen < 0) return -3;
DWORD val = 0;
for (BYTE i = 0; i < k; i++)
val = (val << 8) + *m_pbMsg++;
pwNum = val;
return k + 1;
}
}