1. 程式人生 > >利用開源ASN1C庫實現asn.1的編解碼

利用開源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類似,這裡不做贅述。