2 ;;; Copyright (c) 2007 Zachary Beane, All Rights Reserved
4 ;;; Redistribution and use in source and binary forms, with or without
5 ;;; modification, are permitted provided that the following conditions
8 ;;; * Redistributions of source code must retain the above copyright
9 ;;; notice, this list of conditions and the following disclaimer.
11 ;;; * Redistributions in binary form must reproduce the above
12 ;;; copyright notice, this list of conditions and the following
13 ;;; disclaimer in the documentation and/or other materials
14 ;;; provided with the distribution.
16 ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED
17 ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20 ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
22 ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 (defun bitstream-callback-missing (&rest args
)
32 (declare (ignore args
))
33 (error "No callback set in bitstream"))
35 (defun merge-bits (code size buffer bits callback
)
36 (declare (type (unsigned-byte 32) code
)
37 (type (integer 0 32) size
)
38 (type bitstream-buffer-bit-count bits
)
39 (type bitstream-buffer buffer
)
40 (type function callback
)
42 ;; BITS represents how many bits have been added to BUFFER so far,
43 ;; so the FLOOR of it by 8 will give both the buffer byte index and
44 ;; the bit index within that byte to where new bits should be
46 (let ((buffer-index (ash bits -
3))
47 (bit (logand #b111 bits
)))
48 ;; The first byte to which new bits are merged might have some
49 ;; bits in it already, so pull it out for merging back in the
50 ;; loop. This only has to be done for the first byte, since
51 ;; subsequent bytes in the buffer will consist solely of bits from
54 ;; The check (PLUSP BIT) is done to make sure that no garbage bits
55 ;; from a previous write are re-used; if (PLUSP BIT) is zero, all
56 ;; bits in the first output byte come from CODE.
57 (let ((merge-byte (if (plusp bit
) (aref buffer buffer-index
) 0))
58 (end #.
+bitstream-buffer-size
+)
59 (result (+ bits size
)))
60 ;; (ceiling (+ bit size) 8) is the total number of bytes touched
62 (dotimes (i (ceiling (+ bit size
) 8))
63 (let ((shift (+ bit
(* i -
8)))
64 (j (+ buffer-index i
)))
65 ;; Buffer filled up in the middle of CODE
67 (funcall callback buffer j
))
68 ;; Merge part of CODE into the buffer
69 (setf (aref buffer
(logand #.
+bitstream-buffer-mask
+ j
))
70 (logior (logand #xFF
(ash code shift
)) merge-byte
))
72 ;; Writing is done, and the buffer is full, so call the callback
73 (when (= result
#.
+bitstream-buffer-bits
+)
74 (funcall callback buffer
#.
+bitstream-buffer-size
+))
75 ;; Return only the low bits of the sum
76 (logand #.
+bitstream-buffer-bitmask
+ result
))))
78 (defun merge-octet (octet buffer bits callback
)
79 (declare (type octet octet
)
80 (type bitstream-buffer buffer
)
81 (type bitstream-buffer-bit-count bits
)
82 (type function callback
)
84 (let ((offset (ceiling bits
8)))
85 ;; End of the buffer beforehand
86 (when (= offset
#.
+bitstream-buffer-size
+)
87 (funcall callback buffer
#.
+bitstream-buffer-size
+)
90 (setf (aref buffer offset
) octet
92 (when (= (1+ offset
) #.
+bitstream-buffer-size
+)
93 (funcall callback buffer
#.
+bitstream-buffer-size
+)
99 (defclass bitstream
()
103 :documentation
"Holds accumulated bits packed into octets.")
107 :documentation
"The number of bits written to the buffer so far.")
111 :documentation
"A function of two arguments, BUFFER and END,
112 that should write out all the data in BUFFER up to END."))
114 :buffer
(make-array +bitstream-buffer-size
+ :element-type
'octet
)
116 :callback
#'bitstream-callback-missing
))
118 (defgeneric write-bits
(code size bitstream
))
119 (defgeneric write-octet
(octet bitstream
))
120 (defgeneric write-octet-vector
(vector bitstream
&key start end
))
121 (defgeneric flush
(bitstream))
123 (defmethod write-bits (code size
(bitstream bitstream
))
124 (setf (bits bitstream
)
125 (merge-bits code size
128 (callback bitstream
))))
130 (defmethod write-octet (octet (bitstream bitstream
))
131 (setf (bits bitstream
)
135 (callback bitstream
))))
137 (defmethod write-octet-vector (vector (bitstream bitstream
) &key
(start 0) end
)
138 ;;; Not efficient in the slightest, but not actually used internally.
139 (let ((end (or end
(length vector
))))
140 (loop for i from start below end
141 do
(write-octet (aref vector i
) bitstream
))))
143 (defmethod flush ((bitstream bitstream
))
144 (let ((end (ceiling (bits bitstream
) 8)))
145 (funcall (callback bitstream
) (buffer bitstream
) end
)
146 (setf (bits bitstream
) 0)))
148 (defmethod reset ((bitstream bitstream
))
149 (fill (buffer bitstream
) 0)
150 (setf (bits bitstream
) 0))