@@ -0,0 +1,307 @@
1+{-# LANGUAGE GADTs, RankNTypes, MagicHash, CPP #-}
17+import Data.Binary.Get
19+import Data.ByteString
20+import Data.ByteString.Internal
21+import Data.ByteString.Unsafe
23+import qualified Data.ByteString.Lazy as L
27+import Data.List as List ( reverse )
29+#if defined(__GLASGOW_HASKELL__) && !defined(__HADDOCK__)
30+import GHC.Base hiding ( (:*:) )
37+ RWord8 :: Int -> R Word8
38+ RWord16be :: Int -> R Word16
39+ RWord32be :: Int -> R Word32
40+ RNextTo :: R a -> R b -> R (T a b)
41+ RList :: R a -> Int -> R [a]
42+ RCheck :: R a -> (a -> Bool) -> String -> R a
44+data T a b = !a :*: !b deriving (Show)
46+instance Show (R a) where
50+size_in_bits :: forall a. R a -- ^ The record
51+ -> Int -- ^ Number of bits
52+size_in_bits r = case r of
55+ RWord16be n -> min n 16
56+ RWord32be n -> min n 16
57+ RList r n -> n * size_in_bits r
58+ --RCase r cs -> size_in_bits r + maximum (map size_in_bits cs)
59+ RCheck r _ _ -> size_in_bits r
60+ RNextTo a b -> size_in_bits a + size_in_bits b
62+data S = S !ByteString -- ^ Input
63+ !Int -- ^ Bit offset (0-7)
66+size_in_bytes :: forall a. R a
68+size_in_bytes r = (size_in_bits r + 7) `div` 8
72+ bs <- getByteString (size_in_bytes r)
73+ a :*: s <- getS (S bs 0) r
76+getS :: Monad m => S -> R a -> m (T a S)
79+ RBool -> return (readBool s0)
80+ RWord8 n -> return (readWord8 s0 n)
81+ RWord16be n -> return (readWord16be s0 n)
87+ let loop 0 s acc = return (List.reverse acc :*: s)
90+ loop (m-1) s' (a:acc)
95+ then return (a :*: s)
98+-- make_mask 3 = 00000111
99+make_mask :: Bits a => Int -> a
100+make_mask n = (1 `shiftL` fromIntegral n) - 1
101+{-# SPECIALIZE make_mask :: Int -> Word #-}
102+{-# SPECIALIZE make_mask :: Int -> Word8 #-}
103+{-# SPECIALIZE make_mask :: Int -> Word16 #-}
104+{-# SPECIALIZE make_mask :: Int -> Word32 #-}
105+{-# SPECIALIZE make_mask :: Int -> Word64 #-}
107+readBool :: S -> T Bool S
108+readBool s@(S bs n) = testBit (unsafeHead bs) (7-n) :*: incS s 1
110+incS :: S -> Int -> S
114+ s' | n' == 8 = S (unsafeTail bs) 0
115+ | otherwise = S bs n'
118+ let (d,n') = divMod (n+o) 8
119+ in S (unsafeDrop d bs) n'
121+readWord8 :: S -> Int -> T Word8 S
122+readWord8 s@(S bs o) n
123+ -- no bits at all, return 0
126+ -- all bits are in the same byte
127+ -- we just need to shift and mask them right
128+ | n <= 8 - o = let w = unsafeHead bs
130+ w' = (w `shiftr_w8` (8 - o - n)) .&. m
133+ -- the bits are in two different bytes
134+ -- make a word16 using both bytes, and then shift and mask
135+ | n <= 8 = let w = (fromIntegral (unsafeHead bs) `shiftl_w16` 8) .|.
136+ (fromIntegral (unsafeIndex bs 1))
138+ w' = (w `shiftr_w16` (16 - o - n)) .&. m
139+ in fromIntegral w' :*: incS s n
141+bit_offset :: Int -> Int
142+bit_offset n = make_mask 3 .&. n
144+byte_offset :: Int -> Int
145+byte_offset n = n `shiftR` 3
147+readWord16be :: S -> Int -> T Word16 S
148+readWord16be s@(S bs o) n
150+ -- 8 or fewer bits, use readWord8
151+ | n <= 8 = let w :*: s' = readWord8 s n
152+ in fromIntegral w :*: s'
154+ -- handle 9 or more bits, stored in two bytes
156+ -- no offset, plain and simple 16 bytes
157+ | o == 0 && n == 16 = let msb = fromIntegral (unsafeHead bs)
158+ lsb = fromIntegral (unsafeIndex bs 1)
159+ w = (msb `shiftl_w16` 8) .|. lsb
162+ -- no offset, but not full 16 bytes
163+ | o == 0 = let msb = fromIntegral (unsafeHead bs)
164+ lsb = fromIntegral (unsafeIndex bs 1)
165+ w = (msb `shiftl_w16` (n-8)) .|. (lsb `shiftr_w16` (16-n))
168+ -- with offset, and n=9-16
169+ | n <= 16 = let bits_in_msb = 8 - o
170+ (n',top) = (n - bits_in_msb
171+ , (fromIntegral (unsafeHead bs) .&. make_mask bits_in_msb) `shiftl_w16` (n - bits_in_msb))
173+ segs = byte_offset n
175+ bn 1 = fromIntegral (unsafeIndex bs 1)
176+ bn n = (bn (n-1) `shiftl_w16` 8) .|. fromIntegral (unsafeIndex bs n)
180+ last | bit_offset n' > 0 = (fromIntegral (unsafeIndex bs (segs + 1))) `shiftr_w16` (8 - (bit_offset n'))
183+ w = top .|. mseg .|. last
186+ | otherwise = error "readWord16be: tried to read more than 16 bits"
188+readWithOffset s@(S bs o) shifterL shifterR n
189+ | n <= 64 = let bits_in_msb = 8 - o
190+ (n',top) = (n - bits_in_msb
191+ , (fromIntegral (unsafeHead bs) .&. make_mask bits_in_msb) `shifterL` (n - bits_in_msb))
193+ segs = byte_offset n
195+ bn 1 = fromIntegral (unsafeIndex bs 1)
196+ bn n = (bn (n-1) `shifterL` 8) .|. fromIntegral (unsafeIndex bs n)
200+ last | bit_offset n' > 0 = (fromIntegral (unsafeIndex bs (segs + 1))) `shifterR` (8 - (bit_offset n'))
203+ w = top .|. mseg .|. last
207+readWord32be :: S -> Int -> T Word32 S
208+readWord32be s@(S bs o) n
209+ -- 8 or fewer bits, use readWord8
210+ | n <= 8 = let w :*: s' = readWord8 s n
211+ in fromIntegral w :*: s'
213+ -- 16 or fewer bits, use readWord16be
214+ | n <= 16 = let w :*: s' = readWord16be s n
215+ in fromIntegral w :*: s'
218+ | otherwise = error "readWord32be: Not fully implemented"
222+------------------------------------------------------------------------
223+-- unrolled codensity/state monad
224+newtype BitGet a = C { runCont :: forall r.
230+type Failure r = String -> Either String r
231+type Success a r = S -> a -> Either String r
233+instance Monad BitGet where
234+ return x = C $ \s kf ks -> ks s x
235+ fail str = C $ \s kf ks -> kf str
236+ (C c) >>= f = C $ \s kf ks -> c s kf (\s' a -> runCont (f a) s' kf ks)
238+runBitGet :: BitGet a -> Int -> Get (Either String a)
239+runBitGet bg size = do
240+ bs <- getByteString size
241+ return $ runCont bg (S bs 0) (\str -> Left str) (\s a -> Right a)
243+getWord8 :: Int -> BitGet Word8
244+getWord8 = modifyState . flip readWord8
246+getWord16be :: Int -> BitGet Word16
247+getWord16be = modifyState . flip readWord16be
249+getWord32be :: Int -> BitGet Word32
250+getWord32be = modifyState . flip readWord32be
253+getState = C $ \s kf ks -> ks s s
255+putState :: S -> BitGet ()
256+putState s = C $ \_ kf ks -> ks s ()
258+modifyState :: (S -> (T a S)) -> BitGet a
259+modifyState f = C $ \s kf ks -> case f s of
263+------------------------------------------------------------------------
264+-- Unchecked shifts, from the package binary
266+shiftl_w16 :: Word16 -> Int -> Word16
267+shiftl_w32 :: Word32 -> Int -> Word32
268+shiftl_w64 :: Word64 -> Int -> Word64
270+#if defined(__GLASGOW_HASKELL__) && !defined(__HADDOCK__)
271+shiftl_w8 (W8# w) (I# i) = W8# (w `uncheckedShiftL#` i)
272+shiftl_w16 (W16# w) (I# i) = W16# (w `uncheckedShiftL#` i)
273+shiftl_w32 (W32# w) (I# i) = W32# (w `uncheckedShiftL#` i)
275+shiftr_w8 (W8# w) (I# i) = W8# (w `uncheckedShiftRL#` i)
276+shiftr_w16 (W16# w) (I# i) = W16# (w `uncheckedShiftRL#` i)
277+shiftr_w32 (W32# w) (I# i) = W32# (w `uncheckedShiftRL#` i)
280+#if WORD_SIZE_IN_BITS < 64
281+shiftl_w64 (W64# w) (I# i) = W64# (w `uncheckedShiftL64#` i)
282+shiftr_w64 (W64# w) (I# i) = W64# (w `uncheckedShiftRL64#` i)
284+#if __GLASGOW_HASKELL__ <= 606
285+-- Exported by GHC.Word in GHC 6.8 and higher
286+foreign import ccall unsafe "stg_uncheckedShiftL64"
287+ uncheckedShiftL64# :: Word64# -> Int# -> Word64#
288+foreign import ccall unsafe "stg_uncheckedShiftRL64"
289+ uncheckedShiftRL64# :: Word64# -> Int# -> Word64#
293+shiftl_w64 (W64# w) (I# i) = W64# (w `uncheckedShiftL#` i)
294+shiftr_w64 (W64# w) (I# i) = W64# (w `uncheckedShiftRL#` i)