Blame Data/Memory/Encoding/Base16.hs

Packit c1c4f9
-- |
Packit c1c4f9
-- Module      : Data.Memory.Encoding.Base16
Packit c1c4f9
-- License     : BSD-style
Packit c1c4f9
-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
Packit c1c4f9
-- Stability   : experimental
Packit c1c4f9
-- Portability : unknown
Packit c1c4f9
--
Packit c1c4f9
-- Hexadecimal escaper
Packit c1c4f9
--
Packit c1c4f9
{-# LANGUAGE MagicHash #-}
Packit c1c4f9
{-# LANGUAGE UnboxedTuples #-}
Packit c1c4f9
{-# LANGUAGE OverloadedStrings #-}
Packit c1c4f9
{-# LANGUAGE BangPatterns #-}
Packit c1c4f9
{-# LANGUAGE Rank2Types #-}
Packit c1c4f9
module Data.Memory.Encoding.Base16
Packit c1c4f9
    ( showHexadecimal
Packit c1c4f9
    , toHexadecimal
Packit c1c4f9
    , fromHexadecimal
Packit c1c4f9
    ) where
Packit c1c4f9
Packit c1c4f9
import           Data.Memory.Internal.Compat
Packit c1c4f9
import           Data.Word
Packit c1c4f9
import           Data.Bits ((.|.))
Packit c1c4f9
import           GHC.Prim
Packit c1c4f9
import           GHC.Types
Packit c1c4f9
import           GHC.Word
Packit c1c4f9
import           Control.Monad
Packit c1c4f9
import           Foreign.Storable
Packit c1c4f9
import           Foreign.Ptr (Ptr)
Packit c1c4f9
Packit c1c4f9
-- | Transform a raw memory to an hexadecimal 'String'
Packit c1c4f9
-- 
Packit c1c4f9
-- user beware, no checks are made
Packit c1c4f9
showHexadecimal :: (forall a . (Ptr Word8 -> IO a) -> IO a) -- ^ a 'with' type of function to hold reference to the object
Packit c1c4f9
                -> Int    -- ^ length in bytes
Packit c1c4f9
                -> String
Packit c1c4f9
showHexadecimal withPtr = doChunks 0
Packit c1c4f9
  where
Packit c1c4f9
        doChunks ofs len
Packit c1c4f9
            | len < 4   = doUnique ofs len
Packit c1c4f9
            | otherwise = do
Packit c1c4f9
                let !(W8# a, W8# b, W8# c, W8# d) = unsafeDoIO $ withPtr (read4 ofs)
Packit c1c4f9
                    !(# w1, w2 #) = convertByte a
Packit c1c4f9
                    !(# w3, w4 #) = convertByte b
Packit c1c4f9
                    !(# w5, w6 #) = convertByte c
Packit c1c4f9
                    !(# w7, w8 #) = convertByte d
Packit c1c4f9
                 in wToChar w1 : wToChar w2 : wToChar w3 : wToChar w4
Packit c1c4f9
                  : wToChar w5 : wToChar w6 : wToChar w7 : wToChar w8
Packit c1c4f9
                  : doChunks (ofs + 4) (len - 4)
Packit c1c4f9
Packit c1c4f9
        doUnique ofs len
Packit c1c4f9
            | len == 0  = []
Packit c1c4f9
            | otherwise =
Packit c1c4f9
                let !(W8# b)      = unsafeDoIO $ withPtr (byteIndex ofs)
Packit c1c4f9
                    !(# w1, w2 #) = convertByte b
Packit c1c4f9
                 in wToChar w1 : wToChar w2 : doUnique (ofs + 1) (len - 1)
Packit c1c4f9
Packit c1c4f9
        read4 :: Int -> Ptr Word8 -> IO (Word8, Word8, Word8, Word8)
Packit c1c4f9
        read4 ofs p =
Packit c1c4f9
            liftM4 (,,,) (byteIndex ofs     p) (byteIndex (ofs+1) p)
Packit c1c4f9
                         (byteIndex (ofs+2) p) (byteIndex (ofs+3) p)
Packit c1c4f9
Packit c1c4f9
        wToChar :: Word# -> Char
Packit c1c4f9
        wToChar w = toEnum (I# (word2Int# w))
Packit c1c4f9
Packit c1c4f9
        byteIndex :: Int -> Ptr Word8 -> IO Word8
Packit c1c4f9
        byteIndex i p = peekByteOff p i
Packit c1c4f9
Packit c1c4f9
-- | Transform a number of bytes pointed by.@src in the hexadecimal binary representation in @dst
Packit c1c4f9
--
Packit c1c4f9
-- destination memory need to be of correct size, otherwise it will lead
Packit c1c4f9
-- to really bad things.
Packit c1c4f9
toHexadecimal :: Ptr Word8 -- ^ destination memory
Packit c1c4f9
              -> Ptr Word8 -- ^ source memory
Packit c1c4f9
              -> Int       -- ^ number of bytes
Packit c1c4f9
              -> IO ()
Packit c1c4f9
toHexadecimal bout bin n = loop 0
Packit c1c4f9
  where loop i
Packit c1c4f9
            | i == n  = return ()
Packit c1c4f9
            | otherwise = do
Packit c1c4f9
                (W8# w) <- peekByteOff bin i
Packit c1c4f9
                let !(# w1, w2 #) = convertByte w
Packit c1c4f9
                pokeByteOff bout (i * 2)     (W8# w1)
Packit c1c4f9
                pokeByteOff bout (i * 2 + 1) (W8# w2)
Packit c1c4f9
                loop (i+1)
Packit c1c4f9
Packit c1c4f9
-- | Convert a value Word# to two Word#s containing
Packit c1c4f9
-- the hexadecimal representation of the Word#
Packit c1c4f9
convertByte :: Word# -> (# Word#, Word# #)
Packit c1c4f9
convertByte b = (# r tableHi b, r tableLo b #)
Packit c1c4f9
  where
Packit c1c4f9
        r :: Addr# -> Word# -> Word#
Packit c1c4f9
        r table index = indexWord8OffAddr# table (word2Int# index)
Packit c1c4f9
Packit c1c4f9
        !tableLo =
Packit c1c4f9
            "0123456789abcdef0123456789abcdef\
Packit c1c4f9
            \0123456789abcdef0123456789abcdef\
Packit c1c4f9
            \0123456789abcdef0123456789abcdef\
Packit c1c4f9
            \0123456789abcdef0123456789abcdef\
Packit c1c4f9
            \0123456789abcdef0123456789abcdef\
Packit c1c4f9
            \0123456789abcdef0123456789abcdef\
Packit c1c4f9
            \0123456789abcdef0123456789abcdef\
Packit c1c4f9
            \0123456789abcdef0123456789abcdef"#
Packit c1c4f9
        !tableHi =
Packit c1c4f9
            "00000000000000001111111111111111\
Packit c1c4f9
            \22222222222222223333333333333333\
Packit c1c4f9
            \44444444444444445555555555555555\
Packit c1c4f9
            \66666666666666667777777777777777\
Packit c1c4f9
            \88888888888888889999999999999999\
Packit c1c4f9
            \aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb\
Packit c1c4f9
            \ccccccccccccccccdddddddddddddddd\
Packit c1c4f9
            \eeeeeeeeeeeeeeeeffffffffffffffff"#
Packit c1c4f9
{-# INLINE convertByte #-}
Packit c1c4f9
Packit c1c4f9
-- | convert a base16 @src in @dst.
Packit c1c4f9
--
Packit c1c4f9
-- n need to even
Packit c1c4f9
fromHexadecimal :: Ptr Word8 -> Ptr Word8 -> Int -> IO (Maybe Int)
Packit c1c4f9
fromHexadecimal dst src n
Packit c1c4f9
    | odd n     = error "fromHexadecimal: invalid odd length."
Packit c1c4f9
    | otherwise = loop 0 0
Packit c1c4f9
  where loop di i
Packit c1c4f9
            | i == n    = return Nothing
Packit c1c4f9
            | otherwise = do
Packit c1c4f9
                a <- rHi `fmap` peekByteOff src i
Packit c1c4f9
                b <- rLo `fmap` peekByteOff src (i+1)
Packit c1c4f9
                if a == 0xff || b == 0xff
Packit c1c4f9
                    then return $ Just i
Packit c1c4f9
                    else pokeByteOff dst di (a .|. b) >> loop (di+1) (i+2)
Packit c1c4f9
Packit c1c4f9
        rLo (W8# index) = W8# (indexWord8OffAddr# tableLo (word2Int# index))
Packit c1c4f9
        rHi (W8# index) = W8# (indexWord8OffAddr# tableHi (word2Int# index))
Packit c1c4f9
        
Packit c1c4f9
        !tableLo =
Packit c1c4f9
                "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\x0a\x0b\x0c\x0d\x0e\x0f\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\x0a\x0b\x0c\x0d\x0e\x0f\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"#
Packit c1c4f9
        !tableHi =
Packit c1c4f9
                "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\x00\x10\x20\x30\x40\x50\x60\x70\x80\x90\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xa0\xb0\xc0\xd0\xe0\xf0\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xa0\xb0\xc0\xd0\xe0\xf0\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\
Packit c1c4f9
                 \\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"#
Packit c1c4f9