haskdeep-0.2.0.1: src/HaskDeep/KnownHash/Reader.hs
{-# LANGUAGE OverloadedStrings #-}
-- |
-- Module : HaskDeep.Computation.Reader
-- Copyright : Mauro Taraborelli 2012
-- License : BSD3
--
-- Maintainer : maurotaraborelli@gmail.com
-- Stability : experimental
-- Portability : unknown
--
-- Computes hashes traversing recursively through a directory structure.
-- Uses a list of known hashes to audit a set of files.
--
-- Internal module.
module HaskDeep.KnownHash.Reader
(
-- * Read the known hashes file
readHashes -- HaskDeepConfiguration -> IO HashSet
)
where
import Control.Applicative ((<*), many)
import Control.Monad (liftM)
import Control.Monad.Trans.Resource (runResourceT)
import Data.Maybe(fromJust)
import Data.Word (Word8)
import Prelude hiding (FilePath)
import Data.Attoparsec (Parser)
import qualified Data.Attoparsec as A
import qualified Data.Attoparsec.Char8 as A8
import qualified Data.Attoparsec.Combinator as AC
import qualified Data.ByteString.Char8 as B8
import Data.Conduit (($$))
import qualified Data.Conduit.Attoparsec as CA
import qualified Data.Conduit.Binary as CB
import Data.Text ()
import qualified Data.Text.Encoding as TE
import System.FilePath ()
import HaskDeep.Configuration
import HaskDeep.HashSet (HashSet, HashInfo(..))
import qualified HaskDeep.HashSet as HS
-- | Read known hashes file into an @HashSet@.
readHashes :: HaskDeepConfiguration -- ^ Configuration
-> IO HashSet -- ^ @HashSet@ red from file
readHashes conf = liftM HS.fromList $ runResourceT
$ CB.sourceFile (knownHashes conf) $$ CA.sinkParser knownHashesP
-- Parsers
knownHashesP :: Parser [HashInfo]
knownHashesP = do _ <- AC.count 2 headerP
_ <- many commentP
AC.many1 fileinfoP
headerP :: Parser ()
headerP = do _ <- A8.string "%%%%"
_ <- A.skipWhile (not . isNewline)
skipNewline
commentP :: Parser ()
commentP = do _ <- A8.char8 '#'
A.skipWhile (not . isNewline)
skipNewline
fileinfoP :: Parser HashInfo
fileinfoP = do sizep <- A.takeTill isComma <* skipComma
hashp <- A.takeTill isComma <* skipComma
filep <- A.takeTill isNewline <* skipNewline
let filep' = TE.decodeUtf8 filep
(sizep', _) = fromJust $ B8.readInteger sizep
return $ HashInfo filep' sizep' hashp
isComma :: Word8 -> Bool
isComma w = w == 44
skipComma :: Parser ()
skipComma = A.skip isComma
isNewline :: Word8 -> Bool
isNewline w = w == 10
skipNewline :: Parser ()
skipNewline = A.skip isNewline