{-# LANGUAGE ScopedTypeVariables #-}
module App.Commands.SelectedByBits
( cmdSelectedByBits
) where
import App.Commands.Options.Type
import Control.Lens
import Control.Monad
import Data.Bits (countTrailingZeros)
import Data.Semigroup ((<>))
import Data.Word
import HaskellWorks.Data.Bits.BitWise
import Options.Applicative hiding (columns)
import qualified App.Commands.Options.Lens as L
import qualified Data.ByteString as BS
import qualified Data.ByteString.Builder as B
import qualified Data.ByteString.Lazy as LBS
import qualified Data.ByteString.Unsafe as BS
import qualified Data.Vector.Storable as DVS
import qualified HaskellWorks.Data.ByteString.Lazy as LBS
import qualified HaskellWorks.Data.Vector.AsVector64 as DVS
import qualified System.IO as IO
{-# ANN module ("HLint: ignore Redundant do" :: String) #-}
{-# ANN module ("HLint: ignore Redundant return" :: String) #-}
selectedBytes :: BS.ByteString -> BS.ByteString -> B.Builder
selectedBytes as bs = go (DVS.head (DVS.asVector64 bs)) mempty
where go :: Word64 -> B.Builder -> B.Builder
go w b = if w /= 0
then let i = countTrailingZeros w in
go (w .&. (0xfffffffffffffffe .<. fromIntegral i)) (b <> B.word8 (BS.unsafeIndex as i))
else b
runSelectedByBits :: SelectedByBitsOptions -> IO ()
runSelectedByBits opts = do
let file = opts ^. L.file
let bitFile = opts ^. L.bitFile
chunkedContents <- LBS.toChunks . LBS.rechunkPadded 64 <$> LBS.readFile file
chunkedBitContents <- LBS.toChunks . LBS.rechunkPadded 8 <$> LBS.readFile bitFile
forM_ (zip chunkedContents chunkedBitContents) $ \(byteChunk, bitChunk) -> do
B.hPutBuilder IO.stdout $ selectedBytes byteChunk bitChunk
return ()
optsSelectedByBits :: Parser SelectedByBitsOptions
optsSelectedByBits = SelectedByBitsOptions
<$> strOption
( long "file"
<> help "Source file"
<> metavar "FILE"
)
<*> strOption
( long "bit-file"
<> help "Bit file"
<> metavar "FILE"
)
cmdSelectedByBits :: Mod CommandFields (IO ())
cmdSelectedByBits = command "selected-by-bits" $ flip info idm $ runSelectedByBits <$> optsSelectedByBits