アンパックとパックを制御するには、データレイアウト仕様(Bindat型式とも呼ばれます)を記述します。これは基本型、あるいは複数のフィールドからなる複合型であり、この仕様によって処理対象となる各フィールドの長さや、パック・アンパックの方法を制御します。通常、Bindat型の値は名前が-bindat-specで終わる変数に格納します。このような名前は自動的にリスクがあるものとして認識されます(ファイルローカル変数を参照)。
Bindat型の式 typeに従って、Bindat型の値オブジェクトを生成します。
フィールドの型は、そのフィールドが表すオブジェクトのサイズ(バイト単位)と、マルチバイトフィールドの場合にフィールド内でバイトがどのように配置されるかを記述します。考えられる配置方式には、ビッグエンディアン(「ネットワークバイトオーダー」とも呼ばれる)とリトルエンディアンの2種類があります。例えば、数値 #x23cd(10進数で9165)は、ビッグエンディアンでは2バイトの #x23 #xcd となり、リトルエンディアンでは
#xcd #x23
となります。考えられる型の値は以下の通りです。
u8byte長さ1の符号なしバイト。
uint bitlen &optional leネットワークバイトオーダー(ビッグエンディアン)の符号なし整数で、bitlenビット。bitlenは8の倍数である必要がある。leがnilでない場合は、リトルエンディアンのバイトオーダーを使用する。
sint bitlen leネットワークバイトオーダー(ビッグエンディアン)の符号付き整数で、bitlenビット。bitlenは8の倍数である必要がある。leがnil以外の場合は、リトルエンディアンのバイトオーダーを使用する。
str lenUnibyte string (see Text
Representations) of length len bytes. When
packing, the first len bytes of the input string are
copied to the packed output. If the input string is shorter than len, the remaining bytes will be null (zero) unless a
pre-allocated string was provided to bindat-pack,
in which case the remaining bytes are left unmodified. If the input string
is multibyte with only ASCII and eight-bit
characters, it is converted to unibyte before it is packed; other multibyte
strings signal an error. When unpacking, any null bytes in the packed input
string will appear in the unpacked output.
strz &optional lenlen が指定されていない場合、これは可変長のヌル終端ユニバイト文字列となります(テキスト表現を参照)。strz
にパックする場合、入力文字列全体がパック済み出力にコピーされ、その後にヌル(ゼロ)バイトが付加されます。(strz
へのパック用に事前割り当て済みの文字列が指定されている場合、その事前割り当て済み文字列には、出力文字列の内容に付加される追加のヌルバイト分の十分な領域が必要です(バイトのアンパックおよびパック用関数を参照))。パック済み出力の長さは、入力文字列の長さに1(ヌル終端文字分)を加算した値となります。入力文字列にヌルバイトを含めてはなりません。入力文字列が
ASCII および eight-bit
文字のみからなるマルチバイト文字列である場合、パック前にユニバイトに変換されます。それ以外のマルチバイト文字列はエラーとなります。strz
をアンパックする場合、結果として得られる出力文字列には、入力文字列を終端させたヌルバイトまでの(ただしヌルバイト自体は含まない)すべてのバイトが含まれます。
len が指定されている場合、strz は str と同様に動作しますが、いくつか異なる点があります:
注意: 入力文字列が len バイト未満であるか、または先頭の len バイト以内にヌルバイトが含まれていない限り、パックされた出力はヌル終端されません。
vec len [type]len個の要素からなるベクトル。要素の型はtypeで指定され、デフォルトはバイト型です。typeには任意のBindat型式を指定できます。
repeat len [type]vecと同様ですが、リストへの展開およびリストからのパックを行うのに対し、vecはベクトルへの展開を行います。
bits len
len バイト内で 1 に設定されているビットの一覧。バイトはビッグエンディアン順で扱われ、ビットは
8 * len − 1 から始まり 0
で終わる番号が振られる。例えば、bits 2 は #x28 と #x1c を (2 3 4 11 13) に、#x1c と #x28 を (3 5 10 11 12) にアンパックする。
fill len単なる埋め草として使用される len バイト。パッキング時にはこれらのバイトは変更されず、通常は 0
のままとなります。アンパッキング時には単に nil が返されます。
align lenfillと同様ですが、バイト数はlenバイトの次の倍数までスキップするために必要な数となります。
type expこれにより、型を間接的に参照できるようになります。exp は Lisp 式であり、Bindat 型の 値 を返すはずです。
unit expこれは、領域を0ビット消費するトリビアルな型です。expは、このようなフィールドを「アンパック」しようとした際に返される値を表します。
struct fields...複数のフィールドで構成される複合型。各フィールドは (name
type) の形式であり、ここで type
は任意の Bindat 型式となる。name は、align や fill
フィールドでよく見られるように、フィールドの値に名前を付ける必要がない場合に _
とすることができる。コンテキストからこれが Bindat 型式であることが明らかな場合は、記号 struct を省略できる。
上記の型において、len および bitlen は、フィールドのバイト数(またはビット数)を指定する整数として与えられます。フィールドの長さが固定されていない場合、通常は直前のフィールドの値に依存します。このため、長さ len は定数である必要はなく、任意の Lisp 式とすることができ、また名前を介して直前のフィールドの値を参照することも可能です。
例えば、先頭バイトで後続の16ビット整数ベクトルのサイズを示すデータレイアウトの仕様は、以下のようになります:
(bindat-type (len u8) (payload vec (1+ len) uint 16))