1. Miki Tebeka
  2. clj-digest


Miki Tebeka  committed 173d072

Right handling of files etc

  • Participants
  • Parent commits 018ca2f
  • Branches default

Comments (0)

Files changed (3)

File src/digest.clj

View file
  • Ignore whitespace
   #^{ :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 []

File test/clojure.png

  • Ignore whitespace
New image

File test/digest_test.clj

View file
  • Ignore whitespace
 (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*))))