1

I'm new to Haskell, so I'm probably missing something very simple.

I'm having a supprisingly hard time trying to parse a structured binary stream. The binary stream has varying and conditional parts (like a field which determines how many items follow it (ncount), or what type of message follows it (type)).

To get a simple working example, I'm trying to parse this hypothetical binary structure:

+----------------+---------------+--------------
| Magic (8 bits) | type (3 bits) | type message...
+----------------+---------------+--------------
Type 1:
+----------------+-------------+-------------+-----------------+
|ncount (3 bits) | n1 (3 bits) | n1 (3 bits) | nN (3 bits)...  |
+----------------+-------------+-------------+-----------------+
Type 2:
+----------------+---------------+
|  num1 (7 bits) | num2 (7 bits) |
+----------------+---------------+
...

My code so far:

{-# LANGUAGE RecordWildCards #-}

module Main where

import Data.Bits
import Data.Binary                      as B
import qualified Data.Binary.Bits.Get   as BG
import qualified Data.ByteString        as BS

data Header = Header {
     magic  :: Word8
    ,mtype  :: Word8
    ,num1   :: Word8
    ,num2   :: Word8
} deriving (Show)

--instance Show (Get Header) where
--    show (Header {..}) = show . magic

parse_header :: B.Get Header
parse_header = BG.runBitGet parse_header'

-- Example, assume type 2 for now
parse_header' :: BG.BitGet Header
parse_header' = do
    magic   <- BG.getWord8 8
    mtype   <- BG.getWord8 3
    num1    <- BG.getWord8 7
    num2    <- BG.getWord8 7
    return $ Header magic mtype num1 num2

main :: IO ()
main = do
    putStrLn "Start"

    -- File containing binary stream
    fstr <- BS.readFile "data/hbin.bin"

    let header = parse_header
        in 
            -- How do I print out Header?
            print header
            -- * No instance for (Show (Get Header)) 
            -- arising from a use of `print'
            -- * In the expression: print header

    putStrLn "\nEnd"

In which I get the error:

* No instance for (Show (Get Header)) arising from a use of `print'
* In the expression: print header

Obviously, I plan to parse this recursively, but for now I can't even see a value I've read.

I've followed https://wiki.haskell.org/Dealing_with_binary_data but this uses Data.Binary.Strict (binary-strict) which doesn't compile on Windows (atleast on mine).

I've also followed https://hackage.haskell.org/package/binary-bits-0.5/docs/Data-Binary-Bits-Get.html but it doesn't show how to use values you have gotten with getWord8 (Do I need to put them into an Int to read them as decimal?)

Again, I'm new to Haskell and not familiar with Monads (which I believe Get is).

1 Answer 1

2

header = parse_header is only giving a new name to the parser. You need a function to run the parser, there's one here (here choosing runGet for simplicity, but you should prefer the other one, to handle the error case more easily):

runGet :: Get a -> ByteString -> a

Note that it takes a lazy ByteString (Data.ByteString.Lazy) instead of a strict one (Data.ByteString).

...
import Data.ByteString.Lazy (toLazy)

...

main = do
  fstr <- BS.readFile "data/hbin.bin"
  let header = runGet parse_header (fromStrict fstr)
  print header
  putStrLn "End"
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.