UTF-8, untabify, whitespaces.
[binary-types.git] / README
1 -*- mode: text; coding: utf-8-unix; -*-
2
3 ######################################################################
4 ##
5 ##    Copyright (C) 2001,2000, 2003
6 ##    Department of Computer Science, University of Tromsø, Norway
7 ##
8 ## Filename:      README
9 ## Author:        Frode Vatvedt Fjeld <frodef@acm.org>
10 ## Created at:    Wed Dec  8 15:35:53 1999
11 ## Distribution:  See the accompanying file COPYING.
12 ##
13 ## $Id: README,v 1.1.1.1 2004/01/13 11:13:13 ffjeld Exp $
14 ##
15 ######################################################################
16
17 Binary-types is a Common Lisp package for reading and writing binary
18 files. Binary-types provides macros that are used to declare the
19 mapping between lisp objects and some binary (i.e. octet-based)
20 representation.
21
22 Supported kinds of binary types include:
23
24  * Signed and unsigned integers of any octet-size, big-endian or
25    little-endian. Maps to lisp integers.
26
27  * Enumerated types based on any integer type. Maps to lisp symbols.
28
29  * Complex bit-field types based on any integer type. Sub-fields can
30    be numeric, enumerated, or bit-flags. Maps to lisp lists of symbols
31    and integers.
32
33  * Fixed-length and null-terminated strings. Maps to lisp strings.
34
35  * Compound records of other binary types. Maps to lisp DEFCLASS
36    classes or, when you prefer, DEFSTRUCT structs.
37
38 Typically, a complete binary record format/type can be specified in a
39 single (nested) declaration statement. Such compound records may then
40 be read and written with READ-BINARY and WRITE-BINARY.
41
42 Binary-types is *not* helpful in reading files with variable
43 bit-length code-words, such as most compressed file formats. It will
44 basically only work with file-formats based on 8-bit bytes
45 (octets). Also, at this time no floating-point types are supported out
46 of the box.
47
48 Binary types may now be declared with the DEFINE-BINARY-CLASS macro,
49 which has the same syntax (and semantics) as DEFCLASS, only there is
50 an additional slot-option (named :BINARY-TYPE) that declares that
51 slot's binary type. Note that the binary aspects of slots are *not*
52 inherited (the semantics of inheriting binary slots is unclear to me).
53
54 Another slot-option added by binary-types is :MAP-BINARY-WRITE, which
55 names a function (of two arguments) that is applied to the slot's
56 value and the name of the slot's binary-type in order to obtain the
57 value that is actually passed to WRITE-BINARY. Similarly,
58 :MAP-BINARY-READ takes a function that is to be applied to the binary
59 data and type-name when a record of that type is being read.  A
60 slightly modified version of :map-binary-read is
61 :MAP-BINARY-READ-DELAYED, which will do essentially the same thing as
62 :map-binary-read, only the mapping will be "on-demand": A slot-unbound
63 method will be created for this purpose.
64
65 A variation of the :BINARY-TYPE slot-option is :BINARY-LISP-TYPE,
66 which does everything :BINARY-TYPE does, but also passes on a :TYPE
67 slot-option to DEFCLASS (or DEFSTRUCT).  The type-spec is inferred
68 from the binary-type declaration. When using this mechanism, you
69 should be careful to always provide a legal value in the slot (as you
70 must always do when declaring slots' types). If you find this
71 confusing, just use :BINARY-TYPE.
72
73 Performance has not really been a concern for me while designing this
74 package. There's no obvious performance bottlenecks that I know of,
75 but keep in mind that all "binary" reads and writes are reduced to
76 individual 8-bit READ-BYTEs and WRITE-BYTEs. If you do identify
77 particular performance bottlenecks, let me know.
78
79 The included file "example.lisp" demonstrates how to use this
80 package. To give you a taste of what it looks like, the following
81 declarations are enough to read the header of an ELF executable file
82 with the form
83
84    (let ((*endian* :big-endian))
85      (read-binary 'elf-header stream)
86
87
88 ;;; ELF basic type declarations
89 (define-unsigned word 4)
90 (define-signed sword  4)
91 (define-unsigned addr 4)
92 (define-unsigned off  4)
93 (define-unsigned half 2)
94
95 ;;; ELF file header structure
96 (define-binary-class elf-header ()
97   ((e-ident
98     :binary-type (define-binary-struct e-ident ()
99            (ei-magic nil :binary-type
100                  (define-binary-struct ei-magic ()
101                    (ei-mag0 0 :binary-type u8)
102                    (ei-mag1 #\null :binary-type char8)
103                    (ei-mag2 #\null :binary-type char8)
104                    (ei-mag3 #\null :binary-type char8)))
105            (ei-class nil :binary-type
106                  (define-enum ei-class (u8)
107                    elf-class-none 0
108                    elf-class-32   1
109                    elf-class-64   2))
110            (ei-data nil :binary-type
111                 (define-enum ei-data (u8)
112                   elf-data-none 0
113                   elf-data-2lsb 1
114                   elf-data-2msb 2))
115            (ei-version 0 :binary-type u8)
116            (padding nil :binary-type 1)
117            (ei-name "" :binary-type
118                 (define-null-terminated-string ei-name 8))))
119    (e-type
120     :binary-type (define-enum e-type (half)
121            et-none 0
122            et-rel  1
123            et-exec 2
124            et-dyn  3
125            et-core 4
126            et-loproc #xff00
127            et-hiproc #xffff))
128    (e-machine
129     :binary-type (define-enum e-machine (half)
130            em-none  0
131            em-m32   1
132            em-sparc 2
133            em-386   3
134            em-68k   4
135            em-88k   5
136            em-860   7
137            em-mips  8))
138    (e-version   :binary-type word)
139    (e-entry     :binary-type addr)
140    (e-phoff     :binary-type off)
141    (e-shoff     :binary-type off)
142    (e-flags     :binary-type word)
143    (e-ehsize    :binary-type half)
144    (e-phentsize :binary-type half)
145    (e-phnum     :binary-type half)
146    (e-shentsize :binary-type half)
147    (e-shnum     :binary-type half)
148    (e-shstrndx  :binary-type half)))
149
150
151 For a second example, here's an approach to supporting floats:
152
153   (define-bitfield ieee754-single-float (u32)
154     (((:enum :byte (1 31))
155        positive 0
156        negative 1)
157       ((:numeric exponent 8 23))
158       ((:numeric significand 23 0))))
159
160
161
162
163 The postscript file "type-hierarchy.ps" shows the binary types
164 hierarchy.  It is generated using psgraph and closer-mop, which may be
165 loaded via Quicklisp as shown below:
166
167     (ql:quickload "psgraph")
168     (ql:quickload "closer-mop")
169
170     (with-open-file (*standard-output* "type-hierarchy.ps"
171                                        :direction :output
172                                        :if-exists :supersede)
173       (psgraph:psgraph *standard-output* 'binary-types::binary-type
174                        (lambda (p)
175                          (mapcar #'class-name
176                                  (closer-mop:class-direct-subclasses
177                                   (find-class p))))
178                        (lambda (s) (list (symbol-name s)))
179                        t))