Next: , Up: バイト配列のpackとunpack   [Contents][Index]


40.20.1 データレイアウトの記述

unpackとpackを制御するためには、データレイアウト仕様(data layout specification)を記述します(Bindatタイプ式(Bindat type expression)とも呼ばれる)。これにはベースタイプ(base type)と複数フィールドからなるコンポジットタイプ(composite type)があり、処理するフィールドそれぞれの長さ、packやunpackを行う方法をこの仕様が制御します。わたしたちはbindatタイプの値を、通常は-bindat-specで終わる名前の変数に保持しています。このような種類の名前は、自動的に危険(risky)だと認識されます(ファイルローカル変数を参照)。

Macro: bindat-type &rest type

Bindatタイプのであるtypeに応じて、Bindatタイプのオブジェクトを作成する。

フィールドのタイプ(type)はフィールドが表すオブジェクトのサイズ(バイト単位)、およびそれがマルチバイトフィールドならフィールがバイトオーダーされる方法を記述します。可能なオーダーはビッグエンディアン(big endian。ネットワークバイトオーダーとも呼ばれる)、およびリトルエンディアン(little endian)の2つです。たとえば数字#x23cd (10進の9165)のビッグエンディアンは#x23 #xcdの2バイト、リトルエンディアンは#xcd #x23になるでしょう。以下は可能なタイプの値です:

u8
byte

長さ1の符号なしタイプ。

uint bitlen &optional le

長さbitlenビットのネットワークバイトオーダー(ビッグエンディアン)による符号なし整数。bitlenは8の倍数であること。leが非nilなら、リトルエンディアンによるバイトオーダーを使用する。

sint bitlen le

長さbitlenビットのネットワークバイトオーダー(ビッグエンディアン)による符号付き整数。bitlenは8の倍数であること。leが非nilなら、リトルエンディアンによるバイトオーダーを使用する。

str len

長さがlenバイトであるようなユニバイト文字列(テキストの表現方法を参照)。packを行う際には入力文字列の最初のlenバイトがpack済み出力にコピーされる。入力文字列がlenより短い場合には、残りのバイトはnull(0)になる。ただし事前に割り当てた文字列がbindat-packに与えられた場合には、残りのバイトは未変更のまま残される。入力文字列がASCII文字とeight-bit文字だけから構成されたマルチバイト文字列の場合には、packを行う前にユニバイトに変換される。それ以外のマルチバイト文字列の場合にはエラーをシグナルする。unpackを行う際には、pack済み入力文字列中のすべてのnullバイトはunpack済み出力にも出現することになるだろう。

strz &optional len

lenが与えられない場合にはnull終端された可変長ユニバイト文字列である(テキストの表現方法を参照)。strzへpackする際には、入力文字列全体にnull(0)バイトを付加してpack出力にコピーする(strzへのpackに事前割り当て済みの文字列が与えられた場合には、その事前割り当て済み文字列は出力文字列の終端にnullバイトを付加するための十分なスペースをもっている必要がある; バイトのunpackとpackを行う関数を参照)。pack済み出力の長さは、入力文字列の長さに(null終端用の)1を加えた値になる。入力文字列にnullバイトが含まれていてはならない。入力文字列がASCII文字とeight-bit文字だけから構成されたマルチバイト文字列の場合には、packを行う前にユニバイトに変換される。それ以外のマルチバイト文字列の場合にはエラーをシグナルする。strzのunpack時には、入力文字列を終端するnullバイトまで(ただしnullバイト自体は除外)のすべてのバイトが出力文字列に含まれることになる。

lenが与えられた場合にはstrと同じように振る舞うが2つ異なる点がある:

  • pack時に入力文字列の文字数がlenより短ければpackした入力文字列の後にnull終端が書き込まれる。
  • unpack時にはpack済み文字列d最初に見つかったnullバイトはバイトの終端とみなされて、そのnullバイトと後続のバイトはunpackの結果から除外される。

警告: 入力文字列がlenより短かったり、最初のlenバイトにnullバイトが含まれている場合のみ、pack済出力がnull終端される。

vec len [type]

len要素のベクター。要素のタイプはtypeにより与えられる(デフォルトはバイト)。typeは任意のBindatタイプ式を指定できる。

repeat len [type]

vecと同様だがリストから双方向にunpack/packする(vecはunpackするベクター)。

bits len

lenバイト内で1にセットされたビットのリスト。バイトはビッグエンディアンオーダーで、ビットは8 * len - 1で始まり0で終わるよう番号が付けされる。たとえばbits 2では、#x28 #x1c(2 3 4 11 13)#x1c #x28(3 5 10 11 12)にunpackされる。

fill len

lenバイトは単なるフィラーとして使用される。これらのバイトはpack時には未変更のままとなり通常は0のままであることを、unpack時には単にnilをリターンすることを意味する。

align len

fillと同様だが、次のlenの倍数バイトまでスキップを要するバイト数である点が異なる。

type exp

これによりタイプを間接的に参照できる。expはBindatタイプvalueをリターンするLisp式であること。

unit exp

これは0ビットのスペースを使用する簡易タイプ。expはそのようなフィールドの“unpack”を試みた際にリターンされる値を記述する。

struct fields...

複数フィールドから構成されるコンポジットタイプ(composite typex: 複合型)。フィールドはそれぞれ(name type)という形式をもち、typeには任意のBindatタイプ式を指定できる。alignfillのフィールドのように、そのフィールド値が命名に値しない場合には、name_でもよい。コンテキストによりBindatタイプ式であることが明確なら、シンボルstructは省略可。

上述のタイプの中で、lenbitlenはフィールド内のバイト数(またはビット数)を指定する整数として与えられます。そのフィールドが固定長でなければ、通常は値は先行するフィールドの値に依存します。この理由により、lenの長さは定数である必要がないので任意のLisp式を指定することができ、フィールド名から先行するフィールドの値を通じて参照することができるのです。

たとえば先頭のバイトが16ビット整数の後続ベクターにサイズを与えるデータレイアウトの仕様は、以下のようになります:

(bindat-type
  (len      u8)
  (payload  vec (1+ len) uint 16))