{- | Module : Data.ASN1.BitArray License : BSD-style Copyright : (c) 2010-2013 Vincent Hanquez Stability : experimental Portability : unknown -} module Data.ASN1.BitArray ( BitArray (..) , BitArrayOutOfBound (..) , bitArrayLength , bitArrayGetBit , bitArraySetBitValue , bitArraySetBit , bitArrayClearBit , bitArrayGetData , toBitArray ) where import Control.Exception ( Exception, throw ) import Data.Bits ( clearBit, setBit, testBit ) import Data.ByteString ( ByteString ) import qualified Data.ByteString as B import Data.Maybe ( fromJust ) import Data.Word ( Word64 ) -- | Thrown in case of out of bounds in the bitarray. newtype BitArrayOutOfBound = BitArrayOutOfBound Word64 deriving (Eq, Show) instance Exception BitArrayOutOfBound -- | Represent a bitarray / bitmap. -- -- The memory representation starts at bit 0. data BitArray = BitArray Word64 ByteString deriving (Eq, Show) -- | Returns the length of bits in this bitarray. bitArrayLength :: BitArray -> Word64 bitArrayLength (BitArray l _) = l bitArrayOutOfBound :: Word64 -> a bitArrayOutOfBound n = throw $ BitArrayOutOfBound n -- | Get the nth bits. bitArrayGetBit :: BitArray -> Word64 -> Bool bitArrayGetBit (BitArray l d) n | n >= l = bitArrayOutOfBound n | otherwise = flip testBit (7-fromIntegral bitn) $ B.index d (fromIntegral offset) where (offset, bitn) = n `divMod` 8 -- | Set the nth bit to the value specified. bitArraySetBitValue :: BitArray -> Word64 -> Bool -> BitArray bitArraySetBitValue (BitArray l d) n v | n >= l = bitArrayOutOfBound n | otherwise = let (before, after) = B.splitAt (fromIntegral offset) d in -- array bound check before prevent fromJust from failing. let (w, remaining) = fromJust $ B.uncons after remaining' = setter w (7-fromIntegral bitn) `B.cons` remaining in BitArray l (before `B.append` remaining') where (offset, bitn) = n `divMod` 8 setter = if v then setBit else clearBit -- | Set the nth bit. bitArraySetBit :: BitArray -> Word64 -> BitArray bitArraySetBit bitarray n = bitArraySetBitValue bitarray n True -- | Clear the nth bit. bitArrayClearBit :: BitArray -> Word64 -> BitArray bitArrayClearBit bitarray n = bitArraySetBitValue bitarray n False -- | Get padded bytestring from the bitarray. bitArrayGetData :: BitArray -> ByteString bitArrayGetData (BitArray _ d) = d -- | Number of bits to skip at the end (padding). toBitArray :: ByteString -> Int -> BitArray toBitArray l toSkip = BitArray (fromIntegral (B.length l * 8 - fromIntegral toSkip)) l