module Text.Bytedump
( hexString
, BytedumpConfig(..)
, defaultConfig
, dumpRaw
, dumpRawS
, dumpRawBS
, dumpRawLBS
, dumpWith
, dumpWithS
, dumpWithBS
, dumpWithLBS
, dump
, dumpS
, dumpBS
, dumpLBS
, dumpDiff
, dumpDiffS
, dumpDiffBS
, dumpDiffLBS
) where
import Data.List
import Data.Word
import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString as B
data BytedumpConfig = BytedumpConfig
{ BytedumpConfig -> Int
configRowSize :: Int
, BytedumpConfig -> Int
configRowGroupSize :: Int
, BytedumpConfig -> String
configRowGroupSep :: String
, BytedumpConfig -> String
configRowLeft :: String
, BytedumpConfig -> String
configRowRight :: String
, BytedumpConfig -> String
configCellSep :: String
, BytedumpConfig -> Bool
configPrintChar :: Bool
} 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)
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
hexString :: Word8 -> String
hexString :: Word8 -> String
hexString Word8
i = [Char
h,Char
l] where (Char
h,Char
l) = Word8 -> (Char, Char)
hexBytes Word8
i
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
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)
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
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
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
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)
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
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 :: [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
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)
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
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
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
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)
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)
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)