tls-debug-0.4.1: src/HexDump.hs
module HexDump
( hexdump
) where
import Data.List
import Data.Word
import qualified Data.ByteString as B
hexdump :: String -> B.ByteString -> [String]
hexdump pre b = disptable (defaultConfig { configRowLeft = pre ++ " | " } ) $ B.unpack b
data BytedumpConfig = BytedumpConfig
{ configRowSize :: Int -- ^ number of bytes per row.
, configRowGroupSize :: Int -- ^ number of bytes per group per row.
, configRowGroupSep :: String -- ^ string separating groups.
, configRowLeft :: String -- ^ string on the left of the row.
, configRowRight :: String -- ^ string on the right of the row.
, configCellSep :: String -- ^ string separating cells in row.
, configPrintChar :: Bool -- ^ if the printable ascii table is displayed.
} deriving (Show,Eq)
defaultConfig :: BytedumpConfig
defaultConfig = BytedumpConfig
{ configRowSize = 16
, configRowGroupSize = 8
, configRowGroupSep = " : "
, configRowLeft = " | "
, configRowRight = " | "
, configCellSep = " "
, configPrintChar = True
}
disptable :: BytedumpConfig -> [Word8] -> [String]
disptable _ [] = []
disptable cfg x =
let (pre, post) = splitAt (configRowSize cfg) x
in tableRow pre : disptable cfg post
where
tableRow row =
let l = splitMultiple (configRowGroupSize cfg) $ map hexString row in
let lb = intercalate (configRowGroupSep cfg) $ map (intercalate (configCellSep cfg)) l in
let rb = map printChar row in
let rowLen = 2 * configRowSize cfg
+ (configRowSize cfg - 1) * length (configCellSep cfg)
+ ((configRowSize cfg `div` configRowGroupSize cfg) - 1) * length (configRowGroupSep cfg) in
configRowLeft cfg ++ lb ++ replicate (rowLen - length lb) ' ' ++ configRowRight cfg ++ (if configPrintChar cfg then rb else "")
splitMultiple _ [] = []
splitMultiple n l = let (pre, post) = splitAt n l in pre : splitMultiple n post
printChar :: Word8 -> Char
printChar w
| w >= 0x20 && w < 0x7f = toEnum $ fromIntegral w
| otherwise = '.'
hex :: Int -> Char
hex 0 = '0'
hex 1 = '1'
hex 2 = '2'
hex 3 = '3'
hex 4 = '4'
hex 5 = '5'
hex 6 = '6'
hex 7 = '7'
hex 8 = '8'
hex 9 = '9'
hex 10 = 'a'
hex 11 = 'b'
hex 12 = 'c'
hex 13 = 'd'
hex 14 = 'e'
hex 15 = 'f'
hex _ = ' '
{-# INLINE hexBytes #-}
hexBytes :: Word8 -> (Char, Char)
hexBytes w = (hex h, hex l) where (h,l) = (fromIntegral w) `divMod` 16
-- | Dump one byte into a 2 hexadecimal characters.
hexString :: Word8 -> String
hexString i = [h,l] where (h,l) = hexBytes i