Как я могу прочитать 24-битное Int из байта строки из haskell?
Я пытаюсь проанализировать двоичный формат (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 ответ
Решение
Ну, вы можете разобрать 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