-- |
-- Module      : Text.Bytedump
-- License     : BSD-style
-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
-- Stability   : experimental
-- Portability : unknown
--
-- A module containing some routines to debug data dump
--

module Text.Bytedump
    ( hexString

    -- * Formatted string configuration
    , BytedumpConfig(..)
    , defaultConfig

    -- * Dump bytes into not formatted strings
    , dumpRaw
    , dumpRawS
    , dumpRawBS
    , dumpRawLBS

    -- * Dump bytes into formatted strings using a specific config
    , dumpWith
    , dumpWithS
    , dumpWithBS
    , dumpWithLBS

    -- * Dump bytes into formatted strings using default config
    , dump
    , dumpS
    , dumpBS
    , dumpLBS

    -- * Dump 2 set of bytes into formatted side-by-side strings using default config
    , dumpDiff
    , dumpDiffS
    , dumpDiffBS
    , dumpDiffLBS
    ) where

import Data.List
import Data.Word
import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString as B

-- | Configuration structure used for formatting functions
data BytedumpConfig = BytedumpConfig
    { BytedumpConfig -> Int
configRowSize      :: Int    -- ^ number of bytes per row.
    , BytedumpConfig -> Int
configRowGroupSize :: Int    -- ^ number of bytes per group per row.
    , BytedumpConfig -> String
configRowGroupSep  :: String -- ^ string separating groups.
    , BytedumpConfig -> String
configRowLeft      :: String -- ^ string on the left of the row.
    , BytedumpConfig -> String
configRowRight     :: String -- ^ string on the right of the row.
    , BytedumpConfig -> String
configCellSep      :: String -- ^ string separating cells in row.
    , BytedumpConfig -> Bool
configPrintChar    :: Bool   -- ^ if the printable ascii table is displayed.
    } deriving (Int -> BytedumpConfig -> ShowS
[BytedumpConfig] -> ShowS
BytedumpConfig -> String
(Int -> BytedumpConfig -> ShowS)
-> (BytedumpConfig -> String)
-> ([BytedumpConfig] -> ShowS)
-> Show BytedumpConfig
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> BytedumpConfig -> ShowS
showsPrec :: Int -> BytedumpConfig -> ShowS
$cshow :: BytedumpConfig -> String
show :: BytedumpConfig -> String
$cshowList :: [BytedumpConfig] -> ShowS
showList :: [BytedumpConfig] -> ShowS
Show,BytedumpConfig -> BytedumpConfig -> Bool
(BytedumpConfig -> BytedumpConfig -> Bool)
-> (BytedumpConfig -> BytedumpConfig -> Bool) -> Eq BytedumpConfig
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: BytedumpConfig -> BytedumpConfig -> Bool
== :: BytedumpConfig -> BytedumpConfig -> Bool
$c/= :: BytedumpConfig -> BytedumpConfig -> Bool
/= :: BytedumpConfig -> BytedumpConfig -> Bool
Eq)

-- | Default Config using 16 bytes by row with a separation at the 8th byte, and
-- dumping printable ascii character on the right.
defaultConfig :: BytedumpConfig
defaultConfig :: BytedumpConfig
defaultConfig = BytedumpConfig
    { configRowSize :: Int
configRowSize      = Int
16
    , configRowGroupSize :: Int
configRowGroupSize = Int
8
    , configRowGroupSep :: String
configRowGroupSep  = String
" : "
    , configRowLeft :: String
configRowLeft      = String
" | "
    , configRowRight :: String
configRowRight     = String
" | "
    , configCellSep :: String
configCellSep      = String
" "
    , configPrintChar :: Bool
configPrintChar    = Bool
True
    }

hex :: Int -> Char
hex :: Int -> Char
hex Int
0  = Char
'0'
hex Int
1  = Char
'1'
hex Int
2  = Char
'2'
hex Int
3  = Char
'3'
hex Int
4  = Char
'4'
hex Int
5  = Char
'5'
hex Int
6  = Char
'6'
hex Int
7  = Char
'7'
hex Int
8  = Char
'8'
hex Int
9  = Char
'9'
hex Int
10 = Char
'a'
hex Int
11 = Char
'b'
hex Int
12 = Char
'c'
hex Int
13 = Char
'd'
hex Int
14 = Char
'e'
hex Int
15 = Char
'f'
hex Int
_  = Char
' '

{-# INLINE hexBytes #-}
hexBytes :: Word8 -> (Char, Char)
hexBytes :: Word8 -> (Char, Char)
hexBytes Word8
w = (Int -> Char
hex Int
h, Int -> Char
hex Int
l) where (Int
h,Int
l) = (Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
w) Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`divMod` Int
16

-- | Dump one byte into a 2 hexadecimal characters.
hexString :: Word8 -> String
hexString :: Word8 -> String
hexString Word8
i = [Char
h,Char
l] where (Char
h,Char
l) = Word8 -> (Char, Char)
hexBytes Word8
i

-- | Dump a list of word8 into a raw string of hex value
dumpRaw :: [Word8] -> String
dumpRaw :: [Word8] -> String
dumpRaw = (Word8 -> String) -> [Word8] -> String
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Word8 -> String
hexString

-- | Dump a string into a raw string of hex value
dumpRawS :: String -> String
dumpRawS :: ShowS
dumpRawS = [Word8] -> String
dumpRaw ([Word8] -> String) -> (String -> [Word8]) -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Word8) -> String -> [Word8]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Word8
forall a. Enum a => Int -> a
toEnum(Int -> Word8) -> (Char -> Int) -> Char -> Word8
forall b c a. (b -> c) -> (a -> b) -> a -> c
.Char -> Int
forall a. Enum a => a -> Int
fromEnum)

-- | Dump a bytestring into a raw string of hex value
dumpRawBS :: B.ByteString -> String
dumpRawBS :: ByteString -> String
dumpRawBS = [Word8] -> String
dumpRaw ([Word8] -> String)
-> (ByteString -> [Word8]) -> ByteString -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Word8]
B.unpack

-- | Dump a lazy bytestring into a raw string of hex value
dumpRawLBS :: L.ByteString -> String
dumpRawLBS :: ByteString -> String
dumpRawLBS = [Word8] -> String
dumpRaw ([Word8] -> String)
-> (ByteString -> [Word8]) -> ByteString -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Word8]
L.unpack

disptable :: BytedumpConfig -> [Word8] -> [String]
disptable :: BytedumpConfig -> [Word8] -> [String]
disptable BytedumpConfig
_   [] = []
disptable BytedumpConfig
cfg [Word8]
x  =
    let ([Word8]
pre, [Word8]
post) = Int -> [Word8] -> ([Word8], [Word8])
forall a. Int -> [a] -> ([a], [a])
splitAt (BytedumpConfig -> Int
configRowSize BytedumpConfig
cfg) [Word8]
x in
    [Word8] -> String
tableRow [Word8]
pre String -> [String] -> [String]
forall a. a -> [a] -> [a]
: BytedumpConfig -> [Word8] -> [String]
disptable BytedumpConfig
cfg [Word8]
post
    where
        tableRow :: [Word8] -> String
tableRow [Word8]
row =
            let l :: [[String]]
l  = Int -> [String] -> [[String]]
forall {a}. Int -> [a] -> [[a]]
splitMultiple (BytedumpConfig -> Int
configRowGroupSize BytedumpConfig
cfg) ([String] -> [[String]]) -> [String] -> [[String]]
forall a b. (a -> b) -> a -> b
$ (Word8 -> String) -> [Word8] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Word8 -> String
hexString [Word8]
row in
            let lb :: String
lb = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate (BytedumpConfig -> String
configRowGroupSep BytedumpConfig
cfg) ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ ([String] -> String) -> [[String]] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate (BytedumpConfig -> String
configCellSep BytedumpConfig
cfg)) [[String]]
l in
            let rb :: String
rb = (Word8 -> Char) -> [Word8] -> String
forall a b. (a -> b) -> [a] -> [b]
map Word8 -> Char
printChar [Word8]
row in
            let rowLen :: Int
rowLen = Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* BytedumpConfig -> Int
configRowSize BytedumpConfig
cfg
                       Int -> Int -> Int
forall a. Num a => a -> a -> a
+ (BytedumpConfig -> Int
configRowSize BytedumpConfig
cfg Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Int -> Int -> Int
forall a. Num a => a -> a -> a
* String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (BytedumpConfig -> String
configCellSep BytedumpConfig
cfg)
                       Int -> Int -> Int
forall a. Num a => a -> a -> a
+ ((BytedumpConfig -> Int
configRowSize BytedumpConfig
cfg Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` BytedumpConfig -> Int
configRowGroupSize BytedumpConfig
cfg) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Int -> Int -> Int
forall a. Num a => a -> a -> a
* String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (BytedumpConfig -> String
configRowGroupSep BytedumpConfig
cfg) in
            BytedumpConfig -> String
configRowLeft BytedumpConfig
cfg String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
lb String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> Char -> String
forall a. Int -> a -> [a]
replicate (Int
rowLen Int -> Int -> Int
forall a. Num a => a -> a -> a
- String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
lb) Char
' ' String -> ShowS
forall a. [a] -> [a] -> [a]
++ BytedumpConfig -> String
configRowRight BytedumpConfig
cfg String -> ShowS
forall a. [a] -> [a] -> [a]
++ (if BytedumpConfig -> Bool
configPrintChar BytedumpConfig
cfg then String
rb else String
"")

        splitMultiple :: Int -> [a] -> [[a]]
splitMultiple Int
_ [] = []
        splitMultiple Int
n [a]
l  = let ([a]
pre, [a]
post) = Int -> [a] -> ([a], [a])
forall a. Int -> [a] -> ([a], [a])
splitAt Int
n [a]
l in [a]
pre [a] -> [[a]] -> [[a]]
forall a. a -> [a] -> [a]
: Int -> [a] -> [[a]]
splitMultiple Int
n [a]
post

        printChar :: Word8 -> Char
        printChar :: Word8 -> Char
printChar Word8
w
            | Word8
w Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
0x20 Bool -> Bool -> Bool
&& Word8
w Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< Word8
0x7f = Int -> Char
forall a. Enum a => Int -> a
toEnum (Int -> Char) -> Int -> Char
forall a b. (a -> b) -> a -> b
$ Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
w
            | Bool
otherwise             = Char
'.'

dispDiffTable :: BytedumpConfig -> [Word8] -> [Word8] -> [String]
dispDiffTable :: BytedumpConfig -> [Word8] -> [Word8] -> [String]
dispDiffTable BytedumpConfig
_   [] [] = []
dispDiffTable BytedumpConfig
cfg [Word8]
x1 [Word8]
x2 =
    let ([Word8]
pre1, [Word8]
post1) = Int -> [Word8] -> ([Word8], [Word8])
forall a. Int -> [a] -> ([a], [a])
splitAt (BytedumpConfig -> Int
configRowSize BytedumpConfig
cfg) [Word8]
x1 in
    let ([Word8]
pre2, [Word8]
post2) = Int -> [Word8] -> ([Word8], [Word8])
forall a. Int -> [a] -> ([a], [a])
splitAt (BytedumpConfig -> Int
configRowSize BytedumpConfig
cfg) [Word8]
x2 in
    [Word8] -> [Word8] -> String
tableRow [Word8]
pre1 [Word8]
pre2 String -> [String] -> [String]
forall a. a -> [a] -> [a]
: BytedumpConfig -> [Word8] -> [Word8] -> [String]
dispDiffTable BytedumpConfig
cfg [Word8]
post1 [Word8]
post2

    where
        tableRow :: [Word8] -> [Word8] -> String
tableRow [Word8]
row1 [Word8]
row2 =
            let l1 :: [[String]]
l1 = Int -> [String] -> [[String]]
forall {a}. Int -> [a] -> [[a]]
splitMultiple (BytedumpConfig -> Int
configRowGroupSize BytedumpConfig
cfg) ([String] -> [[String]]) -> [String] -> [[String]]
forall a b. (a -> b) -> a -> b
$ (Word8 -> String) -> [Word8] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Word8 -> String
hexString [Word8]
row1 in
            let l2 :: [[String]]
l2 = Int -> [String] -> [[String]]
forall {a}. Int -> [a] -> [[a]]
splitMultiple (BytedumpConfig -> Int
configRowGroupSize BytedumpConfig
cfg) ([String] -> [[String]]) -> [String] -> [[String]]
forall a b. (a -> b) -> a -> b
$ (Word8 -> String) -> [Word8] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Word8 -> String
hexString [Word8]
row2 in
            let lb1 :: String
lb1 = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate (BytedumpConfig -> String
configRowGroupSep BytedumpConfig
cfg) ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ ([String] -> String) -> [[String]] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate (BytedumpConfig -> String
configCellSep BytedumpConfig
cfg)) [[String]]
l1 in
            let lb2 :: String
lb2 = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate (BytedumpConfig -> String
configRowGroupSep BytedumpConfig
cfg) ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ ([String] -> String) -> [[String]] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate (BytedumpConfig -> String
configCellSep BytedumpConfig
cfg)) [[String]]
l2 in
            let rowLen :: Int
rowLen = Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* BytedumpConfig -> Int
configRowSize BytedumpConfig
cfg
                       Int -> Int -> Int
forall a. Num a => a -> a -> a
+ (BytedumpConfig -> Int
configRowSize BytedumpConfig
cfg Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Int -> Int -> Int
forall a. Num a => a -> a -> a
* String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (BytedumpConfig -> String
configCellSep BytedumpConfig
cfg)
                       Int -> Int -> Int
forall a. Num a => a -> a -> a
+ ((BytedumpConfig -> Int
configRowSize BytedumpConfig
cfg Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` BytedumpConfig -> Int
configRowGroupSize BytedumpConfig
cfg) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Int -> Int -> Int
forall a. Num a => a -> a -> a
* String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (BytedumpConfig -> String
configRowGroupSep BytedumpConfig
cfg) in
            BytedumpConfig -> String
configRowLeft BytedumpConfig
cfg String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
lb1 String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> Char -> String
forall a. Int -> a -> [a]
replicate (Int
rowLen Int -> Int -> Int
forall a. Num a => a -> a -> a
- String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
lb1) Char
' ' String -> ShowS
forall a. [a] -> [a] -> [a]
++ BytedumpConfig -> String
configRowRight BytedumpConfig
cfg
                              String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
lb2 String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> Char -> String
forall a. Int -> a -> [a]
replicate (Int
rowLen Int -> Int -> Int
forall a. Num a => a -> a -> a
- String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
lb2) Char
' ' String -> ShowS
forall a. [a] -> [a] -> [a]
++ BytedumpConfig -> String
configRowRight BytedumpConfig
cfg

        splitMultiple :: Int -> [a] -> [[a]]
splitMultiple Int
_ [] = []
        splitMultiple Int
n [a]
l  = let ([a]
pre, [a]
post) = Int -> [a] -> ([a], [a])
forall a. Int -> [a] -> ([a], [a])
splitAt Int
n [a]
l in [a]
pre [a] -> [[a]] -> [[a]]
forall a. a -> [a] -> [a]
: Int -> [a] -> [[a]]
splitMultiple Int
n [a]
post

-- | Dump a list of bytes into formatted strings using a specific config
dumpWith :: BytedumpConfig -> [Word8] -> String
dumpWith :: BytedumpConfig -> [Word8] -> String
dumpWith BytedumpConfig
cfg [Word8]
l = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"\n" [String]
rows
    where rows :: [String]
rows = BytedumpConfig -> [Word8] -> [String]
disptable BytedumpConfig
cfg [Word8]
l

-- | Dump a string into formatted strings using a specific config
dumpWithS :: BytedumpConfig -> String -> String
dumpWithS :: BytedumpConfig -> ShowS
dumpWithS BytedumpConfig
cfg = BytedumpConfig -> [Word8] -> String
dumpWith BytedumpConfig
cfg ([Word8] -> String) -> (String -> [Word8]) -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Word8) -> String -> [Word8]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Word8
forall a. Enum a => Int -> a
toEnum(Int -> Word8) -> (Char -> Int) -> Char -> Word8
forall b c a. (b -> c) -> (a -> b) -> a -> c
.Char -> Int
forall a. Enum a => a -> Int
fromEnum)

-- | Dump a bytestring into formatted strings using a specific config
dumpWithBS :: BytedumpConfig -> B.ByteString -> String
dumpWithBS :: BytedumpConfig -> ByteString -> String
dumpWithBS BytedumpConfig
cfg = BytedumpConfig -> [Word8] -> String
dumpWith BytedumpConfig
cfg ([Word8] -> String)
-> (ByteString -> [Word8]) -> ByteString -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Word8]
B.unpack

-- | Dump a lazy bytestring into formatted strings using a specific config
dumpWithLBS :: BytedumpConfig -> L.ByteString -> String
dumpWithLBS :: BytedumpConfig -> ByteString -> String
dumpWithLBS BytedumpConfig
cfg = BytedumpConfig -> [Word8] -> String
dumpWith BytedumpConfig
cfg ([Word8] -> String)
-> (ByteString -> [Word8]) -> ByteString -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Word8]
L.unpack

-- | Dump a list of word8 into a formatted string of hex value
dump :: [Word8] -> String
dump :: [Word8] -> String
dump [Word8]
l = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"\n" [String]
rows
    where rows :: [String]
rows = BytedumpConfig -> [Word8] -> [String]
disptable BytedumpConfig
defaultConfig [Word8]
l

-- | Dump a string into a formatted string of hex value
dumpS :: String -> String
dumpS :: ShowS
dumpS = [Word8] -> String
dump ([Word8] -> String) -> (String -> [Word8]) -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Word8) -> String -> [Word8]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Word8
forall a. Enum a => Int -> a
toEnum(Int -> Word8) -> (Char -> Int) -> Char -> Word8
forall b c a. (b -> c) -> (a -> b) -> a -> c
.Char -> Int
forall a. Enum a => a -> Int
fromEnum)

-- | Dump a bytestring into a formatted string of hex value
dumpBS :: B.ByteString -> String
dumpBS :: ByteString -> String
dumpBS = [Word8] -> String
dump ([Word8] -> String)
-> (ByteString -> [Word8]) -> ByteString -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Word8]
B.unpack

-- | Dump a lazy bytestring into a formatted string of hex value
dumpLBS :: L.ByteString -> String
dumpLBS :: ByteString -> String
dumpLBS = [Word8] -> String
dump ([Word8] -> String)
-> (ByteString -> [Word8]) -> ByteString -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Word8]
L.unpack

-- | Dump two list of word8 into a formatted string of hex value side by side
dumpDiff :: [Word8] -> [Word8] -> String
dumpDiff :: [Word8] -> [Word8] -> String
dumpDiff [Word8]
l1 [Word8]
l2 = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"\n" [String]
rows
    where rows :: [String]
rows = BytedumpConfig -> [Word8] -> [Word8] -> [String]
dispDiffTable BytedumpConfig
defaultConfig [Word8]
l1 [Word8]
l2

-- | Dump a string into a formatted string of hex value
dumpDiffS :: String -> String -> String
dumpDiffS :: String -> ShowS
dumpDiffS String
s1 String
s2 = [Word8] -> [Word8] -> String
dumpDiff ((Char -> Word8) -> String -> [Word8]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Word8
forall a. Enum a => Int -> a
toEnum(Int -> Word8) -> (Char -> Int) -> Char -> Word8
forall b c a. (b -> c) -> (a -> b) -> a -> c
.Char -> Int
forall a. Enum a => a -> Int
fromEnum) String
s1) ((Char -> Word8) -> String -> [Word8]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Word8
forall a. Enum a => Int -> a
toEnum(Int -> Word8) -> (Char -> Int) -> Char -> Word8
forall b c a. (b -> c) -> (a -> b) -> a -> c
.Char -> Int
forall a. Enum a => a -> Int
fromEnum) String
s2)

-- | Dump a bytestring into a formatted string of hex value
dumpDiffBS :: B.ByteString -> B.ByteString -> String
dumpDiffBS :: ByteString -> ByteString -> String
dumpDiffBS ByteString
b1 ByteString
b2 = [Word8] -> [Word8] -> String
dumpDiff (ByteString -> [Word8]
B.unpack ByteString
b1) (ByteString -> [Word8]
B.unpack ByteString
b2)

-- | Dump a lazy bytestring into a formatted string of hex value
dumpDiffLBS :: L.ByteString -> L.ByteString -> String
dumpDiffLBS :: ByteString -> ByteString -> String
dumpDiffLBS ByteString
l1 ByteString
l2 = [Word8] -> [Word8] -> String
dumpDiff (ByteString -> [Word8]
L.unpack ByteString
l1) (ByteString -> [Word8]
L.unpack ByteString
l2)