Commit 330bde31 authored by Jan Idzikowski's avatar Jan Idzikowski
Browse files

fixed wrap at column in base64-encode-file

add #\Return#\Newline after each column
parent f78d701a
...@@ -104,11 +104,11 @@ ...@@ -104,11 +104,11 @@
(generate-message-header (generate-message-header
sock sock
:boundary boundary :boundary boundary
:content-type (format nil "~A;~%~tname*=~A;~%~tname=~S" :content-type (format nil "~A;~%~tname*=~A;~%~tname=\"~A\""
(attachment-mime-type attachment) (attachment-mime-type attachment)
quoted-name* quoted-name) quoted-name* quoted-name)
:content-transfer-encoding "base64" :content-transfer-encoding "base64"
:content-disposition (format nil "attachment; filename*=~A; filename=~S" :content-disposition (format nil "attachment; filename*=~A; filename=\"~A\""
quoted-name* quoted-name)))) quoted-name* quoted-name))))
(defun send-end-marker (sock boundary) (defun send-end-marker (sock boundary)
...@@ -158,78 +158,45 @@ ...@@ -158,78 +158,45 @@
(defun base64-encode-file (file-in sock (defun base64-encode-file (file-in sock
&key &key
(buffer-size 256) ;; in KB (buffer-size 256) ;; in KB
(wrap-at-column 70)) (wrap-at-column 76))
"Encodes the file contents given by file-in, which can be of any form appropriate to with-open-file, and write the base-64 encoded version to sock, which is a socket. "Encodes the file contents given by file-in, which can be of any form appropriate to with-open-file,
and write the base-64 encoded version to sock, which is a socket.
Buffer-size, given in KB, controls how much of the file is processed and written to the socket at one time. A buffer-size of 0, processes the file all at once, regardless of its size. One will have to weigh the speed vs, memory consuption risks when chosing which way is best.
Buffer-size is ignored
Wrap-at-column controls where the encode string is divided for line breaks."
(when (probe-file file-in) Wrap-at-column controls where the encode string is divided for line breaks,
;;-- open filein --------- it is always set to a multiple of 3."
(with-open-file (strm-in file-in (declare (ignore buffer-size))
:element-type '(unsigned-byte 8)) (when (probe-file file-in)
(let* ((;; convert buffer size given to bytes ;;-- open filein ---------
;; or compute bytes based on file (print-debug (format nil "base64-encode-file ~A" file-in))
max-buffer-size (with-open-file (strm-in file-in
(if (zerop buffer-size) :element-type '(unsigned-byte 8))
(file-length strm-in) (let* ((flength (file-length strm-in))
;; Ensures 64 bit encoding is properly (columns (* (truncate (/ wrap-at-column 3)) 3))
;; divided so that filler (r 0)
;; characters are not required between chunks (n 0))
(* 24 (truncate (/ (* buffer-size 1024) 24))))) (loop while (< (file-position strm-in) flength)
(column-count 0) for buffer = (make-array 3
(eof? nil) :element-type '(unsigned-byte 8))
(buffer (make-array max-buffer-size do
:element-type '(unsigned-byte 8)))) (loop for i from 0 to 2 do
(loop (let ((bchar (read-byte strm-in nil 'EOF)))
(print-debug (format nil "~%Process attachment ~a~%" file-in)) (if (eql bchar 'EOF)
(let* ((;; read a portion of the file into the buffer arrary and (progn
;; returns the index where it stopped (setf r i)
byte-count (dotimes (i max-buffer-size max-buffer-size) (return))
(let ((bchar (read-byte strm-in nil 'EOF))) (setf (aref buffer i) bchar))))
(if (eql bchar 'EOF) #+allegro
(progn (write-sequence (excl:usb8-array-to-base64-string
(setq eof? t) (if (> r 0) (subseq buffer 0 r) buffer) :wrap-at-column nil)
(return i)) sock)
(setf (aref buffer i) bchar)))))) #-allegro
(if (zerop buffer-size) (cl-base64:usb8-array-to-base64-stream
;; send file all at once to socket. (if (> r 0) (subseq buffer 0 r) buffer) sock :columns 0)
#+allegro (incf n 3)
(write-string (excl:usb8-array-to-base64-string (when (= (mod n columns) 0)
buffer wrap-at-column) sock) (setf n 0)
#-allegro (write-blank-line sock)))
(cl-base64:usb8-array-to-base64-stream (force-output sock)
buffer sock :columns wrap-at-column) (write-blank-line sock)))))
;; otherwise process file in chunks.
;; The extra encoded-string,
;; and its subseq functions are brute force methods
;; to properly handle the wrap-at-column feature
;; between buffers.
;; Not the most efficient way,
;; but it works and uses existing functions
;; in the cl-base64 package.
(let* ((;; drops off extra elements that were not filled in in reading, this is important for lisp systems that default a value into
;; the array when it is created. -- ie Lispworks, SBCL
trimmed-buffer (if eof?
(subseq buffer 0 byte-count)
buffer))
(encoded-string
#+allegro
(excl:usb8-array-to-base64-string
trimmed-buffer)
#-allegro
(cl-base64:usb8-array-to-base64-string
trimmed-buffer)))
(loop for ch across encoded-string
do (progn
(write-char ch sock)
(incf column-count)
(when (= column-count wrap-at-column)
(setq column-count 0)
(write-char #\Newline sock))))))
(force-output sock)
(print-debug (format nil "~% Eof is ~a~%" eof?))
(when (or (zerop buffer-size)
eof?)
(write-blank-line sock)
(return))))))))
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment