Miki Tebeka avatar Miki Tebeka committed 173d072

Right handling of files etc

Comments (0)

Files changed (3)

   #^{ :author "Miki Tebeka <miki.tebeka@gmail.com>"
       :doc "Message digest algorithms for Clojure"}
   (:use [clojure.string :only (split lower-case)])
-  (:import (java.security MessageDigest Security)))
+  (:import (java.security MessageDigest Security)
+           (java.io FileInputStream File InputStream)))
 
+; Default buffer size for reading
+(def *buffer-size* 1024)
+(def ByteArray (type (make-array Byte/TYPE 0)))
+
+(defn- read-some 
+  "Read some data from reader. Return [data size] if there's more to read,
+  otherwise nil."
+  [reader]
+  (let [buffer (make-array Byte/TYPE *buffer-size*)
+        size (.read reader buffer)]
+    (when (> size 0) [buffer size])))
+
+(defn- byte-seq
+  "Return a sequence of [data size] from reader."
+  [reader]
+  (take-while (complement nil?) (repeatedly (partial read-some reader))))
 
 (defmulti digest
-  "Returns digest for message with given algorithm."
+  "Returns digest for input with given algorithm."
   (fn [algorithm message] (class message)))
 
 (defmethod digest String [algorithm message]
-  (digest algorithm [message]))
+  (digest algorithm (.getBytes message)))
 
-; Code "borrowed" from http://www.holygoat.co.uk/blog/entry/2009-03-26-1
-(defmethod digest :default
-  [algorithm messages]
+(defmethod digest ByteArray [algorithm message]
+  (digest algorithm [[message (count message)]]))
+
+(defmethod digest File [algorithm file]
+  (digest algorithm (FileInputStream. file)))
+
+(defmethod digest InputStream [algorithm reader]
+  (digest algorithm (byte-seq reader)))
+
+; Code "borrowed" from 
+; * http://www.holygoat.co.uk/blog/entry/2009-03-26-1
+; * http://www.rgagnon.com/javadetails/java-0416.html 
+(defmethod digest :default [algorithm chunks]
   (let [algo (MessageDigest/getInstance algorithm)]
     (.reset algo)
-    (dorun (map #(.update algo (.getBytes %)) messages))
+    (dorun (map (fn [[message size]] (.update algo message 0 size)) chunks))
     (.toString (BigInteger. 1 (.digest algo)) 16)))
 
 (defn algorithms []

test/digest_test.clj

 (ns digest-test
   (:use [digest] :reload-all)
   (:use [clojure.string :only (lower-case)])
-  (:use [clojure.test]))
+  (:use [clojure.test])
+  (:import java.io.File))
 
 (deftest md5-test
   (is (= (digest "md5" "foo") "acbd18db4cc2f85cedef654fccc4a4d8")))
 (deftest utils-test
   (for [name (algorithms)]
     (dorun (is (ns-resolve *ns* (symbol (lower-case name)))))))
+
+(def *logo-md5* "38cf20fa3c9dc72be56965eb1c311dfa")
+(def *logo-sha256* 
+  "42c2af2a0509832f39d0cef3ecd1612b7857c55abbe2170470eabb2a0318701c")
+
+(deftest file-test
+  (let [f (File. "test/clojure.png")]
+    (is (= (md5 f) *logo-md5*))
+    (is (= (sha-256 f) *logo-sha256*))))
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.