How can I read a 24-bit int from an outtestring from haskell?

I am trying to parse binary format (PES) using Haskell:

import qualified Data.ByteString.Lazy as BL
import Data.Word
import Data.Word.Word24
import qualified Data.ByteString.Lazy.Char8 as L8

data Stitch = MyCoord Int Int deriving (Eq, Show)

data PESFile = PESFile {
      pecstart :: Word24
    , width :: Int
    , height :: Int
    , numColors :: Int
    , header :: String
    , stitches :: [Stitch]
    } deriving (Eq, Show)


readPES :: BL.ByteString -> Maybe PESFile
readPES bs =
        let s = L8.drop 7 bs
            pecstart = L8.readInt s in
            case pecstart of
        Nothing -> Nothing
        Just (offset,rest) ->   Just (PESFile offset 1 1 1 "#PES" [])

main = do
  input <- BL.getContents
  print $ readPES input

I need to read pecstart to get the offset of other data (width, height and verses) But this does not work for me, because I need to read a 24-bit value, and the ByteString package does not seem to have a 24-bit version.

Should I use a different approach? The Data.Binary package seems good for simple formats, but I'm not sure how it will work for something like this, since you need to read the value to find the offset of other data in the file. Is something missing?

+3
source share
1 answer

Well, you can parse a 24-bit value by indexing 3 bytes (here in network order):

import qualified Data.ByteString as B
import Data.ByteString (ByteString, index)
import Data.Bits
import Data.Int
import Data.Word

type Int24 = Int32

readInt24 :: ByteString -> (Int24, ByteString)
readInt24 bs = (roll [a,b,c], B.drop 3 bs)
   where a = bs `index` 0
         b = bs `index` 1
         c = bs `index` 2

roll :: [Word8] -> Int24
roll   = foldr unstep 0
  where
    unstep b a = a `shiftL` 8 .|. fromIntegral b
+5
source

All Articles