1 ######################################################################
3 ## Copyright (C) 2001,2000, 2003
4 ## Department of Computer Science, University of Tromsø, Norway
7 ## Author: Frode Vatvedt Fjeld <frodef@acm.org>
8 ## Created at: Wed Dec 8 15:35:53 1999
9 ## Distribution: See the accompanying file COPYING.
11 ## $Id: README,v 1.1 2004/01/13 11:13:13 ffjeld Exp $
13 ######################################################################
15 Binary-types is a Common Lisp package for reading and writing binary
16 files. Binary-types provides macros that are used to declare the
17 mapping between lisp objects and some binary (i.e. octet-based)
20 Supported kinds of binary types include:
22 * Signed and unsigned integers of any octet-size, big-endian or
23 little-endian. Maps to lisp integers.
25 * Enumerated types based on any integer type. Maps to lisp symbols.
27 * Complex bit-field types based on any integer type. Sub-fields can
28 be numeric, enumerated, or bit-flags. Maps to lisp lists of symbols
31 * Fixed-length and null-terminated strings. Maps to lisp strings.
33 * Compound records of other binary types. Maps to lisp DEFCLASS
34 classes or, when you prefer, DEFSTRUCT structs.
36 Typically, a complete binary record format/type can be specified in a
37 single (nested) declaration statement. Such compound records may then
38 be read and written with READ-BINARY and WRITE-BINARY.
40 Binary-types is *not* helpful in reading files with variable
41 bit-length code-words, such as most compressed file formats. It will
42 basically only work with file-formats based on 8-bit bytes
43 (octets). Also, at this time no floating-point types are supported out
46 Binary types may now be declared with the DEFINE-BINARY-CLASS macro,
47 which has the same syntax (and semantics) as DEFCLASS, only there is
48 an additional slot-option (named :BINARY-TYPE) that declares that
49 slot's binary type. Note that the binary aspects of slots are *not*
50 inherited (the semantics of inheriting binary slots is unclear to me).
52 Another slot-option added by binary-types is :MAP-BINARY-WRITE, which
53 names a function (of two arguments) that is applied to the slot's
54 value and the name of the slot's binary-type in order to obtain the
55 value that is actually passed to WRITE-BINARY. Similarly,
56 :MAP-BINARY-READ takes a function that is to be applied to the binary
57 data and type-name when a record of that type is being read. A
58 slightly modified version of :map-binary-read is
59 :MAP-BINARY-READ-DELAYED, which will do essentially the same thing as
60 :map-binary-read, only the mapping will be "on-demand": A slot-unbound
61 method will be created for this purpose.
63 A variation of the :BINARY-TYPE slot-option is :BINARY-LISP-TYPE,
64 which does everything :BINARY-TYPE does, but also passes on a :TYPE
65 slot-option to DEFCLASS (or DEFSTRUCT). The type-spec is inferred
66 from the binary-type declaration. When using this mechanism, you
67 should be careful to always provide a legal value in the slot (as you
68 must always do when declaring slots' types). If you find this
69 confusing, just use :BINARY-TYPE.
71 Performance has not really been a concern for me while designing this
72 package. There's no obvious performance bottlenecks that I know of,
73 but keep in mind that all "binary" reads and writes are reduced to
74 individual 8-bit READ-BYTEs and WRITE-BYTEs. If you do identify
75 particular performance bottlenecks, let me know.
77 The included file "example.lisp" demonstrates how to use this
78 package. To give you a taste of what it looks like, the following
79 declarations are enough to read the header of an ELF executable file
82 (let ((*endian* :big-endian))
83 (read-binary 'elf-header stream)
86 ;;; ELF basic type declarations
87 (define-unsigned word 4)
88 (define-signed sword 4)
89 (define-unsigned addr 4)
90 (define-unsigned off 4)
91 (define-unsigned half 2)
93 ;;; ELF file header structure
94 (define-binary-class elf-header ()
96 :binary-type (define-binary-struct e-ident ()
97 (ei-magic nil :binary-type
98 (define-binary-struct ei-magic ()
99 (ei-mag0 0 :binary-type u8)
100 (ei-mag1 #\null :binary-type char8)
101 (ei-mag2 #\null :binary-type char8)
102 (ei-mag3 #\null :binary-type char8)))
103 (ei-class nil :binary-type
104 (define-enum ei-class (u8)
108 (ei-data nil :binary-type
109 (define-enum ei-data (u8)
113 (ei-version 0 :binary-type u8)
114 (padding nil :binary-type 1)
115 (ei-name "" :binary-type
116 (define-null-terminated-string ei-name 8))))
118 :binary-type (define-enum e-type (half)
127 :binary-type (define-enum e-machine (half)
136 (e-version :binary-type word)
137 (e-entry :binary-type addr)
138 (e-phoff :binary-type off)
139 (e-shoff :binary-type off)
140 (e-flags :binary-type word)
141 (e-ehsize :binary-type half)
142 (e-phentsize :binary-type half)
143 (e-phnum :binary-type half)
144 (e-shentsize :binary-type half)
145 (e-shnum :binary-type half)
146 (e-shstrndx :binary-type half)))
149 For a second example, here's an approach to supporting floats:
151 (define-bitfield ieee754-single-float (u32)
152 (((:enum :byte (1 31))
155 ((:numeric exponent 8 23))
156 ((:numeric significand 23 0))))
161 The postscript file "type-hierarchy.ps" shows the binary types
162 hierarchy. It is generated using psgraph from the CMU lisp
165 (with-open-file (*standard-output* "type-hierarchy.ps"
167 :if-exists :supersede)
168 (psgraph:psgraph 'binary-type
171 (aclmop:class-direct-subclasses
173 #'(lambda (s) (list (symbol-name s)))