module MD5 where

import Int
import Ptr
import MarshalAlloc
import CString
import CTypes
import IOExts
import Storable (pokeByteOff)

type MD5_STATE = ()
type MD5_DIGEST = Ptr CChar

foreign import ccall "md5.h md5_init"
  md5_init   :: Ptr MD5_STATE -> IO ()
foreign import ccall "md5.h md5_append" 
  md5_append :: Ptr MD5_STATE -> Ptr CChar -> Int32 -> IO ()
foreign import ccall "md5.h md5_finish"
  md5_finish :: Ptr MD5_STATE -> MD5_DIGEST -> IO ()

-- |compute MD5 hash in one go
md5small :: String -> String
md5small str =
  unsafePerformIO $
  do md5_state <- mallocBytes (2*4 + 4*4 + 64)
     md5_digest <- mallocBytes 16
     md5_init md5_state
     n <- newCString str
     md5_append md5_state n (fromIntegral (length str))
     md5_finish md5_state md5_digest
     peekCStringLen (md5_digest, 16)

-- |compute MD5 hash by peeling off parts of 512 characters
md5sum :: String -> String
md5sum str =
  unsafePerformIO $
  do md5_state <- mallocBytes (2*4 + 4*4 + 64)
     md5_digest <- mallocBytes 16
     md5_init md5_state
     let loop s = 
	   case splitAt 512 s of
	     (xs, ys) ->
	       do n <- newCString xs
		  md5_append md5_state n (fromIntegral (length xs))
		  case ys of
		    [] -> return ()
		    _  -> loop ys
     loop str
     md5_finish md5_state md5_digest
     peekCStringLen (md5_digest, 16)

-- |compute MD5 hash byte-wise
md5mus :: String -> String
md5mus str =
  unsafePerformIO $
  do md5_state <- mallocBytes (2*4 + 4*4 + 64)
     md5_digest <- mallocBytes 16
     stringbuffer <- mallocBytes 512
     md5_init md5_state
     let loop [] i = 
	   if i==0 then
	     return ()
	   else
	     md5_append md5_state stringbuffer (fromIntegral i)
	 loop (x:xs) i =
	   let cx = castCharToCChar x in
	   do pokeByteOff stringbuffer i cx
	      next xs (i+1)
	 next xs i =
	   if i==512 then
	     do md5_append md5_state stringbuffer 512
		loop xs 0
	   else loop xs i
     loop str 0
     md5_finish md5_state md5_digest
     peekCStringLen (md5_digest, 16)
