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
showList :: [BytedumpConfig] -> ShowS
$cshowList :: [BytedumpConfig] -> ShowS
show :: BytedumpConfig -> String
$cshow :: BytedumpConfig -> String
showsPrec :: Int -> BytedumpConfig -> ShowS
$cshowsPrec :: Int -> BytedumpConfig -> ShowS
Show,BytedumpConfig -> BytedumpConfig -> Bool
(BytedumpConfig -> BytedumpConfig -> Bool)
-> (BytedumpConfig -> BytedumpConfig -> Bool) -> Eq BytedumpConfig
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: BytedumpConfig -> BytedumpConfig -> Bool
$c/= :: BytedumpConfig -> BytedumpConfig -> Bool
== :: BytedumpConfig -> BytedumpConfig -> Bool
$c== :: BytedumpConfig -> BytedumpConfig -> Bool
Eq)
defaultConfig :: BytedumpConfig
defaultConfig :: BytedumpConfig
defaultConfig = BytedumpConfig :: Int
-> Int
-> String
-> String
-> String
-> String
-> Bool
-> BytedumpConfig
BytedumpConfig
{ configRowSize :: Int
configRowSize = 16
, configRowGroupSize :: Int
configRowGroupSize = 8
, configRowGroupSep :: String
configRowGroupSep = " : "
, configRowLeft :: String
configRowLeft = " | "
, configRowRight :: String
configRowRight = " | "
, configCellSep :: String
configCellSep = " "
, configPrintChar :: Bool
configPrintChar = Bool
True
}
hex :: Int -> Char
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 :: Word8 -> (Char, Char)
hexBytes w :: Word8
w = (Int -> Char
hex Int
h, Int -> Char
hex Int
l) where (h :: Int
h,l :: 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` 16
hexString :: Word8 -> String
hexString :: Word8 -> String
hexString i :: Word8
i = [Char
h,Char
l] where (h :: Char
h,l :: 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 _ [] = []
disptable cfg :: BytedumpConfig
cfg x :: [Word8]
x =
let (pre :: [Word8]
pre, post :: [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 row :: [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 = 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
- 1) Int -> Int -> Int
forall a. Num a => a -> a -> a
* String -> 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
- 1) Int -> Int -> Int
forall a. Num a => a -> a -> a
* String -> 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 (t :: * -> *) a. Foldable t => t a -> Int
length String
lb) ' ' 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 "")
splitMultiple :: Int -> [a] -> [[a]]
splitMultiple _ [] = []
splitMultiple n :: Int
n l :: [a]
l = let (pre :: [a]
pre, post :: [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 w :: Word8
w
| Word8
w Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= 0x20 Bool -> Bool -> Bool
&& Word8
w Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< 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 = '.'
dispDiffTable :: BytedumpConfig -> [Word8] -> [Word8] -> [String]
dispDiffTable :: BytedumpConfig -> [Word8] -> [Word8] -> [String]
dispDiffTable _ [] [] = []
dispDiffTable cfg :: BytedumpConfig
cfg x1 :: [Word8]
x1 x2 :: [Word8]
x2 =
let (pre1 :: [Word8]
pre1, post1 :: [Word8]
post1) = Int -> [Word8] -> ([Word8], [Word8])
forall a. Int -> [a] -> ([a], [a])
splitAt (BytedumpConfig -> Int
configRowSize BytedumpConfig
cfg) [Word8]
x1 in
let (pre2 :: [Word8]
pre2, post2 :: [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 row1 :: [Word8]
row1 row2 :: [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 = 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
- 1) Int -> Int -> Int
forall a. Num a => a -> a -> a
* String -> 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
- 1) Int -> Int -> Int
forall a. Num a => a -> a -> a
* String -> 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 (t :: * -> *) a. Foldable t => t a -> Int
length String
lb1) ' ' 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 (t :: * -> *) a. Foldable t => t a -> Int
length String
lb2) ' ' String -> ShowS
forall a. [a] -> [a] -> [a]
++ BytedumpConfig -> String
configRowRight BytedumpConfig
cfg
splitMultiple :: Int -> [a] -> [[a]]
splitMultiple _ [] = []
splitMultiple n :: Int
n l :: [a]
l = let (pre :: [a]
pre, post :: [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 cfg :: BytedumpConfig
cfg l :: [Word8]
l = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate "\n" [String]
rows
where rows :: [String]
rows = BytedumpConfig -> [Word8] -> [String]
disptable BytedumpConfig
cfg [Word8]
l
dumpWithS :: BytedumpConfig -> String -> String
dumpWithS :: BytedumpConfig -> ShowS
dumpWithS cfg :: 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 cfg :: 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 cfg :: 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 l :: [Word8]
l = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate "\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 l1 :: [Word8]
l1 l2 :: [Word8]
l2 = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate "\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 s1 :: String
s1 s2 :: 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 b1 :: ByteString
b1 b2 :: 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 l1 :: ByteString
l1 l2 :: ByteString
l2 = [Word8] -> [Word8] -> String
dumpDiff (ByteString -> [Word8]
L.unpack ByteString
l1) (ByteString -> [Word8]
L.unpack ByteString
l2)