利用開源ASN1C庫實現asn.1的編解碼
最近在研究MMS的時候接觸到了抽象語義記法ASN.1(Abstract Syntax Notation One),於是對它做了一番瞭解,下面將這幾天的學習到的做下記錄,以供以後偷懶。
ASN.1是一種 ISO/ITU-T 標準,描述了一種對資料進行表示、編碼、傳輸和解碼的資料格式。它提供了一整套正規的格式用於描述物件的結構,而不管語言上如何執行及這些資料的具體指代,也不用去管到底是什麼樣的應用程式,也就是說這種記法獨立於程式語言,具有平臺無關性。關於它的更多的介紹百度文庫有很多資源,這裡提供一個 ISO/ITU-T 標準關於本部分標準的連結,全英文看起來是吃力了點,但慢慢品讀下來往往會有想不到的收穫。(http://www.itu.int/ITU-T/recommendations/index.aspx),在search欄輸入x.680~x.683或x.690可以檢視到ASN.1的具體標準及編解碼的方法,或者從http://www.itu.int/ITU-T/studygroups/com17/languages/獲得相關文件。
有了ASN.1和相關編碼的概念之後,接下來就是如何用程式語言實現ASN.1的編解碼了,下面結合開源編譯器ASN1C對這部分做詳細介紹。
一、下載asn.1 編譯器ASN1C
在http://lionet.info/asn1c/download.html處下載,此處我選擇了“Windows installer: asn1c-0.9.21.exe”,下載後雙擊安裝即可。
本文假設安裝於“D:\Program Files\asn1c”。
二、建立asn.1抽象模型並利用ASN1C編譯器生成C語言型別檔案
1、asn.1文字描述如下
點選(此處)摺疊或開啟
RetangleTest DEFINITIONS ::=BEGIN
Rectangle ::= SEQUENCE{
height INTEGER, -- Height of the rectangle
width INTEGER -- Width of the rectangle
}
END
儲存檔案為“D:\Program Files\asn1c\try.asn1"。
2、利用ASN1C工具生成try.asn1的C語言型別檔案
假設ASN1C安裝在“D:\Program Files\asn1c”路徑下,可以按如下步驟生成C語言型別檔案:
①開啟控制檯:"開始-執行-cmd";
②進入到軟體目錄下:cd “D:\Program Files\asn1c”;
③執行生成指令:輸入asn1c -S skeletons -fskeletons-copy -fnative-types try.asn1+回車enter
其中-S -fskeletons-copy -fnative-types引數可以在“D:\Program Files\asn1c\Help\asn1c-usage.pdf”使用手冊查到相關說明。
若執行成功,則有如下資訊輸出到控制檯
並可以看到在“D:\Program Files\asn1c”目錄下,增加了許多檔案,這些檔案都是後面要用到的:
三、在VS2010中建立asn.1的編解碼demo工程
1、建立win32 console工程asn1_demo
2、將步驟二生成的所有.h和.c檔案拷貝到asn1_demo工程資料夾下
3、將.h和.c檔案新增到工程中
4、建立main.c檔案,內容如下
點選(此處)摺疊或開啟
#include
#include
#include
char tab[8];
/*
* This is a custom function which writes the
* encoded output into a global test table
*/
static int decode_callback(const void *buffer, size_t size, void *app_key)
{
static int i = 0;
memcpy(&tab[i],buffer,size);
i += size;
}
int main()
{
Rectangle_t *rectangle; /* Type to encode */
asn_enc_rval_t ec; /* Encoder return value */
/* Allocate the Rectangle_t */
rectangle = (Rectangle_t*)calloc(1, sizeof(Rectangle_t)); /* not */
if(!rectangle) {
perror("calloc() failed");
exit(71); /* better, EX_OSERR */
}
/* Initialize the Rectangle members */
rectangle->height = 42; /* any random value */
rectangle->width = 23; /* any random value */
/* Encode the Rectangle type as BER (DER) */
ec = der_encode(&asn_DEF_Rectangle,
rectangle, decode_callback, tab);
if(ec.encoded == -1) {
fprintf(stderr,
"Could not encode Rectangle (at %s)\n",
ec.failed_type ? ec.failed_type->name : "unknown");
exit(65); /* better, EX_DATAERR */
} else {
fprintf(stderr, "Created %s with BER encoded Rectangle\n",
"");
}
/* Also print the constructed Rectangle XER encoded (XML) */
xer_fprint(stdout, &asn_DEF_Rectangle, rectangle);
return 0;
}
5、移除converter-sample.c
6、編譯,若出現標頭檔案找不到問題,在工程屬性的標頭檔案包含路徑下指定標頭檔案路徑即可。
7、執行,將斷點設於最有一句"return 0"處,可看到控制檯顯示如下,該xml格式的資料是55行執行的結果。
此時,觀察全域性陣列table,可以看到裡面的內容即為Rectangle的編碼後的十六進位制資料為 30 06 02 01 2a 02 01 17。
四、解碼
解碼的example可檢視使用者手冊“D:\Program Files\asn1c\Help\asn1c-usage.pdf”,和編碼example類似,這裡不做贅述。