Attoparsec makes parsing binary data trivial. Assuming these definitions:
import Data.Attoparsec.ByteString (Parser, eitherResult, parse, take) import Data.Binary.Get (getWord32le, runGet) import Data.ByteString (ByteString, readFile) import Data.ByteString.Char8 (unpack) import Data.ByteString.Lazy (fromStrict) import Prelude hiding (readFile, take) -- The DIB section from a bitmap header data DIB = BM | BA | CI | CP | IC | PT deriving (Show, Read) type Reserved = ByteString -- The entire bitmap header data Header = Header DIB Int Reserved Reserved Int deriving (Show)
We can parse the header from a bitmap file easily. Here, we have 4 parser functions that represent the header section from a bitmap file:
Firstly, the DIB section can be read by taking the first 2 bytes
dibP :: Parser DIB
dibP = read . unpack <$> take 2
Similarly, the size of the bitmap, the reserved sections and the pixel offset can be read easily too:
sizeP :: Parser Int sizeP = fromIntegral . runGet getWord32le . fromStrict <$> take 4 reservedP :: Parser Reserved reservedP = take 2 addressP :: Parser Int addressP = fromIntegral . runGet getWord32le . fromStrict <$> take 4
which can then be combined into a larger parser function for the entire header:
bitmapHeader :: Parser Header bitmapHeader = do dib <- dibP sz <- sizeP reservedP reservedP offset <- addressP return $ Header dib sz "" "" offset