-- |
-- Module    : Codec.Binary.Util
-- Copyright : (c) 2009 Magnus Therning
-- License   : BSD3
--
-- Utility functions used in the other module.
module Codec.Binary.Util
    ( toHex
    , fromHex
    , EncIncData(..)
    , EncIncRes(..)
    , DecIncData(..)
    , DecIncRes(..)
    , encoder
    , decoder
    ) where

import Data.Array
import Data.Bits
import Data.Char
import Data.Word
import qualified Data.Map as M

-- {{{1 hex enc/dec assoc list and maps
hexEncMap :: [(Word8, Char)]
hexEncMap = forall a b. [a] -> [b] -> [(a, b)]
zip [Word8
0..] String
"0123456789ABCDEF"

hexEncodeArray :: Array Word8 Char
hexEncodeArray :: Array Word8 Char
hexEncodeArray = forall i e. Ix i => (i, i) -> [(i, e)] -> Array i e
array (Word8
0, Word8
16) [(Word8, Char)]
hexEncMap

hexDecodeMap :: M.Map Char Word8
hexDecodeMap :: Map Char Word8
hexDecodeMap = forall k a. Ord k => [(k, a)] -> Map k a
M.fromList [(Char
b, Word8
a) | (Word8
a, Char
b) <- [(Word8, Char)]
hexEncMap]

-- {{{1 toHex
toHex :: Word8 -> String
toHex :: Word8 -> String
toHex Word8
o = let
        hn :: Word8
hn = Word8
o forall a. Bits a => a -> Int -> a
`shiftR` Int
4
        ln :: Word8
ln = Word8
o forall a. Bits a => a -> a -> a
.&. Word8
0xf
    in [Array Word8 Char
hexEncodeArray forall i e. Ix i => Array i e -> i -> e
! Word8
hn, Array Word8 Char
hexEncodeArray forall i e. Ix i => Array i e -> i -> e
! Word8
ln]

-- {{{1 fromHex
fromHex :: String -> Maybe Word8
fromHex :: String -> Maybe Word8
fromHex = let
        dec :: [Maybe a] -> Maybe a
dec [Just a
hn, Just a
ln] = let
                o :: a
o = a
hn forall a. Bits a => a -> Int -> a
`shiftL` Int
4 forall a. Bits a => a -> a -> a
.|. a
ln
            in forall a. a -> Maybe a
Just a
o
        dec [Maybe a]
_ = forall a. Maybe a
Nothing
    in forall {a}. Bits a => [Maybe a] -> Maybe a
dec forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map (forall a b c. (a -> b -> c) -> b -> a -> c
flip forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Map Char Word8
hexDecodeMap forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Char
toUpper)

-- {{{1 incremental coding
-- | Data type for the incremental encoding functions.
data EncIncData = EChunk [Word8] -- ^ a chunk of data to be encoded
    | EDone -- ^ the signal to the encoder that the stream of data is ending

-- | Data type for the result of calling the incremental encoding functions.
data EncIncRes i = EPart i (EncIncData -> EncIncRes i) -- ^ a partial result together with the continuation to use for further encoding
    | EFinal i -- ^ the final result of encoding (the response to 'EDone')

encoder :: (EncIncData -> EncIncRes [a]) -> [Word8] -> [a]
encoder EncIncData -> EncIncRes [a]
f [Word8]
os = case EncIncData -> EncIncRes [a]
f ([Word8] -> EncIncData
EChunk [Word8]
os) of
    EPart [a]
r1 EncIncData -> EncIncRes [a]
f' -> case EncIncData -> EncIncRes [a]
f' EncIncData
EDone of
        EFinal [a]
r2 -> [a]
r1 forall a. [a] -> [a] -> [a]
++ [a]
r2

-- | Data type for the incremental decoding functions.
data DecIncData i = DChunk i -- ^ a chunk of data to be decoded
    | DDone -- ^ the signal to the decoder that the stream of data is ending

-- | Data type for the result of calling the incremental encoding functions.
data DecIncRes i = DPart [Word8] (DecIncData i -> DecIncRes i) -- ^ a partial result together with the continuation to user for further decoding
    | DFinal [Word8] i -- ^ the final result of decoding (the response to 'DDone')
    | DFail [Word8] i -- ^ a partial result for a failed decoding, together with the remainder of the data passed in so far

decoder :: (DecIncData i -> DecIncRes i) -> i -> Maybe [Word8]
decoder :: forall i. (DecIncData i -> DecIncRes i) -> i -> Maybe [Word8]
decoder DecIncData i -> DecIncRes i
f i
s = let
        d :: DecIncRes i
d = DecIncData i -> DecIncRes i
f (forall i. i -> DecIncData i
DChunk i
s)
    in case DecIncRes i
d of
        DFinal [Word8]
da i
_ -> forall a. a -> Maybe a
Just [Word8]
da
        DFail [Word8]
_ i
_ -> forall a. Maybe a
Nothing
        DPart [Word8]
da DecIncData i -> DecIncRes i
f -> let
                d' :: DecIncRes i
d' = DecIncData i -> DecIncRes i
f forall i. DecIncData i
DDone
            in case DecIncRes i
d' of
                DFinal [Word8]
da' i
_ -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ [Word8]
da forall a. [a] -> [a] -> [a]
++ [Word8]
da'
                DFail [Word8]
_ i
_ -> forall a. Maybe a
Nothing
                DPart [Word8]
_ DecIncData i -> DecIncRes i
_ -> forall a. Maybe a
Nothing -- should never happen