unpackとpackを制御するためには、データレイアウト仕様(data layout
specification)を記述します(Bindatタイプ式(Bindat type
expression)とも呼ばれる)。これにはベースタイプ(base
type)と複数フィールドからなるコンポジットタイプ(composite
type)があり、処理するフィールドそれぞれの長さ、packやunpackを行う方法をこの仕様が制御します。わたしたちはbindatタイプの値を、通常は-bindat-spec
で終わる名前の変数に保持しています。このような種類の名前は、自動的に危険(risky)だと認識されます(ファイルローカル変数を参照)。
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つ異なる点がある:
警告: 入力文字列が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タイプ式を指定できる。align
やfill
のフィールドのように、そのフィールド値が命名に値しない場合には、nameは_
でもよい。コンテキストによりBindatタイプ式であることが明確なら、シンボルstruct
は省略可。
上述のタイプの中で、lenとbitlenはフィールド内のバイト数(またはビット数)を指定する整数として与えられます。そのフィールドが固定長でなければ、通常は値は先行するフィールドの値に依存します。この理由により、lenの長さは定数である必要がないので任意のLisp式を指定することができ、フィールド名から先行するフィールドの値を通じて参照することができるのです。
たとえば先頭のバイトが16ビット整数の後続ベクターにサイズを与えるデータレイアウトの仕様は、以下のようになります:
(bindat-type (len u8) (payload vec (1+ len) uint 16))