diff 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
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/clojure/contrib/base64.clj	Sat Aug 21 06:25:44 2010 -0400
     1.3 @@ -0,0 +1,99 @@
     1.4 +;;; base64.clj: Experimental Base-64 encoding and (later) decoding
     1.5 +
     1.6 +;; by Stuart Sierra, http://stuartsierra.com/
     1.7 +;; August 19, 2009
     1.8 +
     1.9 +;; Copyright (c) Stuart Sierra, 2009. All rights reserved.  The use
    1.10 +;; and distribution terms for this software are covered by the Eclipse
    1.11 +;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
    1.12 +;; which can be found in the file epl-v10.html at the root of this
    1.13 +;; distribution.  By using this software in any fashion, you are
    1.14 +;; agreeing to be bound by the terms of this license.  You must not
    1.15 +;; remove this notice, or any other, from this software.
    1.16 +
    1.17 +
    1.18 +(ns ^{:doc "Base-64 encoding and (maybe later) decoding.  
    1.19 +
    1.20 +  This is mainly here as an example.  It is much slower than the
    1.21 +  Apache Commons Codec implementation or sun.misc.BASE64Encoder."
    1.22 +       :author "Stuart Sierra"}
    1.23 +    clojure.contrib.base64
    1.24 +  (:import (java.io InputStream Writer ByteArrayInputStream
    1.25 +                    StringWriter)))
    1.26 +
    1.27 +(def *base64-alphabet*
    1.28 +     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=")
    1.29 +
    1.30 +(defn encode
    1.31 +  "Encodes bytes of input, writing Base 64 text on output.  alphabet
    1.32 +  is a 65-character String containing the 64 characters to use in the
    1.33 +  encoding; the 65th character is the pad character.  line-length is
    1.34 +  the maximum number of characters per line, nil for no line breaks."
    1.35 +  [^InputStream input ^Writer output ^String alphabet line-length]
    1.36 +  (let [buffer (make-array Byte/TYPE 3)]
    1.37 +    (loop [line 0]
    1.38 +      (let [len (.read input buffer)]
    1.39 +        (when (pos? len)
    1.40 +          ;; Pre-boxing the bytes as Integers is more efficient for
    1.41 +          ;; Clojure's bit operations.
    1.42 +          (let [b0 (Integer/valueOf (int (aget buffer 0)))
    1.43 +                b1 (Integer/valueOf (int (aget buffer 1)))
    1.44 +                b2 (Integer/valueOf (int (aget buffer 2)))]
    1.45 +            (cond (= len 3)
    1.46 +                  (let [s0 (bit-and 0x3F (bit-shift-right b0 2))
    1.47 +                        s1 (bit-and 0x3F
    1.48 +                                    (bit-or (bit-shift-left b0 4)
    1.49 +                                            (bit-shift-right b1 4)))
    1.50 +                        s2 (bit-and 0x3F
    1.51 +                                    (bit-or (bit-shift-left b1 2)
    1.52 +                                            (bit-shift-right b2 6)))
    1.53 +                        s3 (bit-and 0x3F b2)]
    1.54 +                    (.append output (.charAt alphabet s0))
    1.55 +                    (.append output (.charAt alphabet s1))
    1.56 +                    (.append output (.charAt alphabet s2))
    1.57 +                    (.append output (.charAt alphabet s3)))
    1.58 +
    1.59 +                  (= len 2)
    1.60 +                  (let [s0 (bit-and 0x3F (bit-shift-right b0 2))
    1.61 +                        s1 (bit-and 0x3F
    1.62 +                                    (bit-or (bit-shift-left b0 4)
    1.63 +                                            (bit-shift-right b1 4)))
    1.64 +                        s2 (bit-and 0x3F (bit-shift-left b1 2))]
    1.65 +                    (.append output (.charAt alphabet s0))
    1.66 +                    (.append output (.charAt alphabet s1))
    1.67 +                    (.append output (.charAt alphabet s2))
    1.68 +                    (.append output (.charAt alphabet 64)))
    1.69 +
    1.70 +                  (= len 1)
    1.71 +                  (let [s0 (bit-and 0x3F (bit-shift-right b0 2))
    1.72 +                        s1 (bit-and 0x3F (bit-shift-left b0 4))]
    1.73 +                    (.append output (.charAt alphabet s0))
    1.74 +                    (.append output (.charAt alphabet s1))
    1.75 +                    (.append output (.charAt alphabet 64))
    1.76 +                    (.append output (.charAt alphabet 64)))))
    1.77 +            (if (and line-length (> (+ line 4) line-length))
    1.78 +              (do (.append output \newline)
    1.79 +                  (recur 0))
    1.80 +              (recur (+ line 4))))))))
    1.81 +
    1.82 +(defn encode-str
    1.83 +  "Encodes String in base 64; returns a String.  If not specified,
    1.84 +  encoding is UTF-8 and line-length is nil."
    1.85 +  ([s] (encode-str s "UTF-8" nil))
    1.86 +  ([^String s ^String encoding line-length]
    1.87 +     (let [output (StringWriter.)]
    1.88 +       (encode (ByteArrayInputStream. (.getBytes s encoding))
    1.89 +               output *base64-alphabet* line-length)
    1.90 +       (.toString output))))
    1.91 +
    1.92 +
    1.93 +;;; tests 
    1.94 +
    1.95 +;; (deftest t-encode-str
    1.96 +;;   (is (= (encode-str "") ""))
    1.97 +;;   (is (= (encode-str "f") "Zg=="))
    1.98 +;;   (is (= (encode-str "fo") "Zm8="))
    1.99 +;;   (is (= (encode-str "foo") "Zm9v"))
   1.100 +;;   (is (= (encode-str "foob") "Zm9vYg=="))
   1.101 +;;   (is (= (encode-str "fooba") "Zm9vYmE="))
   1.102 +;;   (is (= (encode-str "foobar") "Zm9vYmFy")))