Для управления распаковкой и упаковкой вы пишете спецификацию структуры данных, также называемую выражением типа Bindat. Это может быть базовый тип или составной тип, состоящий из нескольких полей, где спецификация контролирует длину каждого поля, которое будет обработано, а также то, как оно будет упаковано или распаковано. Обычно мы храним значения типа bindat в переменных, чьи имена оканчиваются на -bindat-spec; такое имя автоматически распознается как рискованное (см. Локальные переменные файла).
Создает объект типа Bindat, соответствующий выражению типа Bindat type.
Тип поля описывает размер (в байтах) объекта, который представляет поле, а в случае многобайтовых полей — порядок байтов внутри поля. Два возможных порядка — это big endian (также известный как «порядок байтов сети») и little endian. Например, число #x23cd (десятичное 9165) в big endian будет двумя байтами #x23 #xcd; а в little endian — #xcd #x23. Вот возможные значения типов:
u8byteБеззнаковый байт, длина 1.
uint bitlen &optional leБеззнаковое целое число в сетевом порядке байтов (big-endian) с bitlen битами. bitlen должно быть кратно 8. Если le не равно nil, используется порядок байтов little-endian.
sint bitlen leЗнаковое целое число в сетевом порядке байтов (big-endian) с bitlen битами. bitlen должно быть кратно 8. Если le не равно nil, используется порядок байтов little-endian.
str lenОднобайтовая строка (см. Представления текста) длиной len байт. При упаковке первые len байт входной строки копируются в упакованный вывод. Если входная строка короче, чем len, оставшиеся байты будут нулевыми (ноль), если только не была предоставлена предварительно выделенная строка для bindat-pack, в этом случае оставшиеся байты остаются неизменными. Если входная строка многобайтовая, но содержит только символы ASCII и eight-bit, она преобразуется в однобайтовую перед упаковкой; другие многобайтовые строки вызывают ошибку. При распаковке любые нулевые байты во входной упакованной строке появятся в распакованном выводе.
strz &optional lenЕсли len не предоставлен, это однобайтовая строка переменной длины, завершающаяся нулем (см. Представления текста). При упаковке в strz вся входная строка копируется в упакованный вывод, за которой следует нулевой (ноль) байт. (Если для упаковки в strz предоставлена предварительно выделенная строка, эта предварительно выделенная строка должна иметь достаточно места для дополнительного нулевого байта, добавляемого к содержимому выходной строки, см. Функции для распаковки и упаковки байтов). Длина упакованного вывода равна длине входной строки плюс один (для нулевого терминатора). Входная строка не должна содержать нулевых байтов. Если входная строка многобайтовая, но содержит только символы ASCII и eight-bit, она преобразуется в однобайтовую перед упаковкой; другие многобайтовые строки вызывают ошибку. При распаковке strz результирующая выходная строка будет содержать все байты до (но не включая) нулевого байта, который завершил входную строку.
Если len предоставлен, strz ведет себя так же, как str, но с парой отличий:
Внимание: Упакованный вывод не будет иметь нулевого терминатора, если входная строка короче, чем len байт, или если она содержит нулевой байт в пределах первых len байт.
vec len [type]Вектор из len элементов. Тип элементов задается type, по умолчанию — байты. type может быть любым выражением типа Bindat.
repeat len [type]Подобно vec, но распаковывается и упаковывается в списки, тогда как vec распаковывается в векторы.
bits lenСписок битов, установленных в 1 в len байтах. Байты берутся в порядке big-endian, а биты нумеруются, начиная с 8 * len − 1 и заканчивая нулем. Например:
bits 2 распаковывает #x28 #x1c в (2 3 4 11 13)
и #x1c #x28 в (3 5 10 11 12).
fill lenlen байт, используемые просто как заполнитель. При упаковке эти байты остаются неизменными, что обычно означает, что они остаются нулями. При распаковке это просто возвращает nil.
align lenТо же, что и fill, за исключением того, что количество байтов равно тому, что необходимо пропустить до следующего кратного 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))