Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Reading Binary Files: Best Practices?

143 views
Skip to first unread message

Bob Felts

unread,
Dec 14, 2008, 12:38:13 AM12/14/08
to
Seibel's book, PCL, has a section on parsing binary files. He gives an
example of reading an unsigned 16-bit thing:

(defun read-ui16 (stream)
(let ((ui16 0))
(setf (ldb (byte 8 8) ui16) (read-byte stream))
(setf (ldb (byte 8 0) ui16) (read-byte stream))
ui16))

So far, so good. How would a Lisp expert read a signed 16-bit thing?

One might, for example, write (sign-ui16 (read-ui16 stream)), where
sign-ui16 is defined as follows:

(defun sign-ui16 (n)
(if (zerop (ldb (byte 1 15) n))
n
(- (1+ (logxor #xffff n)))))

If the sign-bit is zero, return the number. If it's set, return -(~n +
1). (Note: lognot doesn't work - it has to be logxor).

Any suggestions on a better way to do this?

Madhu

unread,
Dec 14, 2008, 1:12:42 AM12/14/08
to

* (Bob Felts) <1irwxg6.14vwqbobbbm70N%wr...@stablecross.com> :
Wrote on Sun, 14 Dec 2008 00:38:13 -0500:

| (defun sign-ui16 (n)
| (if (zerop (ldb (byte 1 15) n))
| n
| (- (1+ (logxor #xffff n)))))
|
| If the sign-bit is zero, return the number. If it's set, return -(~n +
| 1). (Note: lognot doesn't work - it has to be logxor).
|
| Any suggestions on a better way to do this?

Here is general code from Pascal Bourguignon

(defun unsigned-to-signed/2-complement (x width)
(declare (integer x width))
(let ((maxpos+1 (expt 2 (1- width))))
(if (< x maxpos+1) x (- x (* 2 maxpos+1)))))

Most of the code I've seen which reads signed 16bit words is along these
lines: declare the variable to be an unsigned-byte 16, check and
subtract 65536, or just return n.

This does not address how n was read from the external file, endianness
in which the file was stored. For parsing binary files I've been using
frodef's excellent

<URL:http://www.cs.uit.no/~frodef/sw/binary-types/>

(from even before PCL came out.) There you'd do

(read-binary 's16 stream)

--
Madhu

Zach Beane

unread,
Dec 14, 2008, 9:35:52 AM12/14/08
to
wr...@stablecross.com (Bob Felts) writes:

> So far, so good. How would a Lisp expert read a signed 16-bit thing?
>
> One might, for example, write (sign-ui16 (read-ui16 stream)), where
> sign-ui16 is defined as follows:
>
> (defun sign-ui16 (n)
> (if (zerop (ldb (byte 1 15) n))
> n
> (- (1+ (logxor #xffff n)))))
>
> If the sign-bit is zero, return the number. If it's set, return -(~n +
> 1). (Note: lognot doesn't work - it has to be logxor).
>
> Any suggestions on a better way to do this?

Christophe Rhodes showed me this general idea:

(defun sign-sized (n size)
(if (logbitp (1- size) n)
(dpb n (byte size 0) -1)
n))

So:

(defun sign-ui16 (n)
(sign-sized n 16))

Zach

Bob Felts

unread,
Dec 14, 2008, 3:06:32 PM12/14/08
to
Madhu <eno...@meer.net> wrote:

Thanks. Excellent information.

0 new messages