r10069: fix keyword name
[kmrcl.git] / byte-stream.lisp
1 ;;; -*- Syntax: Ansi-Common-Lisp; Base: 10; Mode: lisp; Package: kmrcl -*-
2 ;;;; *************************************************************************
3 ;;;; FILE IDENTIFICATION
4 ;;;;
5 ;;;; Name:          byte-stream.lisp
6 ;;;; Purpose:       Byte array input/output streams
7 ;;;; Programmer:    Kevin M. Rosenberg
8 ;;;; Date Started:  June 2003
9 ;;;;
10 ;;;; $Id$
11 ;;;;
12 ;;;; Works for CMUCL, SBCL, and AllergoCL only
13 ;;;;
14 ;;;; This file, part of KMRCL, is Copyright (c) 2003 by Kevin M. Rosenberg
15 ;;;; and by onShore Development, Inc.
16 ;;;;
17 ;;;; KMRCL users are granted the rights to distribute and use this software
18 ;;;; as governed by the terms of the Lisp Lesser GNU Public License
19 ;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL.
20 ;;;; *************************************************************************
21
22 (in-package #:kmrcl)
23
24 ;; Intial CMUCL version by OnShored. Ported to SBCL by Kevin Rosenberg
25
26 #+(or cmu sbcl)
27 (progn
28 (defstruct (byte-array-output-stream
29              (:include #+cmu system:lisp-stream
30                        #+sbcl sb-impl::file-stream
31                        (bout #'byte-array-bout)
32                        (misc #'byte-array-out-misc))
33              (:print-function %print-byte-array-output-stream)
34              (:constructor make-byte-array-output-stream ()))
35   ;; The buffer we throw stuff in.
36   (buffer (make-array 128 :element-type '(unsigned-byte 8)))
37   ;; Index of the next location to use.
38   (index 0 :type fixnum))
39
40 (defun %print-byte-array-output-stream (s stream d)
41   (declare (ignore s d))
42   (write-string "#<Byte-Array-Output Stream>" stream))
43
44 (setf (documentation 'make-binary-output-stream 'function)
45   "Returns an Output stream which will accumulate all output given it for
46    the benefit of the function Get-Output-Stream-Data.")
47
48 (defun byte-array-bout (stream byte)
49   (let ((current (byte-array-output-stream-index stream))
50         (workspace (byte-array-output-stream-buffer stream)))
51     (if (= current (length workspace))
52         (let ((new-workspace (make-array (* current 2) :element-type '(unsigned-byte 8))))
53           (replace new-workspace workspace)
54           (setf (aref new-workspace current) byte)
55           (setf (byte-array-output-stream-buffer stream) new-workspace))
56         (setf (aref workspace current) byte))
57     (setf (byte-array-output-stream-index stream) (1+ current))))
58
59 (defun byte-array-out-misc (stream operation &optional arg1 arg2)
60   (declare (ignore arg2))
61   (case operation
62     (:file-position
63      (if (null arg1)
64          (byte-array-output-stream-index stream)))
65     (:element-type '(unsigned-byte 8))))
66
67 (defun get-output-stream-data (stream)
68   "Returns an array of all data sent to a stream made by
69 Make-Byte-Array-Output-Stream since the last call to this function and
70 clears buffer."
71   (declare (type byte-array-output-stream stream))
72     (prog1 
73         (dump-output-stream-data stream)
74       (setf (byte-array-output-stream-index stream) 0)))
75
76 (defun dump-output-stream-data (stream)
77   "Returns an array of all data sent to a stream made by
78 Make-Byte-Array-Output-Stream since the last call to this function."
79   (declare (type byte-array-output-stream stream))
80   (let* ((length (byte-array-output-stream-index stream))
81          (result (make-array length :element-type '(unsigned-byte 8))))
82     (replace result (byte-array-output-stream-buffer stream))
83     result))
84
85 ) ; progn
86
87
88 #+(or cmu sbcl)
89 (progn
90   (defstruct (byte-array-input-stream
91              (:include #+cmu system:lisp-stream
92                        #+sbcl sb-impl::file-stream
93                        (in #'byte-array-inch)
94                        (bin #'byte-array-binch)
95                        (n-bin #'byte-array-stream-read-n-bytes)
96                        (misc #'byte-array-in-misc))
97              (:print-function %print-byte-array-input-stream)
98                                         ;(:constructor nil)
99              (:constructor internal-make-byte-array-input-stream
100                            (byte-array current end)))
101   (byte-array nil :type vector)
102   (current nil)
103   (end nil))
104
105 (defun %print-byte-array-input-stream (s stream d)
106   (declare (ignore s d))
107   (write-string "#<Byte-Array-Input Stream>" stream))
108   
109 (defun byte-array-inch (stream eof-errorp eof-value)
110   (let ((byte-array (byte-array-input-stream-byte-array stream))
111         (index (byte-array-input-stream-current stream)))
112     (cond ((= index (byte-array-input-stream-end stream))
113            #+cmu
114            (eof-or-lose stream eof-errorp eof-value)
115            #+sbcl
116            (sb-impl::eof-or-lose stream eof-errorp eof-value)
117            )
118           (t
119            (setf (byte-array-input-stream-current stream) (1+ index))
120            (aref byte-array index)))))
121
122 (defun byte-array-binch (stream eof-errorp eof-value)
123   (let ((byte-array (byte-array-input-stream-byte-array stream))
124         (index (byte-array-input-stream-current stream)))
125     (cond ((= index (byte-array-input-stream-end stream))
126            #+cmu
127            (eof-or-lose stream eof-errorp eof-value)
128            #+sbcl
129            (sb-impl::eof-or-lose stream eof-errorp eof-value)
130            )
131           (t
132            (setf (byte-array-input-stream-current stream) (1+ index))
133            (aref byte-array index)))))
134
135 (defun byte-array-stream-read-n-bytes (stream buffer start requested eof-errorp)
136   (declare (type byte-array-input-stream stream))
137   (let* ((byte-array (byte-array-input-stream-byte-array stream))
138          (index (byte-array-input-stream-current stream))
139          (available (- (byte-array-input-stream-end stream) index))
140          (copy (min available requested)))
141     (when (plusp copy)
142       (setf (byte-array-input-stream-current stream)
143         (+ index copy))
144       #+cmu
145       (system:without-gcing
146        (system::system-area-copy (system:vector-sap byte-array)
147                          (* index vm:byte-bits)
148                          (if (typep buffer 'system::system-area-pointer)
149                              buffer
150                              (system:vector-sap buffer))
151                          (* start vm:byte-bits)
152                          (* copy vm:byte-bits)))
153       #+sbcl
154       (sb-sys:without-gcing
155        (sb-kernel:system-area-copy (sb-sys:vector-sap byte-array)
156                          (* index sb-vm:n-byte-bits)
157                          (if (typep buffer 'sb-sys::system-area-pointer)
158                              buffer
159                              (sb-sys:vector-sap buffer))
160                          (* start sb-vm:n-byte-bits)
161                          (* copy sb-vm:n-byte-bits))))
162     (if (and (> requested copy) eof-errorp)
163         (error 'end-of-file :stream stream)
164         copy)))
165
166 (defun byte-array-in-misc (stream operation &optional arg1 arg2)
167   (declare (ignore arg2))
168   (case operation
169     (:file-position
170      (if arg1
171          (setf (byte-array-input-stream-current stream) arg1)
172          (byte-array-input-stream-current stream)))
173     (:file-length (length (byte-array-input-stream-byte-array stream)))
174     (:unread (decf (byte-array-input-stream-current stream)))
175     (:listen (or (/= (the fixnum (byte-array-input-stream-current stream))
176                      (the fixnum (byte-array-input-stream-end stream)))
177                  :eof))
178     (:element-type 'base-char)))
179   
180 (defun make-byte-array-input-stream (buffer &optional (start 0) (end (length buffer)))
181   "Returns an input stream which will supply the bytes of BUFFER between
182   Start and End in order."
183   (internal-make-byte-array-input-stream buffer start end))
184
185 ) ;; progn
186
187
188 ;;; Simple streams implementation by Kevin Rosenberg
189
190 #+allegro
191 (progn
192
193   (defclass extendable-buffer-output-stream (excl:buffer-output-simple-stream)
194     ()
195     )
196
197   (defun make-byte-array-output-stream ()
198     "Returns an Output stream which will accumulate all output given it for
199    the benefit of the function Get-Output-Stream-Data."
200     (make-instance 'extendable-buffer-output-stream
201       :buffer (make-array 128 :element-type '(unsigned-byte 8))
202       :external-form :octets))
203
204   (defun get-output-stream-data (stream)
205     "Returns an array of all data sent to a stream made by
206 Make-Byte-Array-Output-Stream since the last call to this function
207 and clears buffer."
208     (prog1 
209         (dump-output-stream-data stream)
210       (file-position stream 0)))
211   
212   (defun dump-output-stream-data (stream)
213     "Returns an array of all data sent to a stream made by
214 Make-Byte-Array-Output-Stream since the last call to this function."
215     (force-output stream)
216     (let* ((length (file-position stream))
217            (result (make-array length :element-type '(unsigned-byte 8))))
218       (replace result (slot-value stream 'excl::buffer))
219       result))
220   
221   (defmethod excl:device-extend ((stream extendable-buffer-output-stream)
222                                  need action)
223     (declare (ignore action))
224     (let* ((len (file-position stream))
225            (new-len (max (+ len need) (* 2 len)))
226            (old-buf (slot-value stream 'excl::buffer))
227            (new-buf (make-array new-len :element-type '(unsigned-byte 8))))
228       (declare (fixnum len)
229                (optimize (speed 3) (safety 0)))
230       (dotimes (i len)
231         (setf (aref new-buf i) (aref old-buf i)))
232       (setf (slot-value stream 'excl::buffer) new-buf)
233       (setf (slot-value stream 'excl::buffer-ptr) new-len)
234       )
235     t)
236   
237 )
238
239 #+allegro
240 (progn
241   (defun make-byte-array-input-stream (buffer &optional (start 0)
242                                                         (end (length buffer)))
243     (excl:make-buffer-input-stream buffer start end :octets))
244   ) ;; progn