1 module Network.DNS.Unpacker
27 import qualified Data.Binary as Binary
28 import qualified Data.Binary.Get as Bin
30 import qualified Data.ByteString as Strict
31 import qualified Data.ByteString.Lazy as Lazy
38 stSource :: !Lazy.ByteString
39 , stBytesRead :: !Int64
43 newtype Unpacker s a = U { unU :: UnpackingState s -> (a, UnpackingState s) }
45 instance Monad (Unpacker s) where
46 return a = U (\ s -> (a, s))
47 m >>= k = U (\ s -> let (a, s') = unU m s
50 fail err = do bytes <- get stBytesRead
52 ++ ". Failed unpacking at byte position "
55 get :: (UnpackingState s -> a) -> Unpacker s a
56 get f = U (\ s -> (f s, s))
58 set :: (UnpackingState s -> UnpackingState s) -> Unpacker s ()
59 set f = U (\ s -> ((), f s))
61 mkState :: Lazy.ByteString -> Int64 -> s -> UnpackingState s
69 unpack' :: Unpacker s a -> s -> Lazy.ByteString -> (a, s)
71 = let (a, s') = unU m (mkState xs 0 s)
75 unpack :: Unpacker s a -> s -> Lazy.ByteString -> a
76 unpack = ((fst .) .) . unpack'
78 getState :: Unpacker s s
79 getState = get stUserState
81 setState :: s -> Unpacker s ()
82 setState = modifyState . const
84 modifyState :: (s -> s) -> Unpacker s ()
86 = set $ \ st -> st { stUserState = f (stUserState st) }
88 skip :: Int64 -> Unpacker s ()
89 skip n = getLazyByteString n >> return ()
91 lookAhead :: Unpacker s a -> Unpacker s a
92 lookAhead m = U (\ s -> let (a, _) = unU m s
96 bytesRead :: Integral i => Unpacker s i
97 bytesRead = get stBytesRead >>= return . fromIntegral
99 getByteString :: Int -> Unpacker s Strict.ByteString
100 getByteString n = getLazyByteString (fromIntegral n) >>= return . Strict.concat . Lazy.toChunks
102 getLazyByteString :: Int64 -> Unpacker s Lazy.ByteString
104 = do src <- get stSource
105 let (xs, ys) = Lazy.splitAt n src
106 if Lazy.length xs /= n then
109 do set $ \ st -> st {
111 , stBytesRead = stBytesRead st + n
115 getWord8 :: Unpacker s Word8
116 getWord8 = getLazyByteString 1 >>= return . (`Lazy.index` 0)
118 getWord16be :: Unpacker s Word16
119 getWord16be = do xs <- getLazyByteString 2
120 return $ (fromIntegral (xs `Lazy.index` 0) `shiftL` 8) .|.
121 (fromIntegral (xs `Lazy.index` 1))
123 getWord32be :: Unpacker s Word32
124 getWord32be = do xs <- getLazyByteString 4
125 return $ (fromIntegral (xs `Lazy.index` 0) `shiftL` 24) .|.
126 (fromIntegral (xs `Lazy.index` 1) `shiftL` 16) .|.
127 (fromIntegral (xs `Lazy.index` 2) `shiftL` 8) .|.
128 (fromIntegral (xs `Lazy.index` 3))
130 getBinary :: Binary.Binary a => Unpacker s a
131 getBinary = do s <- get id
132 let (a, rest, bytes) = Bin.runGetState Binary.get (stSource s) (stBytesRead s)
135 , stBytesRead = bytes
140 liftToBinary :: s -> Unpacker s a -> Bin.Get a
142 = do bytes <- Bin.bytesRead
143 src <- Bin.getRemainingLazyByteString
145 let (a, s') = unU m (mkState src bytes s)
147 -- These bytes was consumed by the unpacker.
148 Bin.skip (fromIntegral (stBytesRead s' - bytes))