Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 146 lines (131 sloc) 6.395 kb
5263e4b @stuartsierra Base64 decoding from Teemu Antti-Poika; refs #84
stuartsierra authored
1 ;;; base64.clj: Experimental Base-64 encoding and decoding
b086e55 @stuartsierra base64.clj: Base-64 encoding
stuartsierra authored
2
5263e4b @stuartsierra Base64 decoding from Teemu Antti-Poika; refs #84
stuartsierra authored
3 ;; by Stuart Sierra, http://stuartsierra.com/ - encode
b086e55 @stuartsierra base64.clj: Base-64 encoding
stuartsierra authored
4 ;; August 19, 2009
5263e4b @stuartsierra Base64 decoding from Teemu Antti-Poika; refs #84
stuartsierra authored
5 ;; by Teemu Antti-Poika (anttipoi@gmail.com) - decode
6 ;; May 12, 2010
b086e55 @stuartsierra base64.clj: Base-64 encoding
stuartsierra authored
7
8 ;; Copyright (c) Stuart Sierra, 2009. All rights reserved. The use
9 ;; and distribution terms for this software are covered by the Eclipse
10 ;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
11 ;; which can be found in the file epl-v10.html at the root of this
12 ;; distribution. By using this software in any fashion, you are
13 ;; agreeing to be bound by the terms of this license. You must not
14 ;; remove this notice, or any other, from this software.
15
16
5263e4b @stuartsierra Base64 decoding from Teemu Antti-Poika; refs #84
stuartsierra authored
17 (ns ^{:doc "Base-64 encoding and decoding.
7b661cf @stuartsierra base64.clj: added namespace metadata doc
stuartsierra authored
18
19 This is mainly here as an example. It is much slower than the
20 Apache Commons Codec implementation or sun.misc.BASE64Encoder."
21 :author "Stuart Sierra"}
22 clojure.contrib.base64
5263e4b @stuartsierra Base64 decoding from Teemu Antti-Poika; refs #84
stuartsierra authored
23 (:import (java.io InputStream Writer ByteArrayInputStream
24 ByteArrayOutputStream StringReader StringWriter)))
b086e55 @stuartsierra base64.clj: Base-64 encoding
stuartsierra authored
25
26 (def *base64-alphabet*
27 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=")
28
5263e4b @stuartsierra Base64 decoding from Teemu Antti-Poika; refs #84
stuartsierra authored
29 (defn- char-to-index-map
30 []
31 (into {}
32 (map #(vec [(int %1) %2])
33 *base64-alphabet*
34 (iterate inc 0))))
35
b086e55 @stuartsierra base64.clj: Base-64 encoding
stuartsierra authored
36 (defn encode
37 "Encodes bytes of input, writing Base 64 text on output. alphabet
38 is a 65-character String containing the 64 characters to use in the
39 encoding; the 65th character is the pad character. line-length is
40 the maximum number of characters per line, nil for no line breaks."
7188a51 use the 1.2 metadata reader macro ^ instead of #^
Aaron Bedra and Stuart Halloway authored
41 [^InputStream input ^Writer output ^String alphabet line-length]
b086e55 @stuartsierra base64.clj: Base-64 encoding
stuartsierra authored
42 (let [buffer (make-array Byte/TYPE 3)]
43 (loop [line 0]
44 (let [len (.read input buffer)]
45 (when (pos? len)
54a19a9 @stuartsierra base64.clj: performance enhancement for encode
stuartsierra authored
46 ;; Pre-boxing the bytes as Integers is more efficient for
47 ;; Clojure's bit operations.
48 (let [b0 (Integer/valueOf (int (aget buffer 0)))
49 b1 (Integer/valueOf (int (aget buffer 1)))
50 b2 (Integer/valueOf (int (aget buffer 2)))]
b086e55 @stuartsierra base64.clj: Base-64 encoding
stuartsierra authored
51 (cond (= len 3)
54a19a9 @stuartsierra base64.clj: performance enhancement for encode
stuartsierra authored
52 (let [s0 (bit-and 0x3F (bit-shift-right b0 2))
b086e55 @stuartsierra base64.clj: Base-64 encoding
stuartsierra authored
53 s1 (bit-and 0x3F
54a19a9 @stuartsierra base64.clj: performance enhancement for encode
stuartsierra authored
54 (bit-or (bit-shift-left b0 4)
55 (bit-shift-right b1 4)))
b086e55 @stuartsierra base64.clj: Base-64 encoding
stuartsierra authored
56 s2 (bit-and 0x3F
54a19a9 @stuartsierra base64.clj: performance enhancement for encode
stuartsierra authored
57 (bit-or (bit-shift-left b1 2)
58 (bit-shift-right b2 6)))
59 s3 (bit-and 0x3F b2)]
b086e55 @stuartsierra base64.clj: Base-64 encoding
stuartsierra authored
60 (.append output (.charAt alphabet s0))
61 (.append output (.charAt alphabet s1))
62 (.append output (.charAt alphabet s2))
63 (.append output (.charAt alphabet s3)))
64
65 (= len 2)
54a19a9 @stuartsierra base64.clj: performance enhancement for encode
stuartsierra authored
66 (let [s0 (bit-and 0x3F (bit-shift-right b0 2))
b086e55 @stuartsierra base64.clj: Base-64 encoding
stuartsierra authored
67 s1 (bit-and 0x3F
54a19a9 @stuartsierra base64.clj: performance enhancement for encode
stuartsierra authored
68 (bit-or (bit-shift-left b0 4)
69 (bit-shift-right b1 4)))
70 s2 (bit-and 0x3F (bit-shift-left b1 2))]
b086e55 @stuartsierra base64.clj: Base-64 encoding
stuartsierra authored
71 (.append output (.charAt alphabet s0))
72 (.append output (.charAt alphabet s1))
73 (.append output (.charAt alphabet s2))
74 (.append output (.charAt alphabet 64)))
75
76 (= len 1)
54a19a9 @stuartsierra base64.clj: performance enhancement for encode
stuartsierra authored
77 (let [s0 (bit-and 0x3F (bit-shift-right b0 2))
78 s1 (bit-and 0x3F (bit-shift-left b0 4))]
b086e55 @stuartsierra base64.clj: Base-64 encoding
stuartsierra authored
79 (.append output (.charAt alphabet s0))
80 (.append output (.charAt alphabet s1))
81 (.append output (.charAt alphabet 64))
54a19a9 @stuartsierra base64.clj: performance enhancement for encode
stuartsierra authored
82 (.append output (.charAt alphabet 64)))))
b086e55 @stuartsierra base64.clj: Base-64 encoding
stuartsierra authored
83 (if (and line-length (> (+ line 4) line-length))
84 (do (.append output \newline)
85 (recur 0))
86 (recur (+ line 4))))))))
87
88 (defn encode-str
89 "Encodes String in base 64; returns a String. If not specified,
90 encoding is UTF-8 and line-length is nil."
91 ([s] (encode-str s "UTF-8" nil))
7188a51 use the 1.2 metadata reader macro ^ instead of #^
Aaron Bedra and Stuart Halloway authored
92 ([^String s ^String encoding line-length]
b086e55 @stuartsierra base64.clj: Base-64 encoding
stuartsierra authored
93 (let [output (StringWriter.)]
94 (encode (ByteArrayInputStream. (.getBytes s encoding))
95 output *base64-alphabet* line-length)
96 (.toString output))))
97
5263e4b @stuartsierra Base64 decoding from Teemu Antti-Poika; refs #84
stuartsierra authored
98 (defn- get-next-char
99 "Consume and return next character from reader. Ignore and eat end-of-lines characters. Return -1 on end."
100 [reader]
101 (let [c (.read reader)]
102 (if (or (= c 10) (= c 13))
103 (recur reader)
104 c)))
b086e55 @stuartsierra base64.clj: Base-64 encoding
stuartsierra authored
105
5263e4b @stuartsierra Base64 decoding from Teemu Antti-Poika; refs #84
stuartsierra authored
106 (defn decode
107 "Decodes base64-encoded content from str-reader. Writes resulting bytes to out."
108 [^StringReader str-reader ^ByteArrayOutputStream out]
109 (let [next-char (get-next-char str-reader)]
110 (when (not (= next-char -1))
111 (let [c-to-int (char-to-index-map)
112 content-char? (fn [i] (not (= i 64))) ; 64 is index for the pad character =
113 sb0 (c-to-int next-char)
114 sb1 (c-to-int (get-next-char str-reader))
115 sb2 (c-to-int (get-next-char str-reader))
116 sb3 (c-to-int (get-next-char str-reader))
117 _ (when (not (and sb0 sb1 sb2 sb3))
118 (throw (IllegalArgumentException. "Illegal Base64-encoded input: illegal characters or missing padding")))
119 _ (when (not (and (content-char? sb0) (content-char? sb1)))
120 (throw (IllegalArgumentException. "Illegal Base64-encoded input: padding char at illegl position")))
121 b0 (bit-or
122 (bit-shift-left sb0 2)
123 (bit-shift-right (bit-and 0x30 sb1) 4))]
124 (.write out b0)
125 (when (content-char? sb2)
126 (let [b1 (bit-or
127 (bit-shift-left (bit-and 0xF sb1) 4)
128 (bit-shift-right (bit-and 0x3C sb2) 2))]
129 (.write out b1)
130 (when (content-char? sb3)
131 (let [b2 (bit-or
132 (bit-shift-left (bit-and 0x3 sb2) 6)
133 sb3)]
134 (.write out b2)
135 (recur str-reader out)))))))))
136
b086e55 @stuartsierra base64.clj: Base-64 encoding
stuartsierra authored
137
5263e4b @stuartsierra Base64 decoding from Teemu Antti-Poika; refs #84
stuartsierra authored
138 (defn decode-str
139 "Decodes base64-encoded String using encoding. Encoding defaults to UTF-8."
140 ([s] (decode-str s "UTF-8"))
141 ([^String s ^String encoding]
142 (when s
143 (let [baos (ByteArrayOutputStream.)
144 str-reader (StringReader. s)]
145 (decode str-reader baos)
146 (String. (.toByteArray baos) encoding)))))
Something went wrong with that request. Please try again.