针对asn文件编解码工作,asn1c这个开源工具对c/c++的支持非常好。可以很方便的安装和使用,目前这个工具是开源的,最新版本是0.9.28,项目地址:github.com/vlm/asn1c。官方文档地址:Open Source ASN.1 Compiler: asn1c 0.9.28。
这个工具在linux上的安装很方便。
这个工具还有一个很方便的地方在于,它可以直接将asn文件转化为c语言项目所需要的的头文件和源文件。
下面通过一个简单的示例来演示如何通过asn1c这个工具来实现asn格式数据编解码。
1、准备asn文件:
RectangleTest DEFINITIONS ::= BEGIN
Rectangle ::= SEQUENCE {
height INTEGER,
width INTEGER
}
END
2、在该文件当前目录运行生成命令
asn1c -gen-PER *.asn
运行该命令,会在本目录下生成很多头文件和源代码文件。其中包含一个拥有main主函数的测试代码,一般我们不使用这个源代码来运行示例,自己编写一个。
3、自己编写一个main.c代码如下:
#include
#include
#include "Rectangle.h"
static int write_out(const void *buffer,size_t size,void *key)
{
FILE *out_fp = key;
return (fwrite(buffer,1,size,out_fp)==size)?0:-1;
}
int main()
{
Rectangle_t *rect;
asn_enc_rval_t ec;
rect = calloc(1,sizeof(Rectangle_t));
//init rect
rect->width = 23;
rect->height = 42;
const char* filename = "Test";
FILE *fp = fopen(filename,"wb");
ec = uper_encode(&asn_DEF_Rectangle,rect,write_out,fp);
if(ec.encoded==-1){
printf("encode error.\n");
}else{
printf("encode ok,result in %s.\n",filename);
}
return 0;
}
这段代码很简单,主要定义了一个写入函数,作为uper_encode的回调函数,在这个函数里面,将编码后的结果写入文件,这个文件在本示例里面用Test命名。
4、 编译,运行,如果不出错,那么就是编码成功。这里稍微提一下,编译命令:
gcc -o main -I. *.c
这里的-I.参数指的是,包含本目录。
5、这个结果还不好验证。但是我们可以通过一个asn在线编译器进行验证。 在这个页面,有三个视图,在最左边的视图,我们手动输入我们上面的asn文件内容:
在第二个部分,我们通过json格式把代码中的参数设置进去。
点击第二个试图中的Encode,如果没有报错,那么页面最右侧的第三个控制台输出试图里面就会显示编码结果,各个类型的都会列出来,这里我们关注这个示例中的uper类型,结果是012a0117。
这个是通过三方网站来验证我们的编码结果。
接着我们把linux上的编码结果文件Test下载到windows上,使用notepad++打开,通过hex插件,可以查看16进制表示,结果与上面的编码是一致的:
至此,我们通过一个简单的示例,实现了asn编码。编码类型采用的是uper,因为这个在实际中使用的很广泛。
6、接着改动main.c文件,实现解码功能,大致意思是读取Test文件,然后通过asn1c提供的解码方法uper_decode()解码。代码如下:
#include
#include
#include "Rectangle.h"
int main()
{
Rectangle_t *rect;
asn_dec_rval_t dc;
char buf[20];
rect = calloc(1,sizeof(Rectangle_t));
const char* filename = "Test";
FILE *fp = fopen(filename,"r");
size_t size;
size = fread(buf,1,sizeof buf,fp);
asn_codec_ctx_t *opt_codec_ctx = 0;
dc = uper_decode(opt_codec_ctx,&asn_DEF_Rectangle,(void **)&rect,buf,size,0,0);
if(dc.code==-1){
printf("decode error.\n");
}else{
printf("decode ok,rect's width=%d,height=%d.\n",rect->width,rect->height);
}
return 0;
}
7、编译,运行代码,打印截图如下:
解码成功。