一种结构化数据编码、解码ASN.1报文的设计方法

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是需要解码的报文长度,返回值为已解码的报文长度。
一种结构化数据编码、解码ASN.1报文的设计方法

基础数据类型设计

基础的数据结构有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个字节。
一种结构化数据编码、解码ASN.1报文的设计方法

复合的数据结构有yl_BYTE_SURE_array,yl_BYTE_UNSURE_array,yl_choice,yl_struct,yl_struct_of,共5种,分别为定长BYTE数组,不定长BYTE数组,choice选择,结构体,结构体数组。复合数据结构包含标志、长度、成员数量、选项和数据等成员。
一种结构化数据编码、解码ASN.1报文的设计方法

数据结构的具体定义如下:

编码解码class设计

对外只呈现make和devide两个函数接口。

内部组帧为make*系列的函数,解帧为devide*系列的函数。
一种结构化数据编码、解码ASN.1报文的设计方法

源码

#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;
	}
}
上一篇:【超图+CESIUM】【基础API使用示例】07、超图|CESIUM - 场景颜色设置和校正


下一篇:初识分支语句