To control unpacking and packing, you write a data layout
specification, also called a Bindat type expression. This can
be a base type or a composite type made of several fields,
where the specification controls the length of each field to be
processed, and how to pack or unpack it. We normally keep bindat type
values in variables whose names end in -bindat-spec
; that kind
of name is automatically recognized as risky (see File Local Variables).
Creates a Bindat type value object according to the Bindat type expression type.
A field’s type describes the size (in bytes) of the object
that the field represents and, in the case of multibyte fields, how
the bytes are ordered within the field. The two possible orderings
are big endian (also known as “network byte ordering”) and
little endian. For instance, the number #x23cd
(decimal
9165) in big endian would be the two bytes #x23
#xcd
;
and in little endian, #xcd
#x23
. Here are the possible
type values:
u8
byte
Unsigned byte, with length 1.
uint bitlen
Unsigned integer in network byte order, with bitlen bits. bitlen has to be a multiple of 8.
uintr bitlen
Unsigned integer in little endian order, with bitlen bits. bitlen has to be a multiple of 8.
str len
String of bytes of length len.
strz &optional len
Zero-terminated string of bytes, can be of arbitrary length or in a fixed-size field with length len.
vec len [type]
Vector of len elements. The type of the elements is given by type, defaulting to bytes. The type can be any Bindat type expression.
repeat len [type]
Like vec
, but it unpacks to and packs from lists, whereas
vec
unpacks to vectors.
bits len
List of bits that are set to 1 in len bytes. The bytes are
taken in big-endian order, and the bits are numbered starting with
8 * len - 1
and ending with zero. For example:
bits 2
unpacks #x28
#x1c
to (2 3 4 11 13)
and #x1c
#x28
to (3 5 10 11 12)
.
fill len
len bytes used as a mere filler. In packing, these bytes are are left unchanged, which normally means they remain zero. When unpacking, this just returns nil.
align len
Same as fill
except the number of bytes is that needed to skip
to the next multiple of len bytes.
type exp
This lets you refer to a type indirectly: exp is a Lisp expression which should return a Bindat type value.
unit exp
This is a trivial type which uses up 0 bits of space. exp describes the value returned when we try to “unpack” such a field.
struct fields...
Composite type made of several fields. Every field is of the form
(name type)
where type can be any Bindat
type expression. name can be _
when the field’s value
does not deserve to be named, as is often the case for align
and fill
fields.
When the context makes it clear that this is a Bindat type expression,
the symbol struct
can be omitted.
In the types above, len and bitlen are given as an integer specifying the number of bytes (or bits) in the field. When the length of a field is not fixed, it typically depends on the value of preceding fields. For this reason, the length len does not have to be a constant but can be any Lisp expression and it can refer to the value of previous fields via their name.
For example, the specification of a data layout where a leading byte gives the size of a subsequent vector of 16 bit integers could be:
(bindat-type (len u8) (payload vec (1+ len) uint 16))