File: base64.lisp

package info (click to toggle)
araneida 0.90.1-dfsg-2
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 700 kB
  • ctags: 643
  • sloc: lisp: 4,878; perl: 166; sh: 109; makefile: 34
file content (41 lines) | stat: -rw-r--r-- 1,719 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
(in-package :araneida)

;;;; This assumes an ASCII-based character set.  It's not the fastest
;;;; base64 decoder in the world either, I expect - but presently it's
;;;; only used for http basic authentication header decoding 

(defun base64-decode-quad (q)
  (declare (optimize (speed 3)))
  (labels ((lookup (c)
                   (or
                    (position c
                              "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") 0)))
    (destructuring-bind (q1 q2 q3 q4 &rest ignored) q
      (declare (ignore ignored))
      (let ((val (coerce 0 '(unsigned-byte 32))))
        (setf (ldb (byte 6 0) val) (lookup q4))
        (setf (ldb (byte 6 6) val) (lookup q3))
        (setf (ldb (byte 6 12) val) (lookup q2))
        (setf (ldb (byte 6 18) val) (lookup q1))
        (let ((v1 (ldb (byte 8 16) val))
              (v2 (ldb (byte 8 8) val))
              (v3 (ldb (byte 8 0) val)))
          (list (code-char v1) (code-char v2) (code-char v3)))))))

(defun base64-decode (string)
  "Decode the MIME Base64-encoded data in STRING, as per RFC1521 section 5.2"
  ;; (1) Delete all the characters not in the set [A-Za-z0-9+=]
  ;; (2) assert string length is a multiple of 4
  ;; (3) strip all #\= from end of string
  ;; (4) assign each byte a number 0-63 based on its position in the
  ;;    set A-Za-z0-9+/ 
  ;; (5) iterate over the string in 4-character chunks.  For each
  ;;    chunk, output 3 characters
  (let ((len (truncate (* (or (position #\= string) (length string)) .75))))
    (subseq 
     (coerce 
      (loop for q on (coerce string 'list) by #'cddddr
            for out-chunk = (base64-decode-quad q)
            append out-chunk)
      'string)
     0 len)))