    -- |
    -- 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)