-- Copyright 2023 Lennart Augustsson -- See LICENSE file for full license. module System.IO.MD5(MD5CheckSum, md5File, md5Handle, md5String, md5Combine) where import Prelude(); import MiniPrelude import Primitives(primPerformIO) import Data.Word import Foreign.C.String import Foreign.Marshal.Alloc import Foreign.Marshal.Array import Foreign.Ptr import System.IO import System.IO.Internal foreign import ccall "md5BFILE" c_md5BFILE :: Ptr BFILE -> Ptr Word -> IO () foreign import ccall "md5String" c_md5String :: CString -> Ptr Word -> IO () foreign import ccall "md5Array" c_md5Array :: Ptr Word -> Ptr Word -> Int -> IO () newtype MD5CheckSum = MD5 [Word] -- either 2*64 bits or 4*32 bits instance Eq MD5CheckSum where MD5 a == MD5 b = a == b instance Ord MD5CheckSum where MD5 a <= MD5 b = a <= b instance Show MD5CheckSum where show (MD5 ws) = "MD5" ++ show ws md5Len :: Int md5Len = 16 -- The MD5 checksum is 16 bytes md5WLen :: Int -- length in words md5WLen = (md5Len * 8) `quot` _wordSize chksum :: (Ptr Word -> IO ()) -> IO MD5CheckSum chksum fn = do buf <- mallocArray md5WLen fn buf wmd5 <- peekArray md5WLen buf free buf return (MD5 wmd5) md5String :: String -> MD5CheckSum md5String s = primPerformIO $ withCAString s $ chksum . c_md5String md5Handle :: Handle -> IO MD5CheckSum md5Handle h = withHandleRd h $ chksum . c_md5BFILE md5File :: FilePath -> IO (Maybe MD5CheckSum) md5File fn = do mh <- openFileM fn ReadMode case mh of Nothing -> return Nothing Just h -> do cs <- md5Handle h hClose h return (Just cs) md5Combine :: [MD5CheckSum] -> MD5CheckSum md5Combine [] = error "md5Combine: empty" md5Combine [m] = m md5Combine ms = primPerformIO $ withArrray [ w | MD5 ws <- ms, w <- ws ] $ \ a -> chksum $ \ w -> c_md5Array a w (length ms * md5Len)