{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE CPP
, NoImplicitPrelude
, BangPatterns
#-}
module GHC.Fingerprint (
Fingerprint(..), fingerprint0,
fingerprintData,
fingerprintString,
fingerprintFingerprints,
getFileHash
) where
import GHC.IO
import GHC.Base
import GHC.Num
import GHC.List
import GHC.Real
import GHC.Show
import Foreign
import Foreign.C
import System.IO
import GHC.Fingerprint.Type
#include "HsBaseConfig.h"
fingerprint0 :: Fingerprint
fingerprint0 :: Fingerprint
fingerprint0 = Word64 -> Word64 -> Fingerprint
Fingerprint 0 0
fingerprintFingerprints :: [Fingerprint] -> Fingerprint
fingerprintFingerprints :: [Fingerprint] -> Fingerprint
fingerprintFingerprints fs :: [Fingerprint]
fs = IO Fingerprint -> Fingerprint
forall a. IO a -> a
unsafeDupablePerformIO (IO Fingerprint -> Fingerprint) -> IO Fingerprint -> Fingerprint
forall a b. (a -> b) -> a -> b
$
[Fingerprint]
-> (Int -> Ptr Fingerprint -> IO Fingerprint) -> IO Fingerprint
forall a b. Storable a => [a] -> (Int -> Ptr a -> IO b) -> IO b
withArrayLen [Fingerprint]
fs ((Int -> Ptr Fingerprint -> IO Fingerprint) -> IO Fingerprint)
-> (Int -> Ptr Fingerprint -> IO Fingerprint) -> IO Fingerprint
forall a b. (a -> b) -> a -> b
$ \len :: Int
len p :: Ptr Fingerprint
p -> do
Ptr Word8 -> Int -> IO Fingerprint
fingerprintData (Ptr Fingerprint -> Ptr Word8
forall a b. Ptr a -> Ptr b
castPtr Ptr Fingerprint
p) (Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
* Fingerprint -> Int
forall a. Storable a => a -> Int
sizeOf ([Fingerprint] -> Fingerprint
forall a. [a] -> a
head [Fingerprint]
fs))
fingerprintData :: Ptr Word8 -> Int -> IO Fingerprint
fingerprintData :: Ptr Word8 -> Int -> IO Fingerprint
fingerprintData buf :: Ptr Word8
buf len :: Int
len = do
Int -> (Ptr MD5Context -> IO Fingerprint) -> IO Fingerprint
forall a b. Int -> (Ptr a -> IO b) -> IO b
allocaBytes SIZEOF_STRUCT_MD5CONTEXT $ \pctxt -> do
c_MD5Init pctxt
c_MD5Update pctxt buf (fromIntegral len)
allocaBytes 16 $ \pdigest -> do
c_MD5Final pdigest pctxt
peek (castPtr pdigest :: Ptr Fingerprint)
fingerprintString :: String -> Fingerprint
fingerprintString :: String -> Fingerprint
fingerprintString str :: String
str = IO Fingerprint -> Fingerprint
forall a. IO a -> a
unsafeDupablePerformIO (IO Fingerprint -> Fingerprint) -> IO Fingerprint -> Fingerprint
forall a b. (a -> b) -> a -> b
$
[Word8] -> (Int -> Ptr Word8 -> IO Fingerprint) -> IO Fingerprint
forall a b. Storable a => [a] -> (Int -> Ptr a -> IO b) -> IO b
withArrayLen [Word8]
word8s ((Int -> Ptr Word8 -> IO Fingerprint) -> IO Fingerprint)
-> (Int -> Ptr Word8 -> IO Fingerprint) -> IO Fingerprint
forall a b. (a -> b) -> a -> b
$ \len :: Int
len p :: Ptr Word8
p ->
Ptr Word8 -> Int -> IO Fingerprint
fingerprintData Ptr Word8
p Int
len
where word8s :: [Word8]
word8s = (Char -> [Word8]) -> String -> [Word8]
forall a b. (a -> [b]) -> [a] -> [b]
concatMap Char -> [Word8]
forall a. Num a => Char -> [a]
f String
str
f :: Char -> [a]
f c :: Char
c = let w32 :: Word32
w32 :: Word32
w32 = Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Char -> Int
ord Char
c)
in [Word32 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32
w32 Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`shiftR` 24),
Word32 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32
w32 Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`shiftR` 16),
Word32 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32
w32 Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`shiftR` 8),
Word32 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
w32]
getFileHash :: FilePath -> IO Fingerprint
getFileHash :: String -> IO Fingerprint
getFileHash path :: String
path = String -> IOMode -> (Handle -> IO Fingerprint) -> IO Fingerprint
forall r. String -> IOMode -> (Handle -> IO r) -> IO r
withBinaryFile String
path IOMode
ReadMode ((Handle -> IO Fingerprint) -> IO Fingerprint)
-> (Handle -> IO Fingerprint) -> IO Fingerprint
forall a b. (a -> b) -> a -> b
$ \h :: Handle
h -> do
Int -> (Ptr MD5Context -> IO Fingerprint) -> IO Fingerprint
forall a b. Int -> (Ptr a -> IO b) -> IO b
allocaBytes SIZEOF_STRUCT_MD5CONTEXT $ \pctxt -> do
c_MD5Init pctxt
processChunks h (\buf size -> c_MD5Update pctxt buf (fromIntegral size))
allocaBytes 16 $ \pdigest -> do
c_MD5Final pdigest pctxt
peek (castPtr pdigest :: Ptr Fingerprint)
where
_BUFSIZE :: Int
_BUFSIZE = 4096
processChunks :: Handle -> (Ptr Word8 -> Int -> IO ()) -> IO ()
processChunks :: Handle -> (Ptr Word8 -> Int -> IO ()) -> IO ()
processChunks h :: Handle
h f :: Ptr Word8 -> Int -> IO ()
f = Int -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. Int -> (Ptr a -> IO b) -> IO b
allocaBytes Int
_BUFSIZE ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \arrPtr :: Ptr Word8
arrPtr ->
let loop :: IO ()
loop = do
Int
count <- Handle -> Ptr Word8 -> Int -> IO Int
forall a. Handle -> Ptr a -> Int -> IO Int
hGetBuf Handle
h Ptr Word8
arrPtr Int
_BUFSIZE
Bool
eof <- Handle -> IO Bool
hIsEOF Handle
h
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
count Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
_BUFSIZE Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
eof) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ String -> IO ()
forall a. String -> a
errorWithoutStackTrace (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$
"GHC.Fingerprint.getFileHash: only read " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
count String -> String -> String
forall a. [a] -> [a] -> [a]
++ " bytes"
Ptr Word8 -> Int -> IO ()
f Ptr Word8
arrPtr Int
count
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not Bool
eof) IO ()
loop
in IO ()
loop
data MD5Context
foreign import ccall unsafe "__hsbase_MD5Init"
c_MD5Init :: Ptr MD5Context -> IO ()
foreign import ccall unsafe "__hsbase_MD5Update"
c_MD5Update :: Ptr MD5Context -> Ptr Word8 -> CInt -> IO ()
foreign import ccall unsafe "__hsbase_MD5Final"
c_MD5Final :: Ptr Word8 -> Ptr MD5Context -> IO ()