#if __GLASGOW_HASKELL__ >= 701
#endif
#if defined(__GLASGOW_HASKELL__) && !defined(__HADDOCK__)
#include "MachDeps.h"
#endif
module Data.Binary.Get (
Get
, runGet
, runGetOrFail
, ByteOffset
, Decoder(..)
, runGetIncremental
, pushChunk
, pushChunks
, pushEndOfInput
, skip
, isEmpty
, bytesRead
, getByteString
, getLazyByteString
, getLazyByteStringNul
, getRemainingLazyByteString
, getWord8
, getWord16be
, getWord32be
, getWord64be
, getWord16le
, getWord32le
, getWord64le
, getWordhost
, getWord16host
, getWord32host
, getWord64host
, runGetState
, remaining
, getBytes
) where
import Foreign
import qualified Data.ByteString as B
import qualified Data.ByteString.Unsafe as B
import qualified Data.ByteString.Lazy as L
import Control.Applicative
import Data.Binary.Get.Internal hiding ( Decoder(..), runGetIncremental )
import qualified Data.Binary.Get.Internal as I
#if defined(__GLASGOW_HASKELL__) && !defined(__HADDOCK__)
import GHC.Base
import GHC.Word
#endif
data Decoder a = Fail !B.ByteString !ByteOffset String
| Partial (Maybe B.ByteString -> Decoder a)
| Done !B.ByteString !ByteOffset a
runGetIncremental :: Get a -> Decoder a
runGetIncremental = calculateOffset . I.runGetIncremental
calculateOffset :: I.Decoder a -> Decoder a
calculateOffset r0 = go r0 0
where
go r !acc = case r of
I.Done inp a -> Done inp (acc fromIntegral (B.length inp)) a
I.Fail inp s -> Fail inp (acc fromIntegral (B.length inp)) s
I.Partial k ->
Partial $ \ms ->
case ms of
Nothing -> go (k Nothing) acc
Just i -> go (k ms) (acc + fromIntegral (B.length i))
I.BytesRead unused k ->
go (k $! (acc unused)) acc
runGetState :: Get a -> L.ByteString -> ByteOffset -> (a, L.ByteString, ByteOffset)
runGetState g lbs0 pos' = go (runGetIncremental g) (L.toChunks lbs0)
where
go (Done s pos a) lbs = (a, L.fromChunks (s:lbs), pos+pos')
go (Partial k) (x:xs) = go (k $ Just x) xs
go (Partial k) [] = go (k Nothing) []
go (Fail _ pos msg) _ =
error ("Data.Binary.Get.runGetState at position " ++ show pos ++ ": " ++ msg)
runGetOrFail :: Get a -> L.ByteString
-> Either (L.ByteString, ByteOffset, String) (L.ByteString, ByteOffset, a)
runGetOrFail g bs = feedAll (runGetIncremental g) chunks
where
chunks = L.toChunks bs
feedAll (Done x pos r) xs = Right ((L.fromChunks (x:xs)), pos, r)
feedAll (Partial k) (x:xs) = feedAll (k (Just x)) xs
feedAll (Partial k) [] = feedAll (k Nothing) []
feedAll (Fail x pos msg) xs = Left ((L.fromChunks (x:xs)), pos, msg)
type ByteOffset = Int64
runGet :: Get a -> L.ByteString -> a
runGet g bs = feedAll (runGetIncremental g) chunks
where
chunks = L.toChunks bs
feedAll (Done _ _ r) _ = r
feedAll (Partial k) (x:xs) = feedAll (k (Just x)) xs
feedAll (Partial k) [] = feedAll (k Nothing) []
feedAll (Fail _ pos msg) _ =
error ("Data.Binary.Get.runGet at position " ++ show pos ++ ": " ++ msg)
pushChunk :: Decoder a -> B.ByteString -> Decoder a
pushChunk r inp =
case r of
Done inp0 p a -> Done (inp0 `B.append` inp) p a
Partial k -> k (Just inp)
Fail inp0 p s -> Fail (inp0 `B.append` inp) p s
pushChunks :: Decoder a -> L.ByteString -> Decoder a
pushChunks r0 = go r0 . L.toChunks
where
go r [] = r
go r (x:xs) = go (pushChunk r x) xs
pushEndOfInput :: Decoder a -> Decoder a
pushEndOfInput r =
case r of
Done _ _ _ -> r
Partial k -> k Nothing
Fail _ _ _ -> r
getLazyByteString :: Int64 -> Get L.ByteString
getLazyByteString n0 = L.fromChunks <$> go n0
where
consume n str
| fromIntegral (B.length str) >= n = Right (B.splitAt (fromIntegral n) str)
| otherwise = Left (fromIntegral (B.length str))
go n = do
str <- get
case consume n str of
Left used -> do
put B.empty
demandInput
fmap (str:) (go (n used))
Right (want,rest) -> do
put rest
return [want]
getLazyByteStringNul :: Get L.ByteString
getLazyByteStringNul = L.fromChunks <$> go
where
findNull str =
case B.break (==0) str of
(want,rest) | B.null rest -> Nothing
| otherwise -> Just (want, B.drop 1 rest)
go = do
str <- get
case findNull str of
Nothing -> do
put B.empty
demandInput
fmap (str:) go
Just (want,rest) -> do
put rest
return [want]
getRemainingLazyByteString :: Get L.ByteString
getRemainingLazyByteString = L.fromChunks <$> go
where
go = do
str <- get
put B.empty
done <- isEmpty
if done
then return [str]
else fmap (str:) go
getPtr :: Storable a => Int -> Get a
getPtr n = readNWith n peek
getWord8 :: Get Word8
getWord8 = readN 1 B.unsafeHead
getWord16be :: Get Word16
getWord16be = readN 2 word16be
word16be :: B.ByteString -> Word16
word16be = \s ->
(fromIntegral (s `B.unsafeIndex` 0) `shiftl_w16` 8) .|.
(fromIntegral (s `B.unsafeIndex` 1))
getWord16le :: Get Word16
getWord16le = readN 2 word16le
word16le :: B.ByteString -> Word16
word16le = \s ->
(fromIntegral (s `B.unsafeIndex` 1) `shiftl_w16` 8) .|.
(fromIntegral (s `B.unsafeIndex` 0) )
getWord32be :: Get Word32
getWord32be = readN 4 word32be
word32be :: B.ByteString -> Word32
word32be = \s ->
(fromIntegral (s `B.unsafeIndex` 0) `shiftl_w32` 24) .|.
(fromIntegral (s `B.unsafeIndex` 1) `shiftl_w32` 16) .|.
(fromIntegral (s `B.unsafeIndex` 2) `shiftl_w32` 8) .|.
(fromIntegral (s `B.unsafeIndex` 3) )
getWord32le :: Get Word32
getWord32le = readN 4 word32le
word32le :: B.ByteString -> Word32
word32le = \s ->
(fromIntegral (s `B.unsafeIndex` 3) `shiftl_w32` 24) .|.
(fromIntegral (s `B.unsafeIndex` 2) `shiftl_w32` 16) .|.
(fromIntegral (s `B.unsafeIndex` 1) `shiftl_w32` 8) .|.
(fromIntegral (s `B.unsafeIndex` 0) )
getWord64be :: Get Word64
getWord64be = readN 8 word64be
word64be :: B.ByteString -> Word64
word64be = \s ->
(fromIntegral (s `B.unsafeIndex` 0) `shiftl_w64` 56) .|.
(fromIntegral (s `B.unsafeIndex` 1) `shiftl_w64` 48) .|.
(fromIntegral (s `B.unsafeIndex` 2) `shiftl_w64` 40) .|.
(fromIntegral (s `B.unsafeIndex` 3) `shiftl_w64` 32) .|.
(fromIntegral (s `B.unsafeIndex` 4) `shiftl_w64` 24) .|.
(fromIntegral (s `B.unsafeIndex` 5) `shiftl_w64` 16) .|.
(fromIntegral (s `B.unsafeIndex` 6) `shiftl_w64` 8) .|.
(fromIntegral (s `B.unsafeIndex` 7) )
getWord64le :: Get Word64
getWord64le = readN 8 word64le
word64le :: B.ByteString -> Word64
word64le = \s ->
(fromIntegral (s `B.unsafeIndex` 7) `shiftl_w64` 56) .|.
(fromIntegral (s `B.unsafeIndex` 6) `shiftl_w64` 48) .|.
(fromIntegral (s `B.unsafeIndex` 5) `shiftl_w64` 40) .|.
(fromIntegral (s `B.unsafeIndex` 4) `shiftl_w64` 32) .|.
(fromIntegral (s `B.unsafeIndex` 3) `shiftl_w64` 24) .|.
(fromIntegral (s `B.unsafeIndex` 2) `shiftl_w64` 16) .|.
(fromIntegral (s `B.unsafeIndex` 1) `shiftl_w64` 8) .|.
(fromIntegral (s `B.unsafeIndex` 0) )
getWordhost :: Get Word
getWordhost = getPtr (sizeOf (undefined :: Word))
getWord16host :: Get Word16
getWord16host = getPtr (sizeOf (undefined :: Word16))
getWord32host :: Get Word32
getWord32host = getPtr (sizeOf (undefined :: Word32))
getWord64host :: Get Word64
getWord64host = getPtr (sizeOf (undefined :: Word64))
shiftl_w16 :: Word16 -> Int -> Word16
shiftl_w32 :: Word32 -> Int -> Word32
shiftl_w64 :: Word64 -> Int -> Word64
#if defined(__GLASGOW_HASKELL__) && !defined(__HADDOCK__)
shiftl_w16 (W16# w) (I# i) = W16# (w `uncheckedShiftL#` i)
shiftl_w32 (W32# w) (I# i) = W32# (w `uncheckedShiftL#` i)
#if WORD_SIZE_IN_BITS < 64
shiftl_w64 (W64# w) (I# i) = W64# (w `uncheckedShiftL64#` i)
#if __GLASGOW_HASKELL__ <= 606
foreign import ccall unsafe "stg_uncheckedShiftL64"
uncheckedShiftL64# :: Word64# -> Int# -> Word64#
#endif
#else
shiftl_w64 (W64# w) (I# i) = W64# (w `uncheckedShiftL#` i)
#endif
#else
shiftl_w16 = shiftL
shiftl_w32 = shiftL
shiftl_w64 = shiftL
#endif