Обработка подписанных двоичных данных в Haskell без unsafeCoerce - PullRequest
8 голосов
/ 02 марта 2011

Я читаю в структуре из двоичного файла, который содержит 16-битные целые числа со знаком, используя монаду Get из Data.Binary .Мой текущий код выглядит так:

data DetectorStats = DetectorStats Int16 Word8 Word8
                     Word8 Int16 Version Int16 
                     deriving Show

getDetectorStats :: Get DetectorStats
getDetectorStats = do
  productNumber <- getWord16be
  bitPerCoordinate <- getWord8
  energyCapability <- getWord8
  timingCapability <- getWord8
  clockFrequency <- getWord16be
  serialNumber <- getWord16be
  return (DetectorStats (unsafeCoerce productNumber )
                        bitPerCoordinate
                        energyCapability 
                        timingCapability
                        (unsafeCoerce clockFrequency)
                        firmwareVersion
                        (unsafeCoerce serialNumber))

Я не доволен использованием unsafeCoerce , но в Int16 * 1011, похоже, нет способа чтения* напрямую, ни способ конвертировать Word16 в Int16 .Есть ли лучший способ справиться с этим?

Ответы [ 3 ]

8 голосов
/ 02 марта 2011

fromIntegral преобразует Word16 в Int16. Однако вы должны убедиться, что он дает ожидаемый вами результат при подписании.

3 голосов
/ 02 марта 2011

Пакет Data.Convertible должен выполнить то, что вы просите.

Например, для преобразования из Word16 в Int16:

> (convert (6 :: Word16)) :: Int16
6
1 голос
/ 21 февраля 2015

Опираясь на ответ Стивена, мы реализуем функции get и put для Int8, Int16 и Int32, аналогичные существующим для Word8, Word16 и Word32. Мне пока не требуется Int64 или поддержка Host-endian, но их можно добавить:

{-# LANGUAGE RecordWildCards #-}
module GetAndPutForInt
( getInt8
, getInt16be
, getInt16le
, getInt32be
, getInt32le
, putInt8
, putInt16be
, putInt16le
, putInt32be
, putInt32le
) where

import Data.Binary
import Data.Binary.Get
import Data.Binary.Put

import Data.Int
import Data.Word

import qualified Data.ByteString.Lazy as B

getInt8 :: Get Int8
getInt8 = do a <- getWord8
             return $ fromIntegral a
getInt16be :: Get Int16
getInt16be = do a <- getWord16be
                return $ fromIntegral a
getInt16le :: Get Int16
getInt16le = do a <- getWord16le
                return $ fromIntegral a
getInt32be :: Get Int32
getInt32be = do a <- getWord32be
                return $ fromIntegral a
getInt32le :: Get Int32
getInt32le = do a <- getWord32le
                return $ fromIntegral a

putInt8 :: Int8 -> Put
putInt8 i = putWord8 ((fromIntegral i) :: Word8)
putInt16be :: Int16 -> Put
putInt16be i = putWord16be ((fromIntegral i) :: Word16)
putInt16le :: Int16 -> Put
putInt16le i = putWord16le ((fromIntegral i) :: Word16)
putInt32be :: Int32 -> Put
putInt32be i = putWord32be ((fromIntegral i) :: Word32)
putInt32le :: Int32 -> Put
putInt32le i = putWord32le ((fromIntegral i) :: Word32)

data TestType = TestType
    { a :: Int16
    , b :: Int16
    } deriving (Show, Eq)

instance Binary TestType where
    put TestType{..} =
      do putInt16be a
         putInt16le b
    get = do a <- getInt16be
             b <- getInt16le
             return TestType{..}

main :: IO ()
main = do
    putStrLn "Supplies Get and Put support to Int8, Int16 etc. types as Data.Binary.Get and Data.Binary.Push do for Word8, Word 16 etc."
    putStrLn ""
    putStrLn "Test data in bytes:"
    print bytes
    putStrLn ""
    putStrLn "As TestType:"
    print (decode bytes :: TestType)
    putStrLn ""
    putStrLn "Back to bytes:"
    print $ (encode ((decode bytes) :: TestType))
  where
    bytes = B.pack $ concat $ replicate 2 [0xCD,0xEF]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...