-- |
-- 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 = [Word8] -> [Char] -> [(Word8, Char)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Word8
0..] [Char]
"0123456789ABCDEF"

hexEncodeArray :: Array Word8 Char
hexEncodeArray :: Array Word8 Char
hexEncodeArray = (Word8, Word8) -> [(Word8, Char)] -> Array Word8 Char
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 = [(Char, Word8)] -> Map Char Word8
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 -> [Char]
toHex Word8
o = let
        hn :: Word8
hn = Word8
o Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`shiftR` Int
4
        ln :: Word8
ln = Word8
o Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0xf
    in [Array Word8 Char
hexEncodeArray Array Word8 Char -> Word8 -> Char
forall i e. Ix i => Array i e -> i -> e
! Word8
hn, Array Word8 Char
hexEncodeArray Array Word8 Char -> Word8 -> Char
forall i e. Ix i => Array i e -> i -> e
! Word8
ln]

-- {{{1 fromHex
fromHex :: String -> Maybe Word8
fromHex :: [Char] -> Maybe Word8
fromHex = let
        dec :: [Maybe a] -> Maybe a
dec [Just a
hn, Just a
ln] = let
                o :: a
o = a
hn a -> Int -> a
forall a. Bits a => a -> Int -> a
`shiftL` Int
4 a -> a -> a
forall a. Bits a => a -> a -> a
.|. a
ln
            in a -> Maybe a
forall a. a -> Maybe a
Just a
o
        dec [Maybe a]
_ = Maybe a
forall a. Maybe a
Nothing
    in [Maybe Word8] -> Maybe Word8
forall {a}. Bits a => [Maybe a] -> Maybe a
dec ([Maybe Word8] -> Maybe Word8)
-> ([Char] -> [Maybe Word8]) -> [Char] -> Maybe Word8
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Maybe Word8) -> [Char] -> [Maybe Word8]
forall a b. (a -> b) -> [a] -> [b]
map ((Char -> Map Char Word8 -> Maybe Word8)
-> Map Char Word8 -> Char -> Maybe Word8
forall a b c. (a -> b -> c) -> b -> a -> c
flip Char -> Map Char Word8 -> Maybe Word8
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Map Char Word8
hexDecodeMap (Char -> Maybe Word8) -> (Char -> Char) -> Char -> Maybe Word8
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 [a] -> [a] -> [a]
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 (i -> DecIncData i
forall i. i -> DecIncData i
DChunk i
s)
    in case DecIncRes i
d of
        DFinal [Word8]
da i
_ -> [Word8] -> Maybe [Word8]
forall a. a -> Maybe a
Just [Word8]
da
        DFail [Word8]
_ i
_ -> Maybe [Word8]
forall a. Maybe a
Nothing
        DPart [Word8]
da DecIncData i -> DecIncRes i
f -> let
                d' :: DecIncRes i
d' = DecIncData i -> DecIncRes i
f DecIncData i
forall i. DecIncData i
DDone
            in case DecIncRes i
d' of
                DFinal [Word8]
da' i
_ -> [Word8] -> Maybe [Word8]
forall a. a -> Maybe a
Just ([Word8] -> Maybe [Word8]) -> [Word8] -> Maybe [Word8]
forall a b. (a -> b) -> a -> b
$ [Word8]
da [Word8] -> [Word8] -> [Word8]
forall a. [a] -> [a] -> [a]
++ [Word8]
da'
                DFail [Word8]
_ i
_ -> Maybe [Word8]
forall a. Maybe a
Nothing
                DPart [Word8]
_ DecIncData i -> DecIncRes i
_ -> Maybe [Word8]
forall a. Maybe a
Nothing -- should never happen