Capstone
Capstone

Reputation: 2282

How to get a Stream from a Bit Vector in Common Lisp?

I have a bit vector - #*10010010001001...

I'd like to use READ-BYTE to read off octets from the vector. But it needs a binary stream object.

I can't seem to figure out how to do this. I tried using WRITE-SEQUENCE to get a new stream from a simple vector (converted from bit vector):

(WRITE-SEQUENCE (map 'array #'identity #*10010010...) *standard-output*)

but it complains about the expected type needing to be CHARACTER.

(I'm using Clozure Common Lisp.)

What am I doing wrong?

(Please don't suggest flexi-streams as an answer. I don't intend to add a whole new library for just one small thing.)

Upvotes: 3

Views: 1386

Answers (1)

jkiiski
jkiiski

Reputation: 8411

You can use the non-standard Gray Streams extension to define your own stream classes. A simple example for octet vectors (I'm using SBCL, but CCL should support Gray Streams too):

(deftype octet () '(unsigned-byte 8))

(defclass octet-input-stream (fundamental-binary-input-stream)
  ((data :initarg :data :type (vector octet))
   (position :initform 0)))

(defmethod stream-element-type ((stream octet-input-stream))
  'octet)

(defmethod stream-read-byte ((stream octet-input-stream))
  (with-slots (data position) stream
    (if (< position (length data))
        (prog1 (aref data position)
          (incf position))
        :eof)))

(let* ((arr (make-array 3 :element-type 'octet :initial-contents '(50 100 150)))
       (stream (make-instance 'octet-input-stream :data arr)))
  (loop for octet = (read-byte stream nil nil)
        while octet
        do (format t "~8,'0b~%" octet)))
; 00110010
; 01100100
; 10010110

Regarding your comment about needing to mask bits, there are bit-wise operators in the standard.

(logior 50 #b00001000)
;=> 58

For the printed representation of octet vectors, you can define your own pretty printer dispatch function:

(defun print-octets (stream vector)
  (write-string "#<octet vector:" stream)
  (pprint-newline :mandatory stream)
  (loop for octet across vector
        do (format stream "~8,'0b " octet)
           (pprint-newline :fill stream))
  (pprint-newline :mandatory stream)
  (write-string ">" stream))


CL-USER> (set-pprint-dispatch '(vector (unsigned-byte 8)) #'print-octets)
CL-USER> (make-array 20 :element-type 'octet :initial-contents '(54 123 67 34 65 65 23 98 
                                                                 67 23 54 12 76 123 230 65 
                                                                 23 87 49 10))
#<octet vector:
00110110 01111011 01000011 00100010 01000001 01000001 00010111 01100010
01000011 00010111 00110110 00001100 01001100 01111011 11100110 01000001
00010111 01010111 00110001 00001010
>

Upvotes: 6

Related Questions