Reading binary output from an external program in Common Lisp

I am trying to run an external program in SBCL and capture its output. The output is binary data (png image), while SBCL insists on interpreting it as strings.

I tried several ways, for example

(trivial-shell:shell-command "/path/to/png-generator" :input "some input")

(with-input-from-string (input "some input")
  (with-output-to-string (output)
    (run-program "/path/to/png-generator" () :input input :output output))


(with-input-from-string (input "some input")
  (flexi-streams:with-output-to-sequence (output)
    (run-program "/path/to/png-generator" () :input input :output output))

But I get errors like

Illegal :UTF-8 character starting at byte position 0.

It seems to me that SBCL is trying to interpret binary data as text and decode it. How to change this behavior? I'm only interested in getting the octet vector.

Edit: since it is not clear from the text above, I would like to add that, at least in the case of a flexi stream, the type of the stream element is flexi-streams:octect(which is (unsigned-byte 8)). I would expect, at least in this case, run-programto read raw bytes without many problems. Instead, I get a message likeDon't know how to copy to stream of element-type (UNSIGNED-BYTE 8)

+5
3

: , .

UNSIGNED-BYTE , . , -, fd , .

, ( ), , : STREAM, . , , ... . , READ-SEQUENCE .

(let* 
       ;; Get random bytes
      ((proc-var (sb-ext:run-program "head" '("-c" "10" "/dev/urandom")
                                     :search t
       ;; let SBCL figure out the storage type. This is what solved the problem.
                                     :output :stream))
       ;; Obtain the streams from the process object.
       (output (process-output proc-var))
       (err (process-error proc-var)))
  (values
   ;;return both stdout and stderr, just for polish.
   ;; do a byte read and turn it into a vector.
   (concatenate 'vector
                ;; A byte with value 0 is *not* value nil. Yay for Lisp!
                (loop for byte = (read-byte output nil)
                   while byte
                   collect byte))
   ;; repeat for stderr
   (concatenate 'vector
                (loop for byte = (read-byte err nil)
                   while byte
                   collect byte))))
+4

, babel. , . : latin-1, 256 . .

stderr, 'with-output-to-sequence' .

(defun safe-shell (command &rest args)                                                                                                           
  (octets-to-string                                                                                                                              
   (with-output-to-sequence (stream :external-format :latin-1)                                                                                   
     (let ((proc (sb-ext:run-program command args :search t :wait t :output stream)))                                                            
       (case (sb-ext:process-status proc)                                                                                                        
         (:exited (unless (zerop (sb-ext:process-exit-code proc))                                                                                
                    (error "Error in command")))                                                                                                 
         (t (error "Unable to terminate process")))))                                                                                            
   :encoding :latin-1))                                                                                                                          
+2
, / , , didn ' t: SBCL - UTF-8, with-{in,out}put-to-string.

, , run-program, . SBCL.

+2
source

All Articles