annotate src/clojure/contrib/base64.clj @ 10:ef7dbbd6452c

added clojure source goodness
author Robert McIntyre <rlm@mit.edu>
date Sat, 21 Aug 2010 06:25:44 -0400
parents
children
rev   line source
rlm@10 1 ;;; base64.clj: Experimental Base-64 encoding and (later) decoding
rlm@10 2
rlm@10 3 ;; by Stuart Sierra, http://stuartsierra.com/
rlm@10 4 ;; August 19, 2009
rlm@10 5
rlm@10 6 ;; Copyright (c) Stuart Sierra, 2009. All rights reserved. The use
rlm@10 7 ;; and distribution terms for this software are covered by the Eclipse
rlm@10 8 ;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
rlm@10 9 ;; which can be found in the file epl-v10.html at the root of this
rlm@10 10 ;; distribution. By using this software in any fashion, you are
rlm@10 11 ;; agreeing to be bound by the terms of this license. You must not
rlm@10 12 ;; remove this notice, or any other, from this software.
rlm@10 13
rlm@10 14
rlm@10 15 (ns ^{:doc "Base-64 encoding and (maybe later) decoding.
rlm@10 16
rlm@10 17 This is mainly here as an example. It is much slower than the
rlm@10 18 Apache Commons Codec implementation or sun.misc.BASE64Encoder."
rlm@10 19 :author "Stuart Sierra"}
rlm@10 20 clojure.contrib.base64
rlm@10 21 (:import (java.io InputStream Writer ByteArrayInputStream
rlm@10 22 StringWriter)))
rlm@10 23
rlm@10 24 (def *base64-alphabet*
rlm@10 25 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=")
rlm@10 26
rlm@10 27 (defn encode
rlm@10 28 "Encodes bytes of input, writing Base 64 text on output. alphabet
rlm@10 29 is a 65-character String containing the 64 characters to use in the
rlm@10 30 encoding; the 65th character is the pad character. line-length is
rlm@10 31 the maximum number of characters per line, nil for no line breaks."
rlm@10 32 [^InputStream input ^Writer output ^String alphabet line-length]
rlm@10 33 (let [buffer (make-array Byte/TYPE 3)]
rlm@10 34 (loop [line 0]
rlm@10 35 (let [len (.read input buffer)]
rlm@10 36 (when (pos? len)
rlm@10 37 ;; Pre-boxing the bytes as Integers is more efficient for
rlm@10 38 ;; Clojure's bit operations.
rlm@10 39 (let [b0 (Integer/valueOf (int (aget buffer 0)))
rlm@10 40 b1 (Integer/valueOf (int (aget buffer 1)))
rlm@10 41 b2 (Integer/valueOf (int (aget buffer 2)))]
rlm@10 42 (cond (= len 3)
rlm@10 43 (let [s0 (bit-and 0x3F (bit-shift-right b0 2))
rlm@10 44 s1 (bit-and 0x3F
rlm@10 45 (bit-or (bit-shift-left b0 4)
rlm@10 46 (bit-shift-right b1 4)))
rlm@10 47 s2 (bit-and 0x3F
rlm@10 48 (bit-or (bit-shift-left b1 2)
rlm@10 49 (bit-shift-right b2 6)))
rlm@10 50 s3 (bit-and 0x3F b2)]
rlm@10 51 (.append output (.charAt alphabet s0))
rlm@10 52 (.append output (.charAt alphabet s1))
rlm@10 53 (.append output (.charAt alphabet s2))
rlm@10 54 (.append output (.charAt alphabet s3)))
rlm@10 55
rlm@10 56 (= len 2)
rlm@10 57 (let [s0 (bit-and 0x3F (bit-shift-right b0 2))
rlm@10 58 s1 (bit-and 0x3F
rlm@10 59 (bit-or (bit-shift-left b0 4)
rlm@10 60 (bit-shift-right b1 4)))
rlm@10 61 s2 (bit-and 0x3F (bit-shift-left b1 2))]
rlm@10 62 (.append output (.charAt alphabet s0))
rlm@10 63 (.append output (.charAt alphabet s1))
rlm@10 64 (.append output (.charAt alphabet s2))
rlm@10 65 (.append output (.charAt alphabet 64)))
rlm@10 66
rlm@10 67 (= len 1)
rlm@10 68 (let [s0 (bit-and 0x3F (bit-shift-right b0 2))
rlm@10 69 s1 (bit-and 0x3F (bit-shift-left b0 4))]
rlm@10 70 (.append output (.charAt alphabet s0))
rlm@10 71 (.append output (.charAt alphabet s1))
rlm@10 72 (.append output (.charAt alphabet 64))
rlm@10 73 (.append output (.charAt alphabet 64)))))
rlm@10 74 (if (and line-length (> (+ line 4) line-length))
rlm@10 75 (do (.append output \newline)
rlm@10 76 (recur 0))
rlm@10 77 (recur (+ line 4))))))))
rlm@10 78
rlm@10 79 (defn encode-str
rlm@10 80 "Encodes String in base 64; returns a String. If not specified,
rlm@10 81 encoding is UTF-8 and line-length is nil."
rlm@10 82 ([s] (encode-str s "UTF-8" nil))
rlm@10 83 ([^String s ^String encoding line-length]
rlm@10 84 (let [output (StringWriter.)]
rlm@10 85 (encode (ByteArrayInputStream. (.getBytes s encoding))
rlm@10 86 output *base64-alphabet* line-length)
rlm@10 87 (.toString output))))
rlm@10 88
rlm@10 89
rlm@10 90 ;;; tests
rlm@10 91
rlm@10 92 ;; (deftest t-encode-str
rlm@10 93 ;; (is (= (encode-str "") ""))
rlm@10 94 ;; (is (= (encode-str "f") "Zg=="))
rlm@10 95 ;; (is (= (encode-str "fo") "Zm8="))
rlm@10 96 ;; (is (= (encode-str "foo") "Zm9v"))
rlm@10 97 ;; (is (= (encode-str "foob") "Zm9vYg=="))
rlm@10 98 ;; (is (= (encode-str "fooba") "Zm9vYmE="))
rlm@10 99 ;; (is (= (encode-str "foobar") "Zm9vYmFy")))