Как я могу прочитать 24-битный Int из строки байтов haskell? - PullRequest
4 голосов
/ 05 июня 2011

Я пытаюсь проанализировать двоичный формат (PES), используя 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

Мне нужно прочитать pecstart, чтобы получить смещение других данных (ширина, высота и строчки) Но это не работает для меня, потому что мне нужно прочитать 24-битное значение, а пакет ByteString, похоже, не имеет 24-битной версии.

Должен ли я использовать другой подход? Пакет Data.Binary кажется хорошим для простых форматов, но я не уверен, как он будет работать для чего-то подобного, так как вы должны прочитать значение, чтобы найти смещение других данных в файле. Что-то мне не хватает?

1 Ответ

6 голосов
/ 05 июня 2011

Ну, вы можете разобрать 24-битное значение, проиндексировав 3 байта (здесь в сетевом порядке):

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
...